倒不如画一些渐变色的线条吧!
这实际上是一个feature request,进化树上线条连接着父节点和子节点,两者之间的状态是不一样的,我们一般给树上颜色,画所谓的热树(heat-tree)用的是子节点的状态来给线条上色,这个需求是线条的颜色从父节点给子节点是渐变的,体现出从祖先节点到当前物种的一个进化转变过程。
这个需求两年前就提出来了,但当时我正在毕业答辩,根本没空理他。放着放着就忘记这码事了。但最近有人挖坟,把这个需求给挖出来了,于是我就着手实现它,当天就把这功能给放出来了。
来举个栗子:
anole.tree<-read.tree("http://www.phytools.org/eqg2015/data/anole.tre")
svl <- read.csv("http://www.phytools.org/eqg2015/data/svl.csv",
row.names=1)
svl <- as.matrix(svl)[,1]
fit <- phytools::fastAnc(anole.tree,svl,vars=TRUE,CI=TRUE)
有一个小蜥蜴的进化树,以及这些我们采样测量的小蜥蜴的体重数据。蜥蜴长这样子的:
这里使用phytools的fastAnc进行祖先节点的状态估计,我们设vars = TRUE和CI = TRUE,这样它会把方差和置信区间也估算出来。
td <- data.frame(node = nodeid(anole.tree, names(svl)),
trait = svl)
nd <- data.frame(node = names(fit$ace), trait = fit$ace)
d <- rbind(td, nd)
d$node <- as.numeric(d$node)
那么我们把这个叶子节点的测量数据和祖先节点的估算数据整合在一个数据框里。然后使用一个full_join方法,就可以把数据框整合到树对象中:
tree <- full_join(anole.tree, d, by = 'node')
当然另一个方法,你可以使用%<+%操作符,在画树的过程中进行整合,这也是我在《文章发表:两种方法在进化树上可视化数据》一文中所介绍的方法之一。
数据有了,最后就是可视化了,简单地讲,我实现了这个功能是通过额外的参数来做为开关的,以前的代码照常,没有任何变化,也不需要新的函数来实现这种渐变的功能。你只要画树的时候,传入新的参数continuous = TRUE,ggtree就知道你画的热树原来是要渐变的,然后它就会干所有该干的事情。你画出来就是渐变色的,而这不影响其它功能,你该加图层还照常加,该干啥都一样。
ggtree(tree, aes(color=trait), layout = 'circular',
ladderize = FALSE, continuous = TRUE, size=2) +
scale_color_gradientn(colours=c("red", 'orange', 'green', 'cyan', 'blue')) +
geom_tiplab2(hjust = -.1) + xlim(0, 1.2) + theme(legend.position = c(.05, .85))
还记得我在ggtree第一篇文章,《Ask me anything about ggtree》,演示的2维树吗?像这种有祖先状态的树,用来画2维树就正好,这种也有个名字叫phenogram,把表型数据投射到y轴上,ggtree画起来毫无压力。显然对于体重的进化,从上图是比较难以看出什么门道来的,但是下图,却异常地清晰了。没有什么图是完美的,但有些图能够帮助我们解释某些问题,而ggtree提供了画各种图的可能性。
ggtree(tree, aes(color=trait), continuous = TRUE, yscale = "trait") +
scale_color_viridis_c() + theme_minimal()
ggtree大法好,现在你不用,迟早也得用,我就是有这样的自信!
往期精彩