Monday, June 10, 2019

Plotting a contMap tree with tip labels color-coded according to a discrete character

Today a phytools user contacted me with the following question:

“So far, I have customized my tree in contMap fairly easily (add.color.bar, custom gradients, etc). Is there a way to customize the color of the text for the species names on the tree? For visualization purposes, I want to embed another factor level of colors within species.”

The answer is, of course, “yes” - it's just a matter of how. I have a related solution on this blog that I posted some time ago; however, I thought the specific details of the solution could pose some problems for "contMap" & thus it seemed worth re-posting.

I'm going to use real data in the form of body size & ecomorph of Caribbean Anolis lizards:

library(phytools)
data(anoletree)
anoletree
## 
## Phylogenetic tree with 82 tips and 81 internal nodes.
## 
## Tip labels:
##  Anolis_ahli, Anolis_allogus, Anolis_rubribarbus, Anolis_imias, Anolis_sagrei, Anolis_bremeri, ...
## 
## The tree includes a mapped, 6-state discrete character with states:
##  CG, GB, TC, TG, Tr, Tw
## 
## Rooted; includes branch lengths.
svl<-as.matrix(read.csv(
    file="http://www.phytools.org/TS2018/data/anole.data.csv",
    row.names=1))[,1]
svl
##            ahli         alayoni         alfaroi        aliniger 
##         4.03913         3.81570         3.52665         4.03656 
##        allisoni         allogus   altitudinalis         alumina 
##         4.37539         4.04014         3.84299         3.58894 
##       alutaceus     angusticeps     argenteolus     argillaceus 
##         3.55489         3.78860         3.97131         3.75787 
##         armouri   bahorucoensis        baleatus        baracoae 
##         4.12168         3.82745         5.05306         5.04278 
##       barahonae        barbatus        barbouri        bartschi 
##         5.07696         5.00395         3.66393         4.28055 
##         bremeri        breslini    brevirostris        caudalis 
##         4.11337         4.05111         3.87415         3.91174 
##       centralis  chamaeleonides    chlorocyanus     christophei 
##         3.69794         5.04235         4.27545         3.88465 
##       clivicola     coelestinus        confusus           cooki 
##         3.75873         4.29797         3.93844         4.09154 
##    cristatellus    cupeyalensis         cuvieri    cyanopleurus 
##         4.18982         3.46201         4.87501         3.63016 
##         cybotes     darlingtoni       distichus dolichocephalus 
##         4.21098         4.30204         3.92880         3.90855 
##       equestris      etheridgei   eugenegrahami       evermanni 
##         5.11399         3.65799         4.12850         4.16561 
##         fowleri         garmani         grahami           guafe 
##         4.28878         4.76947         4.15427         3.87746 
##       guamuhaya         guazuma       gundlachi       haetianus 
##         5.03695         3.76388         4.18810         4.31654 
##      hendersoni      homolechis           imias    inexpectatus 
##         3.85983         4.03281         4.09969         3.53744 
##       insolitus        isolepis           jubar           krugi 
##         3.80047         3.65709         3.95260         3.88650 
##      lineatopus   longitibialis        loysiana          lucius 
##         4.12861         4.24210         3.70124         4.19891 
##    luteogularis      macilentus        marcanoi          marron 
##         5.10109         3.71576         4.07948         3.83181 
##         mestrei       monticola          noblei        occultus 
##         3.98715         3.77061         5.08347         3.66305 
##         olssoni        opalinus      ophiolepis        oporinus 
##         3.79390         3.83838         3.63796         3.84567 
##        paternus        placidus       poncensis        porcatus 
##         3.80296         3.77397         3.82038         4.25899 
##          porcus      pulchellus         pumilis quadriocellifer 
##         5.03803         3.79902         3.46686         3.90162 
##      reconditus        ricordii     rubribarbus          sagrei 
##         4.48261         5.01396         4.07847         4.06716 
##    semilineatus        sheplani         shrevei      singularis 
##         3.69663         3.68292         3.98300         4.05800 
##      smallwoodi         strahmi       stratulus     valencienni 
##         5.03510         4.27427         3.86988         4.32152 
##       vanidicus    vermiculatus        websteri       whitemani 
##         3.62621         4.80285         3.91655         4.09748

Unfortunately or data & tree don't exactly match in that the labels of the tree are in the format Genus_species, whereas the data are coded just by specific epithet. Let's make the tree match the data:

tree<-anoletree
tree$tip.label<-setNames(sapply(anoletree$tip.label,
    function(x) strsplit(x,"_")[[1]][2]),NULL)
tree
## 
## Phylogenetic tree with 82 tips and 81 internal nodes.
## 
## Tip labels:
##  ahli, allogus, rubribarbus, imias, sagrei, bremeri, ...
## 
## The tree includes a mapped, 6-state discrete character with states:
##  CG, GB, TC, TG, Tr, Tw
## 
## Rooted; includes branch lengths.
ecomorph<-as.factor(getStates(tree,"tips"))
svl<-svl[tree$tip.label]

Now we can make a test plot as follows:

object<-contMap(tree,exp(svl),fsize=c(0.6,0.8))

plot of chunk unnamed-chunk-3

Now, we need to pull out the information that we need as follows:

lastPP<-get("last_plot.phylo",envir=.PlotPhyloEnv)
## for fun, let's change our contMap gradient
object<-setMap(object,c("blue","green","yellow"))
plot(object,ftype="off",xlim=lastPP$x.lim,fsize=c(0,0.8),
    leg.txt="SVL (mm)",legend=2.5,sig=1)
## make sure our discrete character is in the order of our tree
ecomorph<-ecomorph[object$tree$tip.label]
cols<-setNames(RColorBrewer::brewer.pal(
    n=length(levels(ecomorph)),
    "Dark2"),levels(ecomorph))
for(i in 1:length(ecomorph))
    text(lastPP$xx[i],lastPP$yy[i],object$tree$tip.label[i],
        pos=4,cex=0.6,col=cols[ecomorph[i]],font=3)
add.simmap.legend(colors=cols,prompt=FALSE,
    x=3.7,y=-5.4,vertical=FALSE,fsize=0.8)

plot of chunk unnamed-chunk-4

That's it.

2 comments:

Note: due to the very large amount of spam, all comments are now automatically submitted for moderation.