Today, a phytools user writes:
“I am trying to use the command plotTree.wBars
in phytools to add bars as tips of a circular tree.
The bars represent values of a continuous trait assigned to the tips. I was wondering if it is possible
to also color these bars according to their values?”
The answer is, of course, yes. Let's see a couple of different examples.
For this example, I'll use a phylogeny and dataset for liolaemid lizards from Esquerre et al. (2019).
Luke Harmon & I use these data in our upcoming book, so the easiest way to get them is from the book website.
## load phytools
library(phytools)
## read tree
liol.tree<-read.nexus(file="http://www.phytools.org/Rbook/7/Liolaemidae.MCC.nex")
liol.tree
##
## Phylogenetic tree with 258 tips and 257 internal nodes.
##
## Tip labels:
## Ctenoblepharys_adspersa, Liolaemus_abaucan, Liolaemus_koslowskyi, Liolaemus_albiceps, Liolaemus_irregularis, Liolaemus_ornatus, ...
##
## Rooted; includes branch lengths.
## read data
liol.data<-read.csv(file="http://www.phytools.org/Rbook/7/Liolaemidae.data.csv",
row.names=1)
head(liol.data)
## parity_mode max_altitude temperature
## Ctenoblepharys_adspersa O 750 23.05
## Liolaemus_abaucan O 2600 20.20
## Liolaemus_albiceps V 4020 12.38
## Liolaemus_andinus V 4900 11.40
## Liolaemus_annectens V 4688 5.10
## Liolaemus_anomalus O 1400 23.78
I'm going to first plot the tree with max_altitude
using plotTree.wBars
. The only trick I'm adding
is that I'm going to steal some internal calculations (for scale=NULL
) to add a scale bar to the tree
using polygon
. If we had set a specific value for scale
, we'd use that instead of the variable
ss
.
max_altitude<-setNames(liol.data$max_altitude,rownames(liol.data))
plotTree.wBars(liol.tree,max_altitude,type="fan",lwd=1,
tip.label=TRUE,fsize=0.3)
ss<-0.3*max(nodeHeights(liol.tree))/diff(range(max_altitude))
h<-0.95*par()$usr[2]
bb<-3000
polygon(x=-h+c(0,0,ss*bb,ss*bb),y=h+c(1,0,0,1),col="grey")
text(x=-h+ss*bb,y=h+0.5,paste(bb,"m",sep=""),pos=4)
Next, let's do it again, but this time coloring all the bars greater than or equal to 2000m with one
color (blue) and all those below 2000m another (red). For this one, I will set the plotTree.wBars
argument col
which specifies the fill color of our polygons. The easiest way for me to do this here
is by creating a vector col
containing only the color blue (palette()[4]
in this case), and then
substituting palette()[2]
for all max_altitude<2000
.
max_altitude<-setNames(liol.data$max_altitude,rownames(liol.data))
col<-setNames(rep(palette()[4],length(max_altitude)),names(max_altitude))
col[max_altitude<2000]<-palette()[2]
plotTree.wBars(liol.tree,max_altitude,type="fan",lwd=1,
tip.label=TRUE,fsize=0.3,col=col)
ss<-0.3*max(nodeHeights(liol.tree))/diff(range(max_altitude))
h<-0.9*par()$usr[2]
bb<-2000
polygon(x=-h+c(0,0,ss*bb,ss*bb),y=h+c(1,0,0,1),col=palette()[2])
text(x=-h+ss*bb,y=h+0.5,paste("<2000m",sep=""),pos=4,cex=0.8)
h<-0.9*par()$usr[2]
bb<-2000
polygon(x=-h+c(0,0,ss*bb,ss*bb),y=0.95*h+c(1,0,0,1),col=palette()[4])
text(x=-h+ss*bb,y=0.95*h+0.5,paste(">2000m",sep=""),pos=4,cex=0.8)
Lastly, let's do it based on a continuous color gradient. I guess this should be the hardest, but I'm pretty sure we can figure it out!
In this case, what I decided to do was to first discretize my continuous character (altitude) by
normalizing it to the interval [0,1] and then multiplying this quantity by 1,000 (actually, 999 + 1).
After rounding, I have created an index vector between 1 & 1,000. I then create my color ramp with 1,000
colors and pull out those that I want to use in my graph. I chose the topo.colors
palette, but I could
have picked any.
ind<-round((max_altitude-min(max_altitude))/diff(range(max_altitude))*999)+1
cols<-setNames(topo.colors(n=1000)[ind],names(ind))
plotTree.wBars(liol.tree,max_altitude,type="fan",lwd=1,
tip.label=TRUE,fsize=0.3,col=cols)
ss<-0.3*max(nodeHeights(liol.tree))/diff(range(max_altitude))
h<-0.9*par()$usr[2]
bb<-10000
add.color.bar(bb*ss,topo.colors(n=1000),title="",
subtitle="max altitude (m)",lims=range(max_altitude),
x=-h,y=h,prompt=FALSE,fsize=0.8)
That's it folks!
How would I go about coloring the tree itself by a different variable?
ReplyDeleteI ended up doing:
DeleteplotTree.wBars(jetz2,c(l50,busco),lwd=0.1, colors = "white", type = "fan",legend = NULL, tip.label=TRUE, fsize=0.25)
par(fg="transparent")
plot(obj$tree,type="fan",add=TRUE,lwd=1.5,color=obj$cols,fsize=0.73)
Is there a better way? Thank you, -madza