Saturday, June 20, 2020

Plotting an 'upward-facing' traitgram using phylomorphospace

A long-time friend & colleague just asked on Twitter:

You can do this in phytools, in fact, but only using phylomorphospace. Here's a demo.

First, we'll use some data from Revell & Collar (2009) that now comes packaged with phytools:

library(phytools)
data(sunfish.data)
data(sunfish.tree)
x<-setNames(sunfish.data$gape.width,
    rownames(sunfish.data))
tree<-as.phylo(sunfish.tree)
tree
## 
## Phylogenetic tree with 28 tips and 27 internal nodes.
## 
## Tip labels:
##  Acantharchus_pomotis, Lepomis_gibbosus, Lepomis_microlophus, Lepomis_punctatus, Lepomis_miniatus, Lepomis_auritus, ...
## 
## Rooted; includes branch lengths.
x
##    Acantharchus_pomotis        Lepomis_gibbosus     Lepomis_microlophus 
##                   0.114                  -0.133                  -0.151 
##       Lepomis_punctatus        Lepomis_miniatus         Lepomis_auritus 
##                  -0.103                  -0.134                  -0.222 
##      Lepomis_marginatus       Lepomis_megalotis         Lepomis_humilis 
##                  -0.187                  -0.073                   0.024 
##     Lepomis_macrochirus         Lepomis_gulosus     Lepomis_symmetricus 
##                  -0.191                   0.131                   0.013 
##       Lepomis_cyanellus      Micropterus_coosae      Micropterus_notius 
##                  -0.002                   0.045                   0.097 
##     Micropterus_treculi   Micropterus_salmoides  Micropterus_floridanus 
##                   0.056                   0.056                   0.096 
## Micropterus_punctulatus    Micropterus_dolomieu Centrarchus_macropterus 
##                   0.092                   0.035                  -0.007 
##      Enneacantus_obesus       Pomoxis_annularis  Pomoxis_nigromaculatus 
##                   0.016                  -0.004                   0.105 
##  Archolites_interruptus    Ambloplites_ariommus   Ambloplites_rupestris 
##                  -0.024                   0.135                   0.086 
##   Ambloplites_cavifrons 
##                   0.130

To create our traitgram (as the plot created by phytools::phenogram is properly called), we need to first compute the vertical and horizontal positions of our ancestral nodes:

a<-fastAnc(tree,x)
t<-sapply(1:Ntip(tree),nodeheight,tree=tree)
h<-sapply(1:tree$Nnode+Ntip(tree),nodeheight,
    tree=tree)

Now we're ready to feed these into phylomorphospace to create our plot:

par(mar=c(5.1,4.1,2.1,1.1))
phylomorphospace(tree,
    X=cbind(x[tree$tip.label],t),
    A=cbind(a,h),node.size=c(0,1),bty="l",
    label="off",xlab="relative gape width",
    ylab="time",
    ylim=c(0,1.4*max(h)))
fsize<-0.6
segments(x[tree$tip.label],t,x[tree$tip.label],
    t+0.05*max(h),lty="dotted")
text(x[tree$tip.label],t+0.05*max(h),
    gsub("_"," ",tree$tip.label),
    srt=90,pos=4,offset=0,
    cex=fsize,font=3)

plot of chunk unnamed-chunk-3

Note the phylomorphospace can also plot a tree with a mapped discrete character, just like phenogram.

For fun, let's also evenly space the tip labels this time.

E.g.:

cols<-setNames(c("blue","red"),c("non","pisc"))
par(mar=c(5.1,4.1,2.1,1.1))
phylomorphospace(sunfish.tree,colors=cols,
    node.by.map=TRUE,
    X=cbind(x[sunfish.tree$tip.label],t),
    A=cbind(a,h),node.size=c(0,1),bty="l",
    label="off",xlab="relative gape width",
    ylab="time",
    ylim=c(0,1.4*max(h)))
fsize<-0.6
segments(sort(x[sunfish.tree$tip.label]),t,
    seq(min(x),max(x),length.out=Ntip(sunfish.tree)),
    t+0.05*max(h),lty="dotted")
text(seq(min(x),max(x),length.out=Ntip(sunfish.tree)),
    t+0.05*max(h),
    gsub("_"," ",names(sort(x))),
    srt=90,pos=4,offset=0,
    cex=fsize,font=3)
legend(x="bottomleft",bty="n",
    legend=c("non-piscivorous","piscivorous"),
    pch=22,pt.cex=1.5,pt.bg=cols)
points(x[sunfish.tree$tip.label],t,pch=19,cex=1.2,
    col=cols[getStates(sunfish.tree,"tips")])

plot of chunk unnamed-chunk-4

Pretty cool.

4 comments:

  1. Hi, thanks for the script. I tried but seems that some arguments are outdated. Fast.Anc doesn't work ("could not find function "fastAnc"").

    ReplyDelete
  2. Can you make your blog searchable? It's got so many cool stuff, but takes a while find what you need.

    ReplyDelete
    Replies
    1. There's a search bar in the header, and it is also available to search engines, like Google. Do you have other suggestions?

      Delete

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