Toytree is a Python tree plotting library that uses the modern and minimalist graphics library Toyplot to generate high quality figures that can be displayed directly within jupyter-notebooks or exported in a variety of formats. Find the full documentation at http://toytree.readthedocs.io.
Toyplot can be easily installed using the conda software package manager with the command below.
In [1]:
## conda install toytree -c eaton-lab
In [2]:
import toytree
import toyplot
import numpy
In [3]:
toytree.__version__
Out[3]:
In [3]:
## an example newick string with edge lengths and support values
newick = """
((apple:2,orange:4)100:2,(((tomato:2,eggplant:1)
100:2,pepper:3)90:1,tomatillo:2)100:1);
"""
## create a toytree object from the newick string
tre = toytree.tree(newick)
In [4]:
## A toytree object in memory
tre
Out[4]:
To draw a tree from a Toytree object simply call its .draw()
function which will generate a Canvas and a set of axes on which the plot is embedded. The Canvas is represented in HTML which allows it to be displayed seemlessly in a jupyter-notebook, and to look crisp on the web, as in this notebook presentation.
In [5]:
tre.draw(width=200);
A fun advantage to generating figures in HTML is that you can easily add interactive features to your plots. In the example below I use the magic argument node_labels=True
to diplay markers on nodes with an interactive hover feature. Hover your cursor over a node to see all of the features associated with it. Node features are parsed from the newick string, or can be added later.
In [6]:
tre.draw(width=200, node_labels=True);
Besides the magic command node_values=True
you can also set specific node features to be displayed on the tree. Or you can access node values to create custom lists to use as arguments to modify nodes colors or sizes. This is all controlled through arguments to the draw()
function.
In [7]:
## get list of support values in node-order
supports = tre.get_node_values("support", show_root=False, show_tips=False)
## get list of node colors in node-order
colors = [tre.colors[0] if i==100 else tre.colors[1] for i in supports]
## draw with node supports and some styling
tre.draw(
width=300,
node_labels=supports,
node_color=colors,
node_size=20,
node_style={"stroke": "none"}
);
Toyplot uses a stripped-down version of the TreeNode object from the ete3 library to represent Tree objects in memory as a hierarchical structure that is easy to traverse and manipulate. This makes it easy to store and access meta-data on a tree in a programmatic way. See the ete documentation for many helpful tips on editing trees. In this example we add a new feature to each node and write the new tree string in extended newick format.
In [11]:
## a simple tree
tre = toytree.tree("(((a,b),c),d);")
## add a new feature to every node
for node in tre.tree.traverse():
node.add_feature("new_feature", 100)
## write the tree string in NHX format with features
nhx = tre.tree.write(features=["new_feature", "dist", "support"], format=0)
## print the newick string
nhx
Out[11]:
In [12]:
## load a newick string from a file path
newick = "/home/deren/Dropbox/Viburnum_t65_min4"
tre = toytree.tree(newick)
## draw it
tre.draw(
width=500,
height=900,
node_labels=tre.get_node_values("support"),
);
It can be informative to visualize a distribution of trees, such as a posterior distribution of species trees, and a cloud tree diagram which is easy to do with toyplot since opacity is an easy variable to modify. Here we create a MultiTree object which holds a list of Toytrees in memory, and call the draw_cloudtree()
function.
In [19]:
## a file with trees sampled from a posterior dist.
mcmcfile = "/home/deren/Documents/ipyrad/tests/analysis-bpp/copy-d10-r0.mcmc.txt"
## use 'slice' operations to subsample every 10th tree from first 5000
mtrees = toytree.multitree(mcmcfile, treeslice=(0, 5000, 10))
## plot a cloud tree
mtrees.draw_cloudtree(
width=350,
height=300,
use_edge_lengths=True,
orient='right',
edge_style={
"opacity": 0.025,
"stroke": mtrees.colors[0]},
tip_labels_style={
"-toyplot-anchor-shift": "10px"},
);
In [44]:
## create a canvas and axes
canvas = toyplot.Canvas(width=400, height=550)
axes = canvas.cartesian()
## create some data
data = numpy.random.randint(5, 15, len(tre))
## add tree to the axes with the axes argument
_, axes = tre.draw(
axes=axes,
tip_labels=False,
);
## add barplot to the same axes
axes.bars(data[::-1],
along='y',
baseline=[1]*len(tre),
title=["name={}; val={}".format(i, j) for i, j in \
zip(tre.get_tip_labels(), data[::-1])]
)
## hide axes
axes.show=False