Today, Karla Shikev asked the following question:
I need to add species go a genus-level phylogeny, such that the generated nodes are consistent with a Yule process. I tried phytools' add.species.to.genus function, but the generated branch lengths tend to be too recent.
add.species.to.genus
adds tips randomly - not under some model. However, if we have a purely
genus-level tree (that is, a tree in which only genera are represented) and we want to produce random
species trees, in which each subtree arose by a Yule process - then this is not too hard either.
Here is a quick demo:
library(phytools)
## first let's simulate our genus tree:
genus.tree<-pbtree(n=7,tip.label=c("Abc","Def","Ghi","Jkl","Mno","Qrs","Tuv"))
## here it is:
plotTree(genus.tree,ftype="i")
Next, let's simulate some random species within each genus to attach to our tree. Here I simulate 1-5 species per genus; however, note that if there is only one species in a genus, then the tip of our genus tree will simply be renamed.
tips<-c()
for(i in 1:Ntip(genus.tree)){
n.genus<-sample(1:5,1)
for(j in 1:n.genus) tips<-c(tips,paste(genus.tree$tip.label[i],paste(sample(letters,6),collapse=""),sep="_"))
}
## these are the tips we want for our species tree:
tips
## [1] "Abc_svhmwl" "Abc_xhjdvy" "Def_ykhsrx" "Ghi_dxuhtl" "Ghi_avzyks"
## [6] "Ghi_buyawg" "Jkl_nbgmsk" "Jkl_ryialh" "Jkl_nwuqhe" "Jkl_ufmixj"
## [11] "Jkl_bclftw" "Mno_sonmkr" "Mno_kpydtl" "Mno_ujalsy" "Mno_cyeojk"
## [16] "Mno_sohent" "Qrs_xlbphe" "Qrs_nvsziu" "Qrs_iuwkjm" "Qrs_tscqbr"
## [21] "Qrs_azcfnl" "Tuv_tidfwy"
OK, now let's imagine how we want to create our species tree in which each genus arose via a Yule process. We can simply take the genus tree and glue on a Yule tree somewhere along the terminal edge leading to each tip in the genus tree! Here is an example function in which this is done at a random position along that edge - but this needn't be the case, and could be modified easily:
genus.to.pbSpeciesTree<-function(tree,tips){
N<-Ntip(tree)
genera<-tree$tip.label
for(i in 1:N){
jj<-grep(paste(genera[i],"_",sep=""),tips)
nn<-which(tree$tip.label==genera[i])
if(length(jj)>1){
h<-runif(n=1)*tree$edge.length[which(tree$edge[,2]==nn)]
tree$edge.length[which(tree$edge[,2]==nn)]<-
tree$edge.length[which(tree$edge[,2]==nn)]-h
sub.tree<-pbtree(n=length(jj),scale=h,tip.label=tips[jj])
tree<-bind.tree(tree,sub.tree,where=nn)
} else tree$tip.label[nn]<-tips[jj]
}
tree
}
species.tree<-genus.to.pbSpeciesTree(genus.tree,tips)
plotTree(species.tree,ftype="i")
As an alternative to rescaling, we could have simulated conditioned on time & a birth rate; however I'm not sure it would make much difference, and it would require that some birthrate be supplied.
That's it!
Thanks Liam!
ReplyDeleteHi, this code has been really usefull to me, so thank you! I wanted to further group the populations (I added populations to species not species to genus) according to a location variable I have. This way, populations that are closer geographically would also be closer phylogenetically. I guess I would have to create a subtree with specific requirements and then bind the subtree to the species, but I have been quite stuck on how to do that. Would you have any advice?
ReplyDelete