About two & a half years ago I posted about an interesting tree visualization style that you could call a slanted-fan tree. This is a circular tree graph, but in which the edges are connected in a slanted (i.e., “cladogram”) fashion.
Here's an example taken from a talk by Matt McGee at the SSB stand-alone meeting in 2020:
This style of tree can basically already be rendered using ape::plot.phylo
with type="radial"
, but phytools
so far lacks similar functionality. I promised this would be
coming to a phytools update soon,
but, more than two & a half years later, I've failed to live up to that promise!
Today, I'm just going to take one step closer & show what a stand-alone function to produce this type of plot might look like.
fanCladogram<-function(tree,use.edge.length=FALSE,...){
if(use.edge.length==FALSE){
if(hasArg(power)) power<-list(...)$power
else power<-0.6
tree<-compute.brlen(tree,power=power)
}
args<-list(...)
args$power<-NULL
args$tree<-tree
args$type<-"fan"
args$color<-"transparent"
do.call(plotTree,args)
obj<-get("last_plot.phylo",envir=.PlotPhyloEnv)
X<-cbind(obj$xx[1:Ntip(tree)],
obj$yy[1:Ntip(tree)])
rownames(X)<-tree$tip.label
A<-cbind(obj$xx[1:tree$Nnode+Ntip(tree)],
obj$yy[1:tree$Nnode+Ntip(tree)])
rownames(A)<-1:tree$Nnode+Ntip(tree)
pp.args<-list(...)
pp.args$power<-NULL
pp.args$tree<-tree
pp.args$X<-X
pp.args$A<-A
pp.args$ftype<-"off"
pp.args$node.size<-c(0,0)
pp.args$xlim<-obj$x.lim
pp.args$ylim<-obj$y.lim
pp.args$xaxt<-"n"
pp.args$type<-NULL
pp.args$add<-TRUE
do.call(phylomorphospace,pp.args)
}
That's pretty much it. Simple, right?
By default, I set use.edge.length=FALSE
. This is because (just as with a regular slanted phylogram) there's
no way to plot a fan-style slanted phylogram while guaranteeing that edges do not cross each other! (The
problem can be largely, if not entirely, averted by setting the edge lengths to the so-called 'Grafen'
values with ape::compute.brlen
.)
OK, now let's try it. In this example, I'll use a tree of squamtes that is featured in my upcoming book with Luke Harmon, but is originally from a paper by Matt Brandley et al. (2008).
library(phytools) ## load phytools
squamate.tree<-read.nexus(file="http://www.phytools.org/Rbook/11/squamate.tre")
fanCladogram(squamate.tree,lwd=1,ftype="i",fsize=0.3)
Neat.
Let's try a couple of other tricks.
Since we are using phytools::plotTree
internally to compute the node positions, we should also be able
to use other options of the plotTree
function, such as part
which, for a fan-style tree, tells R what
fraction of the circle to use for the tree. Let's try, this time using a phylogeny of cetaceans from
Morlon et al. (2011). I this case, I think I'll also 'ladderize'
the tree, just to see what that looks like.
whale.tree<-read.tree(file="http://www.phytools.org/Rbook/10/Cetacea.phy")
fanCladogram(ladderize(whale.tree),lwd=2,ftype="i",fsize=0.7,part=0.5)
We can likewise graph a stochastic character mapped tree. To illustrate this, why don't I use a phylogeny of bony fish & parental care from Benun Sutton & Wilson (2019).
bonyfish.tree<-read.tree(file="http://www.phytools.org/Rbook/7/bonyfish.tre")
bonyfish.data<-read.csv(file="http://www.phytools.org/Rbook/7/bonyfish.csv",
row.names=1,stringsAsFactors=TRUE)
care<-setNames(bonyfish.data$paternal_care,rownames(bonyfish.data))
smap.bonyfish<-make.simmap(bonyfish.tree,care,model="ARD",nsim=1)
## make.simmap is sampling character histories conditioned on
## the transition matrix
##
## Q =
## male none
## male 0.000000000 0.000000000
## none 0.002229021 -0.002229021
## (estimated using likelihood);
## and (mean) root node prior probabilities
## pi =
## male none
## 0.5 0.5
## Done.
cols<-setNames(palette()[c(2,4)],levels(care))
fanCladogram(bonyfish.tree,lwd=4,part=0.5,fsize=0.6)
par(fg="transparent") ## to avoid plotting tip labels x 2
fanCladogram(smap.bonyfish,lwd=2,colors=cols,part=0.5,fsize=0.6,add=TRUE)
par(fg="black")
legend("topleft",levels(care),pch=22,pt.bg=cols,pt.cex=2,
title="parental care",bty="n")
Lastly, we ought to be able to use this style for a "contMap"
type visualization. For this example, I'm
going to use a classic dataset for mammalian body mass evolution from Garland et al.
(1992).
mammal.tree<-read.tree(file="http://www.phytools.org/Rbook/2/mammalHR.phy")
mammal.tree<-ladderize(mammal.tree)
mammal.data<-read.csv(file="http://www.phytools.org/Rbook/2/mammalHR.csv",
row.names=1)
lnMass<-setNames(log(mammal.data$bodyMass),rownames(mammal.data))
cMap.mammals<-contMap(mammal.tree,lnMass,plot=FALSE)
cMap.mammals<-setMap(cMap.mammals,c("#440154FF","#21908CFF","#FDE725FF"))
fanCladogram(mammal.tree,lwd=6,part=0.5,fsize=0.8)
fanCladogram(cMap.mammals$tree,lwd=4,colors=cMap.mammals$cols,part=0.5,
fsize=0.8,add=TRUE)
add.color.bar(0.75,cols=cMap.mammals$cols,lims=cMap.mammals$lims,
digits=2,x=par()$usr[1]+0.1,y=0.9*par()$usr[4],prompt=FALSE,
title="log(body mass kg)",subtitle="")
That's it.
Can this be somehow combined with plotTree.wBars and arc.cladelabels?
ReplyDeleteHere is an example of using this method with plotTree.wBars. Later I hope to add one to the blog showing arc.cladelabels. Hope this helps!
DeleteHello Liam, thank you very much for your response!!!! It helped me a lot. I was able to add the bars to the tree :))) (you are awesome!!!)... I will be attentive to your blog for showing arc.cladelabels.
DeleteThank you again for your help!