OK, I just posted a new version of drop.tip.simmap which modifies both the $maps and $mapped.edge elements of the modified tree object created by (say) read.simmap or sim.history. Direct link to the code is here, but I have also built a new version (0.1-81) of phytools containing this update. You can download and install from source here.
Nothing spectacular, I just created this function from the tree pruning function that I completed (with some errors, now fixed in this version) this afternoon. Let's check it out:
> # first load from source or install new phytools
> install.packages("phytools_0.1-81.tar.gz",type="source", repos=NULL)
* installing *source* package 'phytools' ...
...
* DONE (phytools)
> require(phytools)
Loading required package: phytools
...
> # now simulate tree or read from file (here simulated)
> tree<-pbtree(n=20,scale=2)
> Q<-matrix(c(-2,1,1,1,-2,1,1,1,-2),3,3)
> mtree<-sim.history(tree,Q)
> # this is the full, unpruned tree
> plotSimmap(mtree,pts=F,lwd=3)
> # pick some tips to prune at random
> tips<-sample(tree$tip.label,5)
> tips
[1] "t20" "t8" "t5" "t16" "t14"
> ptree<-drop.tip.simmap(mtree,tips)
> plotSimmap(ptree,lwd=3,pts=F)
Well, this seems to work - but I welcome feedback from users that try it on their own data or from trees read from file. Good luck!
Thursday, May 10, 2012
"Mini" version of drop.tip
The phytools package can read, simulate, plot, reorder, and write stochastic character map style trees. (That is, trees in which a discrete character history is stored on the edges of the tree.) I even recently added the capacity to read SIMMAP v1.5 trees to the function read.simmap. Unfortunately, phytools only has a very limited capacity to manipulate SIMMAP style trees. In particular, the one existing function (drop.tip.simmap only alters the $mapped.edge element of the modified "phylo" object, without touching $maps. $mapped.edge contains only the time spent in each state on each edge, while $maps contains the times and order of each state on each edge. The latter element is required for both plotting (using plotSimmap) and for other types of analyses using (for instance) the new OUwie phylogenetics package.
Well, I'm at long last trying to build a function that will drop tips from the tree, but preserve both $maps and $mapped.edge. At first, I was hoping to do this using basically the same trick (but in reverse) that I used to read SIMMAP trees from file in the first version of read.simmap (this trick has long been replaced by a much more sophisticated function). Alas, this did not work. So I have gone back to the basics and I have started out by writing a basic tip dropping function of my own. This is incredibly simple, and much less versatile than the ape function drop.tip, but it gives me a structure to work from to build up a full drop.tip.simmap function.
The function is as follows:
pruneTree<-function(tree,tip){
tip<-which(tree$tip.label%in%tip)
edges<-match(tip,tree$edge[,2])
tree$edge<-tree$edge[setdiff(1:nrow(tree$edge),edges),]
z<-setdiff(tree$edge[,2],tree$edge[,1])
z<-z[z>length(tree$tip)]
while(length(z)>0){
edges<-match(z,tree$edge[,2])
tree$edge<-tree$edge[setdiff(1:nrow(tree$edge),edges),]
z<-setdiff(tree$edge[,2],tree$edge[,1])
z<-z[z>length(tree$tip)]
}
z<-setdiff(tree$edge[,2],tree$edge[,1])
tree$tip.label<-tree$tip.label[z]
tree$edge[which(tree$edge[,2]%in%z),2]<-1:length(tree$tip)
i<-1
while(i < nrow(tree$edge)){
single<-sum(tree$edge[i,2]==tree$edge[,1])==1
while(single){
if(sum(tree$edge[i,2]==tree$edge[,1])==1){
z<-match(tree$edge[i,2],tree$edge[,1])
tree$edge[i,2]<-tree$edge[z,2]
tree$edge<-tree$edge[setdiff(1:nrow(tree$edge),z),]
}
single<-sum(tree$edge[i,2]==tree$edge[,1])==1
}
i<-i+1
}
z<-unique(as.vector(tree$edge))
z<-z[z>length(tree$tip)]
y<-order(z)+length(tree$tip)
for(i in 1:length(z)) tree$edge[tree$edge==z[i]]<-y[i]
tree$Nnode<-max(tree$edge)-length(tree$tip)
tree$edge.length<-NULL
class(tree)<-"phylo"
return(tree)
}
OK, let's try it:
> require(phytools); source("pruneTree.R")
> set.seed(1)
> tree<-pbtree(n=20); tree$edge.length<-NULL
> plot(tree)
> ptree<-pruneTree(tree,c("t6","t8","t7","t3","t2","t15"))
> plot(ptree)
Now I just need to figure out how to preserve the mappings and I'll be all set!
Well, I'm at long last trying to build a function that will drop tips from the tree, but preserve both $maps and $mapped.edge. At first, I was hoping to do this using basically the same trick (but in reverse) that I used to read SIMMAP trees from file in the first version of read.simmap (this trick has long been replaced by a much more sophisticated function). Alas, this did not work. So I have gone back to the basics and I have started out by writing a basic tip dropping function of my own. This is incredibly simple, and much less versatile than the ape function drop.tip, but it gives me a structure to work from to build up a full drop.tip.simmap function.
The function is as follows:
pruneTree<-function(tree,tip){
tip<-which(tree$tip.label%in%tip)
edges<-match(tip,tree$edge[,2])
tree$edge<-tree$edge[setdiff(1:nrow(tree$edge),edges),]
z<-setdiff(tree$edge[,2],tree$edge[,1])
z<-z[z>length(tree$tip)]
while(length(z)>0){
edges<-match(z,tree$edge[,2])
tree$edge<-tree$edge[setdiff(1:nrow(tree$edge),edges),]
z<-setdiff(tree$edge[,2],tree$edge[,1])
z<-z[z>length(tree$tip)]
}
z<-setdiff(tree$edge[,2],tree$edge[,1])
tree$tip.label<-tree$tip.label[z]
tree$edge[which(tree$edge[,2]%in%z),2]<-1:length(tree$tip)
i<-1
while(i < nrow(tree$edge)){
single<-sum(tree$edge[i,2]==tree$edge[,1])==1
while(single){
if(sum(tree$edge[i,2]==tree$edge[,1])==1){
z<-match(tree$edge[i,2],tree$edge[,1])
tree$edge[i,2]<-tree$edge[z,2]
tree$edge<-tree$edge[setdiff(1:nrow(tree$edge),z),]
}
single<-sum(tree$edge[i,2]==tree$edge[,1])==1
}
i<-i+1
}
z<-unique(as.vector(tree$edge))
z<-z[z>length(tree$tip)]
y<-order(z)+length(tree$tip)
for(i in 1:length(z)) tree$edge[tree$edge==z[i]]<-y[i]
tree$Nnode<-max(tree$edge)-length(tree$tip)
tree$edge.length<-NULL
class(tree)<-"phylo"
return(tree)
}
OK, let's try it:
> require(phytools); source("pruneTree.R")
> set.seed(1)
> tree<-pbtree(n=20); tree$edge.length<-NULL
> plot(tree)
> ptree<-pruneTree(tree,c("t6","t8","t7","t3","t2","t15"))
> plot(ptree)
Now I just need to figure out how to preserve the mappings and I'll be all set!
Tuesday, May 8, 2012
Getting the ancestral state estimate from the "same" node on many trees
An R-SIG-phylo user today asked how to extract the ancestral state estimate from the same node on a set of trees. First, we need to define what is meant by the "same" node. Here, I presume that the same node is defined by the set of taxa descended from the that node (so is equivalently the MRCA of a set of tip species). In a set of trees read into R using read.tree there is no guarantee that a node defined in this way will have the same node number in every tree.
I suggested that one could use the phytools function findMRCA, which returns the most recent common ancestor for a set of tip species provided in a vector. Say our set of tip species consists of "t1", "t3", and "t8", to extract the estimated ancestral value for their MRCA on a set of trees, we can just use the following code (trait vector is in x):
> sp<-c("t1","t3","t8")
> target.state<-sapply(trees,function(a,x,sp) ace(x,a)$ace[as.character(findMRCA(a,sp))],x=x,sp=sp)
Simple as that. Of course, we can also might want to check in each case as to whether our tip species represent a monophyletic group. To do that we could just do:
> m<-sapply(trees,is.monophyletic,tips=sp)
And then to pull out only the target node state estimates from trees in which our list of taxa are monophyletic, you can use:
> target.state<-target.state[m]
That's it.
I suggested that one could use the phytools function findMRCA, which returns the most recent common ancestor for a set of tip species provided in a vector. Say our set of tip species consists of "t1", "t3", and "t8", to extract the estimated ancestral value for their MRCA on a set of trees, we can just use the following code (trait vector is in x):
> sp<-c("t1","t3","t8")
> target.state<-sapply(trees,function(a,x,sp) ace(x,a)$ace[as.character(findMRCA(a,sp))],x=x,sp=sp)
Simple as that. Of course, we can also might want to check in each case as to whether our tip species represent a monophyletic group. To do that we could just do:
> m<-sapply(trees,is.monophyletic,tips=sp)
And then to pull out only the target node state estimates from trees in which our list of taxa are monophyletic, you can use:
> target.state<-target.state[m]
That's it.
Friday, May 4, 2012
Ordering trees in a multiPhylo object by the number of tips
Today a R phylogenetics user asks if there is an easy way to sort the trees in a "multiPhylo" object by the number of tips each tree contains. The answer is yes. One way to do it is as follows:
> # first simulate a set of trees with different numbers of tips
> require(phytools)
> trees<-replicate(10,pbtree(n=round(runif(n=1,min=10,max=40))), simplify=FALSE)
> class(trees)<-"multiPhylo"
> trees
10 phylogenetic trees
> # now get the number of tips in each tree
> ntips<-sapply(trees,function(x) length(x$tip))
> ntips
[1] 35 19 13 34 18 27 18 33 10 25
> # now sort by the decreasing order of ntips
> sorted.trees<-trees[order(ntips,decreasing=T)]
To check & see that we have sorted our trees we can of course just plot them using plot.multiPhylo, but we can also just recalculate the vector ntips from our new list of trees:
> ntips.sorted<-sapply(sorted.trees,function(x) length(x$tip))
> ntips.sorted
[1] 35 34 33 27 25 19 18 18 13 10
Cool - sorted!
The same user also asked how to pull NULL trees from the list. I suggested one could just do the following:
> trees.no.null<-lapply(trees,function(x) if(!is.null(x)) x))
> class(trees.no.null)<-"multiPhylo"
Evidently, this works - but it just occurred to me that the following simpler option should also do the trick:
> trees.no.null<-trees[!is.null(trees)]
Cool.
> # first simulate a set of trees with different numbers of tips
> require(phytools)
> trees<-replicate(10,pbtree(n=round(runif(n=1,min=10,max=40))), simplify=FALSE)
> class(trees)<-"multiPhylo"
> trees
10 phylogenetic trees
> # now get the number of tips in each tree
> ntips<-sapply(trees,function(x) length(x$tip))
> ntips
[1] 35 19 13 34 18 27 18 33 10 25
> # now sort by the decreasing order of ntips
> sorted.trees<-trees[order(ntips,decreasing=T)]
To check & see that we have sorted our trees we can of course just plot them using plot.multiPhylo, but we can also just recalculate the vector ntips from our new list of trees:
> ntips.sorted<-sapply(sorted.trees,function(x) length(x$tip))
> ntips.sorted
[1] 35 34 33 27 25 19 18 18 13 10
Cool - sorted!
The same user also asked how to pull NULL trees from the list. I suggested one could just do the following:
> trees.no.null<-lapply(trees,function(x) if(!is.null(x)) x))
> class(trees.no.null)<-"multiPhylo"
Evidently, this works - but it just occurred to me that the following simpler option should also do the trick:
> trees.no.null<-trees[!is.null(trees)]
Cool.
Thursday, May 3, 2012
Specifying node colors with phylomorphospace()
A user recently made the following request:
I was just wondering if you would mind posting a short example of the code and data format used to specify colours in the phylomorphospace function (e.g., to create the figure form the paper describing the packages)?
Ok, just for reference, a screen grab of that figure is here:
What this figure shows is a projection of the phylogeny of Caribbean Anolis ecomorph species into a two dimensional morphospace defined by PC 1 & PC 2 from the morphological dataset and tree of Mahler et al. (2010). The tip nodes are colored by ecomorph category; and the internal nodes are black.
All right, for simplicity I'll assume that we want to replicate this general plot in a hypothetical case. First, let's simulate a tree and data for two characters:
> require(phytools)
> tree<-pbtree(n=21)
> X<-cbind(fastBM(tree),fastBM(tree))
Here, I have just simulated the tree & data; normally we would probably read these from file using functions like read.tree or read.nexus and read.csv. Here is a visualization of our simulated tree:
> plotTree(tree,pts=F)
Next, let's say we want to color (for simplicity) every third tip red, blue, or green. (I.e., the series t1, t4, t7, etc. is red.) Normally, we would probably read this from a file as well. For instance, in the ecomorph example, above, we would read a data file containing the ecomorph identification of each of the species from the tree. We could then settle on a color scheme for translation and convert our ecomorph codes to colors. In our example here, we can just do:
> tip.cols<-rep(c("red","blue","green"),7)
> names(tip.cols)<-tree$tip.label
> cols<-c(tip.cols[tree$tip.label],rep("black",tree$Nnode))
> names(cols)<-1:(length(tree$tip)+tree$Nnode)
> phylomorphospace(tree,X,control=list(col.node=cols))
If you examine this figure closely, you'll see that (as intended) everything third numbered tip node is colored red, blue, and green. Obviously, with a real (rather than simulated) tree and dataset we would read in the states for the tip nodes from a file (and they would most likely mean something). It is important to both reorder the color vector by tree$tip.label and re-number it by node number. Don't forget to add elements for internal nodes, even if they are to be colored black (for now at least: perhaps I will fix this in a future version). If we just want to color tip nodes, this is not difficult because the node numbers of the tips are 1 through N (for N species) in the order given by tree$tip.label. It is also probably a good idea to provide X as a matrix & control$col.node as a named vector, just to be safe.
I hope this helps!
I was just wondering if you would mind posting a short example of the code and data format used to specify colours in the phylomorphospace function (e.g., to create the figure form the paper describing the packages)?
Ok, just for reference, a screen grab of that figure is here:
What this figure shows is a projection of the phylogeny of Caribbean Anolis ecomorph species into a two dimensional morphospace defined by PC 1 & PC 2 from the morphological dataset and tree of Mahler et al. (2010). The tip nodes are colored by ecomorph category; and the internal nodes are black.
All right, for simplicity I'll assume that we want to replicate this general plot in a hypothetical case. First, let's simulate a tree and data for two characters:
> require(phytools)
> tree<-pbtree(n=21)
> X<-cbind(fastBM(tree),fastBM(tree))
Here, I have just simulated the tree & data; normally we would probably read these from file using functions like read.tree or read.nexus and read.csv. Here is a visualization of our simulated tree:
> plotTree(tree,pts=F)
Next, let's say we want to color (for simplicity) every third tip red, blue, or green. (I.e., the series t1, t4, t7, etc. is red.) Normally, we would probably read this from a file as well. For instance, in the ecomorph example, above, we would read a data file containing the ecomorph identification of each of the species from the tree. We could then settle on a color scheme for translation and convert our ecomorph codes to colors. In our example here, we can just do:
> tip.cols<-rep(c("red","blue","green"),7)
> names(tip.cols)<-tree$tip.label
> cols<-c(tip.cols[tree$tip.label],rep("black",tree$Nnode))
> names(cols)<-1:(length(tree$tip)+tree$Nnode)
> phylomorphospace(tree,X,control=list(col.node=cols))
If you examine this figure closely, you'll see that (as intended) everything third numbered tip node is colored red, blue, and green. Obviously, with a real (rather than simulated) tree and dataset we would read in the states for the tip nodes from a file (and they would most likely mean something). It is important to both reorder the color vector by tree$tip.label and re-number it by node number. Don't forget to add elements for internal nodes, even if they are to be colored black (for now at least: perhaps I will fix this in a future version). If we just want to color tip nodes, this is not difficult because the node numbers of the tips are 1 through N (for N species) in the order given by tree$tip.label. It is also probably a good idea to provide X as a matrix & control$col.node as a named vector, just to be safe.
I hope this helps!
Wednesday, May 2, 2012
New version of phytools (v 0.1-8) on CRAN
The newest version of phytools (0.1-8) is now available on CRAN. Check out the phytools CRAN page here. It usually takes a couple of days for a new package version to percolate through all the CRAN mirrors.
Updates in this version (over the previous CRAN release) include:
1. A new version of read.simmap that can read SIMMAP version 1.5 tree files.
2. A new version of ltt to simultaneously create lineage-through-time plots (and compute γ) for multiple trees.
3. A bug fix in fitBayes.
4. A new version of treeSlice that returns trivial as well as non-trivial subtrees.
5. New functions getExtant and getExtinct which return a list of the tip names of all the extant species (or its complement).
Enjoy!
Updates in this version (over the previous CRAN release) include:
1. A new version of read.simmap that can read SIMMAP version 1.5 tree files.
2. A new version of ltt to simultaneously create lineage-through-time plots (and compute γ) for multiple trees.
3. A bug fix in fitBayes.
4. A new version of treeSlice that returns trivial as well as non-trivial subtrees.
5. New functions getExtant and getExtinct which return a list of the tip names of all the extant species (or its complement).
Enjoy!
Tuesday, May 1, 2012
read.simmap now reads SIMMAP v1.5 input files
I finally got around to adding the capacity to read SIMMAP v1.5 (program description here). SIMMAP v1.5 mapped tree files use a very different modified Nexus format tree file than the previous version. Although I obviously can't speak directly to the motives of the program author, my guess is that this change was designed to allow SIMMAP tree files to be read into other programs that read Nexus format trees (albeit without the mapping). This was accomplished by bracketing all mappings with [ square brackets ] which are ignored as "comments" by Nexus convention. In particular, the following Newick string from version 1.0 SIMMAP tree:
((1:{0,0.3:1,0.4:0,0.3},2:{0,1.0}):{0,1.0},(3:{1,0.75:0,0.25},4:{0,1.0}):{0,1.0});
Representing the following tree:
Would be written as follows by SIMMAP v1.5:
((1:[&map={0,0.3,1,0.4,0}]1.0,2:[&map={0}]1.0):[&map={0}]1.0,(3:[&map={1,0.75,0}]1.0,4:[&map={0}]1.0):[&map={0}]1.0);
In SIMMAP v1.5 output files the mapping information for each branch is contained in the [&maps={...}] elements in which ... contains the state and (if there is more than one state on a branch) the time spend in each state from the tipward to the most rootward states on the edge - but excluding the time spend in the most rootward state (which can here be inferred by subtracting the time spend in each tipward state from the total length of the edge given after the ]).
Version is specified by a new argument: read.simmap(...,version), which is a numeric argument and can be 1.0 or 1.5.
Like prior versions of read.simmap, this present version can also read multiple trees in a list. However, I should note that if version=1.5 the tree or trees must be supplied in a Nexus style input file (not in a text string or Phylip style file, as is allowed for version=1.0).
Ok, well I have posted the function online here. It is also part of the latest version of phytools, version 0.1-8, which can be installed from the source code from my website (phytools page) and has also been submitted to CRAN.
I have only tested this with a few input files, so if you are able to give it a go - please let me know of the result.
((1:{0,0.3:1,0.4:0,0.3},2:{0,1.0}):{0,1.0},(3:{1,0.75:0,0.25},4:{0,1.0}):{0,1.0});
Representing the following tree:
Would be written as follows by SIMMAP v1.5:
((1:[&map={0,0.3,1,0.4,0}]1.0,2:[&map={0}]1.0):[&map={0}]1.0,(3:[&map={1,0.75,0}]1.0,4:[&map={0}]1.0):[&map={0}]1.0);
In SIMMAP v1.5 output files the mapping information for each branch is contained in the [&maps={...}] elements in which ... contains the state and (if there is more than one state on a branch) the time spend in each state from the tipward to the most rootward states on the edge - but excluding the time spend in the most rootward state (which can here be inferred by subtracting the time spend in each tipward state from the total length of the edge given after the ]).
Version is specified by a new argument: read.simmap(...,version), which is a numeric argument and can be 1.0 or 1.5.
Like prior versions of read.simmap, this present version can also read multiple trees in a list. However, I should note that if version=1.5 the tree or trees must be supplied in a Nexus style input file (not in a text string or Phylip style file, as is allowed for version=1.0).
Ok, well I have posted the function online here. It is also part of the latest version of phytools, version 0.1-8, which can be installed from the source code from my website (phytools page) and has also been submitted to CRAN.
I have only tested this with a few input files, so if you are able to give it a go - please let me know of the result.
Subscribe to:
Posts (Atom)







