ToyTree with matrix/heatmap
Plot tree with matrix/heatmapĀ¶
import toytree
import numpy as np
import toyplot
# load tree with variable name lengths
tree = toytree.tree("https://eaton-lab.org/data/Cyathophora.tre")
tree = tree.root(13) #13th node corresponds to przwilenskii outgroup
Method 1:Ā¶
The simplest method is to plot the tree and markers on shared coordinate axes. To make it easy to space items on the x-axis I set the tree to be 2X the width of the data (matrix), which allows me to use units of x=1 to space items on the x-axis. Then I generate a canvas and axes by drawing a tree, as usual, and here I add the data as square scatterplot markers with different opacities to represent the (randomly generated) data.
The only tricky thing here is that you need to use tip_labels_style
to offset the x-location of the tre tip labels, and also to extend the x-axis max domain if the names are long to prevent them from getting cut off.
# generate some random data for this columns
spdata = np.random.randint(low=1, high=10, size=(tree.ntips, 5))
spdata
array([[2, 5, 7, 7, 7], [6, 2, 2, 4, 2], [5, 3, 9, 3, 5], [8, 6, 5, 9, 6], [5, 6, 7, 2, 4], [8, 2, 9, 4, 3], [4, 2, 2, 3, 2], [9, 2, 1, 4, 8], [6, 6, 1, 5, 3], [3, 5, 2, 8, 2], [7, 9, 1, 5, 1], [1, 4, 1, 8, 7], [9, 8, 7, 6, 4]])
# scale tree
ctree = tree.mod.edges_scale_to_root_height()
# get canvas and axes with tree plot
canvas, axes, mark = ctree.draw(
width=600,
height=300,
tip_labels_align=True,
tip_labels_style={"-toyplot-anchor-shift": "80px"}
);
# add n columns of data (here random data)
ncols = 5
xoffset = 1
for col in range(5):
# select the column of data
data = spdata[:, col]
# plot the data column
axes.scatterplot(
np.repeat(col, tree.ntips) + xoffset,
np.arange(tree.ntips),
marker='s',
size=10,
color="magenta",
opacity=0.1 + data[::-1] / data.max(),
title=data,
);
# stretch domain to fit long tip names
axes.x.domain.max = 40
Method 2:Ā¶
Using both a matrix and cartesian axes in toyplot. The key to aligning the two is that matrices have a margin of 50px by default. There aren't as many options to style matrix cells as there are in the option above. Here I used the right-side matrix labels to add and align tip names.
# a random rectangular matrix
matrix = np.arange(tree.ntips * 5).reshape(tree.ntips, 5)
matrix.shape
(13, 5)
# create a canvas
canvas = toyplot.Canvas(width=500, height=350);
# add tree
axes = canvas.cartesian(bounds=(50, 150, 70, 250))
tree.draw(axes=axes, tip_labels=False, tip_labels_align=True)
# add matrix
table = canvas.table(
rows=13,
columns=5,
margin=0,
bounds=(175, 250, 65, 255),
)
colormap = toyplot.color.brewer.map("BlueRed")
# apply a color to each cell in the table
for ridx in range(matrix.shape[0]):
for cidx in range(matrix.shape[1]):
cell = table.cells.cell[ridx, cidx]
cell.style = {
"fill": colormap.colors(matrix[ridx, cidx], 0, 100),
}
# style the gaps between cells
table.body.gaps.columns[:] = 3
table.body.gaps.rows[:] = 3
# hide axes coordinates
axes.show = False
# create a canvas
canvas = toyplot.Canvas(width=500, height=350);
# add tree
axes = canvas.cartesian(bounds=(50, 150, 70, 250))
tree.draw(axes=axes, tip_labels=False, tip_labels_align=True)
# add matrix
colormap = toyplot.color.brewer.map("BlueRed")
table = canvas.matrix(
(matrix, colormap),
bounds=(120, 300, 25, 295),
tshow=True,
tlabel="Traits",
lshow=False,
rshow=True,
margin=0,
rlocator=toyplot.locator.Explicit(range(tree.ntips), tree.get_tip_labels()[::-1])
)
# hide axes coordinates
axes.show = False