Monday, January 29, 2024

How to add a tip below the root node using bind.tip in phytools

Today a phytools user asks about the function bind.tip

“What about the case the tip needs binding beyond the root? I.e. where bind.tip creates a trichotomy at the root. I find the documentation mentions this but I cannot find a solution to create an outgroup beyond the root.”

I thought this would be an easy matter, but it turns out that bind.tip does not in fact allow users to easily attach a new tip to the tree at a position below the global root of that tree – i.e., on the stem.

First, let’s take a look at the behavior of bind.tip when we attach a new tip to the global root of the tree.

library(phytools)
## Loading required package: ape
## Loading required package: maps
data("vertebrate.tree")
plotTree(vertebrate.tree,ftype="i")
nodelabels(frame="circle",cex=0.8)

plot of chunk unnamed-chunk-1

This is a tree of vertebrate species, so let’s attach the “outgroup” *Myxine glutinosa (the Atlantic hagfish) at the root and rename our phylogeny craniata.tree.

craniata.tree<-bind.tip(vertebrate.tree,"Myxine_glutinosa",
  where=12)
plotTree(ladderize(craniata.tree),ftype="i")

plot of chunk unnamed-chunk-2

Of course, this tree is not genuinely polytomous at the root – the hagfish is a true outgroup. Indeed, timetree.org asserts that Myxine glutinosa may have diverged from the other taxa in this tree as long ago as 563 million years in the past.

If bind.tip were better designed, it might’ve allowed us to use the argument position to create a stem below the root and then attach Myxine glutinosa on that stem.

Unfortunately, this does not work.

h<-max(nodeHeights(vertebrate.tree))
craniata.tree<-bind.tip(vertebrate.tree,"Myxine_glutinosa",
  where=12,position=563-h)
## Error in bind.tree(tree, tip, where = where, position = pp): tree 'x' has no root edge

Fortunately, there are a couple of quite easy work-arounds.

Firstly, since our tree is ultrametric, we can employ the argument edge.length to specify the terminal branch length leading to Myxine glutinosa and then simply re-root our tree along that edge as follows.

craniata.tree<-bind.tip(vertebrate.tree,"Myxine_glutinosa",
  where=12,
  edge.length=2*563-h)
craniata.tree<-midpoint.root(craniata.tree)
plotTree(ladderize(craniata.tree),ftype="i",
  mar=c(2.1,0.1,0.1,0.1),direction="leftwards",
  xlim=c(563,-239))
axis(1,at=seq(0,550,by=50),cex.axis=0.7)

plot of chunk unnamed-chunk-4

Great. That totally worked! (As a sidenote, think carefully about why I made the edge length leading to Myxine glutinosa 2*563-h rather than 563.)

Another solution is to first add a stem, then to add the additional time at the base of that stem.

vertebrate.tree$root.edge<-563-h
vertebrate.tree<-rootedge.to.singleton(vertebrate.tree)
plotTree(ladderize(vertebrate.tree),ftype="i")
nodelabels(frame="circle",cex=0.8)

plot of chunk unnamed-chunk-5

craniata.tree<-bind.tip(vertebrate.tree,
  where=12,"Myxine_glutinosa",edge.length=563)
plotTree(ladderize(craniata.tree),ftype="i",
  mar=c(2.1,0.1,0.1,0.1),direction="leftwards",
  xlim=c(563,-239))
axis(1,at=seq(0,550,by=50),cex.axis=0.7)

plot of chunk unnamed-chunk-6

That’s it.