baltic
baltic copied to clipboard
Adding extra elements on tree plots
Hey, thank you for setting baltic
up as a python package: the installation was much easier now. I installed it days ago, and since them I've been playing with its functionalities. I have a question about plotting extra elements on trees. I'm trying to achieve a result similar to this baltic figure.
The extra elements I want to plot are:
- Node markers indicating posterior probabilities
- tMRCA violin plots at internal nodes
- Date ticks in months
- A subtree, pruned from the imput tree
Concerning 1, I was wondering how I can achieve that using a function similar to plotPoints
, but for nodes, not leaves.
Concerning 4, I tried to apply the function subtree
, however, instead of getting a tree rooted at the selected commonAncestor
tMRCA (2012.58), baltic
is keeping the root of the original tree (1970.55). As a result, when using the cmap 'hsv', instead of having a gradient from blue to red, in the final plot I only see red/magenta hues (indicating the misplacement of the root decades before the expected).
Since I couldn't find specific instructions on austhecia or curonia, I was wondering if you have any examples on how to plot these elements.
Thank you.
Cheers
Hey!
-
plotPoints()
can be used to draw the posterior probability node markers. The defaulttarget
function only filters the leaf_nodes.
You can customize and pass the following lambda functions to plotPoints(),
target=lambda k:k.branchType!='leaf'
size_function=lambda k: 50 if k.traits['posterior']>=0.5 else 10
colour_function=lambda k: "#000000" if k.traits['posterior']>=0.5 else "#ECECEC"
- Could you add the exact function call you used for
subtree()
?
Hey @gkarthik, thank you for your quick response.
For 1, your suggestion solved the issue! ✨ Thank you.
For 4, I've been defining the clade of interest from its ancestor
, based a set of 42 target_tips
.
keep_tips = [k.numName for k in treeFile.Objects if k.branchType == 'leaf' and k.name in target_tips]
ancestor = treeFile.commonAncestor(treeFile.getExternal(lambda k: k.numName in keep_tips))
subtree = treeFile.subtree(k=ancestor)
print(subtree.treeStats())
gives me this:
Tree height: 48.907069
Tree length: 90.130334
strictly bifurcating tree
annotations present
Numbers of objects in tree: 83 (41 nodes and 42 leaves)
and print(subtree.root.absoluteTime)
shows 2010.2653139215834
, which is actually the age of the parent node of the ancestor
, not its expected tMRCA, which is 2012.58, height=6.87 (see long root and MRCA in this newly plotted subtree, with the posterior probabilities markers).
Any idea of what is wrong? 6.87 as height is the expected result, but baltic is using the original tree height (48.907069), despite ancestor
being set as as the starting node of the subtree. It seems commonAncestor
is returning the ancestor branch, not node.
The root of the tree is set to the mrca's parent. Could you confirm that len(subtree.root.children)
is 1 and subtree.root.children[0].absoluteTime
is 2012.58
?
Correct:
len(subtree.root.children)
= 1
subtree.root.children[0].absoluteTime
= 2012.58
Seems like the parent of the mrca is the root of the entire tree?
A quick fix might be to pass a target
lambda function excluding the root to plotTree
.
target=lambda k: k != subtree.root
.
@evogytis might have better suggestions (accounting for time zone differences 😄).
Thank you, @gkarthik. I'm handling that using a pre-pruned tree in the meantime.
Do you have any suggestions concerning the points 2 (tMRCA violin plots) and 3 (Time ticks in months)?
- For the violin plots, I usually pull all the trees from the BEAST trees file and extract the height of the mrca. Following this, its a simple histogram that is shown in that figure. I have some ad hoc scripts lying around for this will see if I can dig them up.
- Haven't tested this much but this code should work to create tick labels at the first of every month of 2020 (01 Jan, 01 Feb .. ). You can modify it to fit the time interval you're considering.
import datetime as dt
new_ticks = [bt.decimalDate("2020-{}-01".format(i)) for i in range(1,13)]
new_tick_labels = ["01 "+dt.datetime.strptime("2020-{}-01".format(i), "%Y-%m-%d").strftime("%b") for i in range(1,13)]
ax.set_xticks(new_ticks)
ax.set_xticklabels(new_tick_labels)
@gkarthik thanks for taking care of this! :)
1., 2., and 3. have been addressed well by Karthik. Let us know if you need code references for any of these.
4. The root of the subtree being the parent of the node you called subtree
on is not a bug, but an intentional choice for producing the "exploded tree" plots with some branch length at its base. Admittedly, this is not ideal and this should ideally be an option (something like stem=True
).
treeHeight
being incorrect for the subtree is more worrying though, because the subtree
function should only deep copy the branches that comprise the subtree and assign them to a completely new tree
object which without a traversal should have treeHeight==0
by default. I can take a look at the data/code if neither is sensitive.