Thursday, March 26, 2015

Interactive tree plotter to collapse & expand subtrees in R

I just posted some code to do a visualization in R in which we can, interactively, succcessively expand and collapse (to its ancestral node) any subtree of the phylogeny.

Since this is an interactive, animated exercise, it probably makes more sense for me to illustrate how it works with a screenshot video, but the code below illustrates the set up for the video demo.

library(phytools)
packageVersion("phytools")
## [1] '0.4.50'
tree<-pbtree(n=64,scale=1)
foo<-function(i,sep="._") paste(c(sample(LETTERS,1),sep,
    sample(letters,6)),collapse="")
tree$tip.label<-sapply(1:Ntip(tree),foo)
## do not run
# pruned<-collapseTree(tree)

Here is a video screeshot of the demo:

I should mention that this function is inspired by (as well as somewhat of a poor man's copy of) the interactive tree plotter on Gavin Naylor's amazing website sharksrays.org. Even if you have no interest in this tree plotter, the website is really neat so I'd encourage you to check it out.

This function is in a new non-CRAN version of phytools.

Feedback welcome.

Thursday, March 5, 2015

Splitting a tree across multiple pages, with node labels & other such things

After posting a simple wrapper to split a plotted tree across plotting devices or pages of a PDF file, I received the following inquiry:

Would there be a way to modify this so that annotations like node labels and axes could be applied to both 1/2s of a split tree at the same time? I've been struggling with a similar problem using plot.phylo() and we can get our tree to look like what we want on one page, but splitting it up while keeping node and branch annotations etc is problematic.

This seems hard - but is actually not too difficult. I can just add an argument fn that is a function containing the functions we want to run for each page of our plotted tree.

First, here is the function:

split.plotTree<-function(tree,splits=NULL,file=NULL,fn,...){
    ef<-0.037037037037
    if(!is.null(file)) pdf(file,width=8.5,height=11)
    if(is.null(splits)) splits<-(floor(0.5*Ntip(tree))+0.5)/Ntip(tree)
    S<-matrix(c(0,splits,splits,1+1/Ntip(tree)),length(splits)+1,2)
    S<-cbind(S[,1]+ef*(S[,2]-S[,1]),S[,2]-ef*(S[,2]-S[,1]))
    for(i in nrow(S):1){
        if(is.null(file)&&i<nrow(S)) par(ask=TRUE)
        plotTree(tree,ylim=Ntip(tree)*S[i,],...)
        fn()
    }
    if(!is.null(file)) oo<-dev.off()
}

Now, just for example, let's create a custom function that adds an axis to each subplot, and includes node labels:

foo<-function(){
    nodelabels()
    axis(1,at=c(0,round(max(nodeHeights(tree)),2)))
}

Finally, let's load phytools, simulate a tree, and try it out:

library(phytools)
tree<-pbtree(n=90)
split.plotTree(tree,splits=c(0.3275,0.683),fn=foo,ftype="i",
    mar=c(3,1,1,1))

plot of chunk unnamed-chunk-3 plot of chunk unnamed-chunk-3 plot of chunk unnamed-chunk-3

That's all there is to it.

Splitting a tree over mutiple plotting devices or pages

An R-sig-phylo subscriber asked the following yesterday:

I'm searching for a way to plot a huge phylogenetic tree to multiple pages in one searchable pdf file from R…. Does anybody know if this is possible and an effective way of doing this?

Well, my first response was that phytools has a function, splitplotTree, that can be used to split a plotted tree across columns in a single plotting window, or across plotting devices. Consequently, I responded:

One option is to use the function splitplotTree in phytools. By default it plots the split tree in two columns, but there is an option to split it into two windows. Then each plotted tree could be saved as a PDF.

On further thought, I realized that there is a better way. plotSimmap in phytools (and, consequently, plotTree, which uses plotTree, which uses plotSimmap internally) allows the user to control the y-limits of the plot. As a result it would be straightforward to write a simple wrapper that split the tree using a moving window over the plotting area. It also allows us to relatively easily split our tree over more than two pages. The following is an example of what that might look like:

split.plotTree<-function(tree,splits=NULL,file=NULL,...){
    ef<-0.037037037037
    if(!is.null(file)) pdf(file,width=8.5,height=11)
    if(is.null(splits)) splits<-(floor(0.5*Ntip(tree))+0.5)/Ntip(tree)
    S<-matrix(c(0,splits,splits,1+1/Ntip(tree)),length(splits)+1,2)
    S<-cbind(S[,1]+ef*(S[,2]-S[,1]),S[,2]-ef*(S[,2]-S[,1]))
    for(i in nrow(S):1){
        if(is.null(file)&&i<nrow(S)) par(ask=TRUE)
        plotTree(tree,ylim=Ntip(tree)*S[i,],...)
    }
    if(!is.null(file)) oo<-dev.off()
}

Note that in order to avoid having the tips & edges near the bottom of each page plot at the top of the following page, I had to trim ~4% off of the top & bottom of each plot. This is because for a given y range, R will create a plotting area that is 4% on each size larger than the area specified.

OK, now let's try it:

library(phytools)
n<-100
## create realistic tip labels
foo<-function(i) paste(sample(LETTERS,1),"._",paste(sample(letters,round(runif(1,min=4,max=8))),
    collapse=""),sep="")
tree<-pbtree(n=n,tip.label=sapply(1:n,foo))
splits<-c(0.255,0.505,0.755)
split.plotTree(tree,splits,ftype="i",mar=rep(1.1,4),fsize=0.9,lwd=1)

plot of chunk unnamed-chunk-2 plot of chunk unnamed-chunk-2 plot of chunk unnamed-chunk-2 plot of chunk unnamed-chunk-2

The splits mark the proportions of the plotted graph that I want to be displayed on each page.

We can also send the output to a multi-page PDF:

split.plotTree(tree,splits,ftype="i",mar=rep(1,4),file="split.plotTree.pdf",lwd=1)

The output is here: split.plotTree.pdf.

That's it.