使用ggtree實現進化樹的可視化和注釋

2021-02-08 統計之都

本文作者:餘光創,目前就讀於香港大學公共衛生系,開發過多個R/Bioconductor包,包括ChIPseeker, clusterProfiler, DOSE,ggtree,GOSemSim和ReactomePA。


進化樹看起來和層次聚類很像。有必要解釋一下兩者的一些區別。


層次聚類的側重點在於分類,把距離近的聚在一起。而進化樹的構建雖然也可以說是一個聚類過程,但側重點在於推測進化關係和進化距離(evolutionary distance)。


層次聚類的輸入是距離,比如euclidean或manhattan距離。把距離近的聚在一起。而進化樹推斷是從生物序列(DNA或胺基酸)的比對開始。最簡單的方法是計算一下序列中不匹配的數目,稱之為hamming distance(通常用序列長度做歸一化),使用距離當然也可以應用層次聚類的方法。進化樹的構建最簡單的方法是非加權配對平均法(Unweighted Pair Group Method with Arithmetic Mean, UPGMA),這其實是使用average linkage的層次聚類。這種方法在進化樹推斷上現在基本沒人用。更為常用的是鄰接法(neighbor joining),兩個節點距離其它節點都比較遠,而這兩個節點又比較近,它們就是neighbor,可以看出neighbor不一定是距離最近的兩個節點。真正做進化的人,基本不用這些基於距離的方法。現在主流的方法是最大似然法(Maximum likelihood, ML),通過進化模型(evolutionary model)估計拓樸結構和分支長度,估計的結果具有最高的概率能夠產生觀測數據(多序列比對)。另外還有最大簡約法和貝葉斯推斷等方法用於構建進化樹。



Newick是最常用的存儲進化樹的文件格式,如上面這個樹,拓樸結構用newick格式可以表示為:

(B,(A,C,E),D);

括號最外層是根節點,它有三個子節點,B, (A,C,E)和D,而節點(A,C,E)也有三個子節點A,C和E。


加上分支長度,使用 : 來分隔:

(B:6.0,(A:5.0,C:3.0,E:4.0):5.0,D:11.0);

比如A:5.0代表的是A與其父節點的距離是5.0。


內部節點也可以有label,寫在相應的括號外面,如下所示:

(B:6.0,(A:5.0,C:3.0,E:4.0)Ancestor1:5.0,D:11.0);

這是最為廣泛支持的文件格式,很多進化樹可視軟體只支持newick格式。


ggtree的開發源自於我需要在樹上做注釋,發現並沒有軟體可以很容易地實現,通常情況下我們把統計信息加到節點的label上來展示,比如CodeML的dN/dS分析,輸出文件裡就給用戶準備了newick樹文本,把dN/dS (ω) 加於節點label之上:


codeml_file <- system.file("extdata/PAML_Codeml/mlc", package="ggtree")tree_text <- readLines(codeml_file)[375:376]tree_text

## [1] "w ratios as labels for TreeView:" ## [2] "(K #0.0224 , N #0.0095 , (D #0.0385 , (L #0.0001 , (J #0.0457 , (G #0.1621 , ((C #0.0461 , (E #0.0641 , O #0.0538 ) #0.0001 ) #0.0395 , (H #0.1028 , (I #0.0001 , (B #0.0001 , (A #0.0646 , (F #0.2980 , M #0.0738 ) #0.0453 ) #0.0863 ) #1.5591 ) #0.0001 ) #0.0001 ) #0.0549 ) #0.0419 ) #0.0001 ) #0.0964 ) #0.0129 );"

這種做法只能展示一元信息,而且修改節點label真心是個髒活,滿滿的都是不爽,我心中理想的方式是樹與注釋信息分開,注釋信息可以方便地通過圖層加上去,而且可以自由組合。於是著手開發ggtree。ggtree是個簡單易用的R包,一行代碼ggtree(read.tree(file))即可實現樹的可視化。而注釋通過圖層來實現,多個圖層可以完成複雜的注釋,這得力於ggtree的設計。其中最重要的一點是如何來解析進化樹。


除了ggtree之外,我所了解到的其它畫樹軟體在畫樹的時候都把樹當成是線條的集合。很明顯畫出來的進化樹就是一堆線條,但是線條表示的是父節點和子節點的關係,除此之外沒有任何意義,而節點在進化樹上代表物種,葉子節點是我們構建進化樹的物種,內部節點是根據葉子節點推斷的共同祖先。我們所有的進化分析、推斷、實驗都是針對節點,節點才是進化樹上有意義的實體。這是ggtree設計的基礎,ggtree只映射節點到坐標系統中,而線條在geom_tree圖層中計算並畫出來。這是與其它軟體最根本的不同,也是ggtree能夠簡單地用圖層加注釋信息的基礎。

有很多可視化包基於ggplot2實現,包括各種gg打頭的,號稱擴展了ggplot2,支持圖形語法(grammar of graphics),我並不認同。雖然基於ggplot2產生的圖,我們可以用theme來進一步調整細節,用scale_系列函數來調整顏色和標尺的映射,但這些不足以稱之為』支持圖形語法』,圖形語法最關鍵核心的部分我認為是圖層和映射。

像ggphylo, OutbreakTools和phyloseq這幾個包都有基於ggplot2的畫樹函數,但其實都不支持圖形語法,它們所實現的是複雜的函數,畫完就完事了,用戶並不能使用圖層來添加相關的信息。


如果在OutbreakTools這個包中:


if (show.tip.label) { p <- p + geom_text(data = df.tip, aes(x = x, y = y, label = label), hjust = 0, size = tip.label.size)}

如果show.tip.label=FALSE,當函數返回p時df.tip就被扔掉,用戶想要再加tip.label就不可能了。ggphylo和phyloseq都是類似的實現,這些包把樹解析為線條,所以節點相關的信息需要額外的data.frame來存儲,並且只有極少數的預設參數,比如上面例子中的tip.label。在上面的例子中,用戶連更改tip.label的顏色都不可能,更別說使用額外的注釋信息了。


這幾個包所實現的畫圖函數,都可以很容易地用ggtree實現,並且經過測試,ggtree運行速度比這幾個包都要快。更多信息請參考ggtree的wiki頁面。


ggtree是真正擴展ggplot2,支持圖形語法的包。我們首先擴展ggplot支持tree object做為輸入,並實現geom_tree圖層來畫線條。


library(ggplot2)
library(ggtree)
set.seed(2015-11-26)
tree <- rtree(30)
ggplot(tree, aes(x, y)) + geom_tree()


ggtree函數是ggplot() + geom_tree() + xlab(NA) + ylab(NA) + theme_tree()的簡單組合。

ggtree(tree)


想要加tip.label,用geom_tiplab圖層,並且ggplot2的圖層都可以直接應用於ggtree。

ggtree(tree) + geom_tiplab() + geom_point(color='firebrick')


ggtree提供了多個函數可以把clade放大縮小(scaleClade),摺疊(collapse)和展開(expand),位置調換(flip)和旋轉(rotate),以及分類(groupOTU, groupClade)。


nwk <- system.file("extdata", "sample.nwk", package="ggtree")
tree <- read.tree(nwk)
p <- ggtree(tree)
cp <- ggtree(tree) %>% collapse(node=21) + ggtitle('collapse')
ep <- cp %>% expand(node=21) + ggtitle('expand')
hp <- p %>% hilight(node=21) + ggtitle('hilight')
rp <- hp %>% rotate(node=21) + ggtitle('rotate')
library(gridExtra)
grid.arrange(cp, ep, hp, rp, ncol=2)


ggtree支持的文件格式包括Newick, Nexus, NHX和jplace。


上面已經展示了Newick格式,下面的例子是NHX格式:


nhxfile = system.file("extdata", "ADH.nhx", package="ggtree")
nhx <- read.nhx(nhxfile)
ggtree(nhx, ladderize=F) + geom_tiplab() + geom_point(aes(color=S), size=8, alpha=.3) + theme(legend.position="right") + geom_text(aes(label=branch.length, x=branch), vjust=-.5) + xlim(NA, 0.3)


我們知道FigTree是針對BEAST的輸出設計的,可以把BEAST的統計推斷拿來給樹做注釋,但很多的進化分析軟體並沒有相應的畫樹軟體支持,用戶很難把信息展示出來。
ggtree支持ape, phangorn, r8s, RAxML, PAML, HYPHY, EPA, pplacer和BEAST的輸出。相應的統計分析結果可以應用於樹的注釋。可以說ggtree把這些軟體分析的結果帶給了R用戶,通過ggtree的解析, 這些進化分析結果可以進一步在R裡進行處理和統計分析,並不單單是在ggtree中展示而已。

raxml_file <- system.file("extdata/RAxML", "RAxML_bipartitionsBranchLabels.H3", package="ggtree")
raxml <- read.raxml(raxml_file)ggtree(raxml) + geom_text(aes(label=bootstrap, color=bootstrap)) + scale_color_gradient(high='red', low='darkgreen') + theme(legend.position='right')


multiPhylo也是支持的,所以100顆bootstrap樹可以同時用一行代碼展示出來。


btree_file <- system.file("extdata/RAxML", "RAxML_bootstrap.H3", package="ggtree")
btree = read.tree(btree_file)
ggtree(btree) + facet_wrap(~.id, ncol=10)


如果不分面,這100顆樹會重疊畫在一起,這也能很好地展示bootstrap分析的結果,bootstrap值低的clade,線條會比較亂,而bootstrap值高的地方,線條一致性比較好。

使用BaseML預測的祖先序列,ggtree解析結果的同時會把父節點到子節點的subsitution給統計出來,可以直接在樹上注釋:


rstfile <- system.file("extdata/PAML_Baseml", "rst", package="ggtree")
rst <- read.paml_rst(rstfile)
p <- ggtree(rst) + geom_text(aes(label=marginal_AA_subs, x=branch), vjust=-.5)
print(p)


不同於BaseML以鹼基為單位,CodeML預測祖先序列,以密碼子為單位。ggtree定義了一個操作符%<%,如果有相同的注釋信息要展示,可以用tree object來更新tree view。


rstfile <- system.file("extdata/PAML_Codeml", "rst", package="ggtree")
crst <- read.paml_rst(rstfile)
p %<% crst


像上面的例子,用crst來更新p,就是用crst畫出來的樹+注釋。對比兩圖,可以發現BaseML和CodeML推測的祖先序列是稍有不同的。


CodeML的dN/dS分析,我們可以直接把數據拿來給樹上色。同樣道理分類數據也可以拿來上色。


mlc_file <- system.file("examples/mlc", package="ggtree")
mlc <- read.codeml_mlc(mlc_file)
ggtree(mlc, aes(color=dN_vs_dS)) + scale_color_continuous(limits=c(0, 1.5), high='red', low='green', oob=scales::squish, name='dN/dS') + theme(legend.position='right')


進化樹已經被廣泛應用於各種跨學科的研究中,隨著實驗技術的發展,各種數據也更易於獲得,使用用戶數據注釋進化樹,也是ggtree所支持的。


nwk <- system.file("extdata", "sample.nwk", package="ggtree")
tree <- read.tree(nwk)
p <- ggtree(tree)
dd <- data.frame(taxa = LETTERS[1:13], place = c(rep("GZ", 5), rep("HK", 3), rep("CZ", 4), NA), value = round(abs(rnorm(13, mean=70, sd=10)), digits=1))
dd <- dd[sample(1:13, 13), ]
row.names(dd) <- NULL
print(dd)

## taxa place value## 1 A GZ 68.8## 2 J CZ 56.8## 3 L CZ 74.7## 4 C GZ 53.3## 5 F HK 62.8## 6 B GZ 60.8## 7 E GZ 87.1## 8 M <NA> 70.9## 9 H HK 67.0## 10 G HK 59.8## 11 I CZ 77.7## 12 K CZ 69.8## 13 D GZ 66.3

在上面的例子中,使用一個分類數據和一個連續型數據,輸入的唯一要求是第一列是taxon label。ggtree中定義了操作符%<+%,來添加數據。添加之後,用戶的數據對ggplot是可見的。可以用於樹的注釋。


p <- p %<+% dd + geom_text(aes(color=place, label=label), hjust=-0.5) + geom_tippoint(aes(size=value, shape=place, color=place), alpha=0.25)p+theme(legend.position="right")

ggtree還支持用戶把自己的數據和樹保存為jplace格式。

更多的實例請參考vignette。


ggtree允許把不同軟體的分析結果整合在一起,同時在樹上展示或者比較結果。在我們提交的論文中,使用了整合BEAST和CodeML的例子,在樹上展示dN/dS、時間軸、胺基酸替換、clade support values、物種和基因型 (genotype)等多維信息,6種不同的信息同時展示在一顆進化樹上,這是個複雜的例子,我們在附件1中展示了可重複的代碼。如果有興趣,可以留意一下我們的文章。 :)


我們把樹當成節點的集合,而不是線條的集合,這一點回歸到了進化樹的本質意義上,使這一實現成為可能。而支持圖形語法,與ggplot2的無縫銜接又讓注釋變得更加容易。ggtree為我們打開了各種注釋和操作的可能性。甚至於可以創造出好玩的圖,比如使用showtext來加載圖形化的字體、用emoji來畫樹、使用圖片來注釋樹等等。


一個比較正經又好玩的是使用PhyloPic資料庫上的圖形。


pp <- ggtree(tree) %>% phylopic("79ad5f09-cf21-4c89-8e7d-0c82a00ce728", color="steelblue", alpha = .3)
pp + geom_tiplab(align=T, linetype='dashed', linesize=.5) + geom_tippoint(color='firebrick', size=2)

另一個好玩又為我們展現各種可能性的是 subview 函數,它使得圖上加小圖變得特別容易。並且已經被應用於地圖上加餅圖。解決這個問題的初衷在於,想要給節點加餅圖注釋。有了subview函數之後,這會變得很容易,當然我還沒有寫出給節點加餅圖的函數,因為我還沒有這個需求,得有一些實際的數據做參考,這樣才能夠設計出更易用的函數呈現給用戶。


很多的功能還在開發之中,有問題/建議請及時在Github上報告(中英文都可以)。


本文微信編輯:馮璟爍



統計之都:專業、人本、正直的中國統計學門戶網站。

關注方式:掃描下圖二維碼。或查找公眾帳號,搜索 統計之都 或 CapStat 即可。


往期推送:進入統計之都會話窗口,點擊右上角小人圖標,查看歷史消息即可。



相關焦點

  • ggtree使用大全,進化樹編輯、美化一手資料全掌握
    進化樹展示的是進化關係,簡單說就是親緣關係,通常是使用物種的遺傳序列(如 DNA 序列、胺基酸序列等)來構建的。進化樹看起來和層次聚類很像,這兩者有木有區別呢?進化樹數據格式進化樹的數據格式有多種,常見的有 Newick、NEXUS 及 Phylip。Newick 格式Newick 格式是最常見的使用最廣泛的進化樹數據格式。
  • 我寫了一個簡單的進化樹可視化/注釋工具
    提到進化樹可視化/注釋工具,以我個人的認知,那麼現在可能只有兩個優秀的工具。一個是ITOLs,一個是ggtree。前者便不過多說明,是一個網頁工具。而後者則是你Y叔我大溼兄(公眾號:biobabble的運營者)。應是有部分朋友知道我從來就喊你Y叔叫大溼兄,也基本只有我這麼喊(我的意思是,不是每個人都能這麼喊)。
  • R語言ggtree按照指定的節點旋轉樹
    R語言裡的ggtree這個包可視化進化樹有一個默認的順序,如果想要改變枝的相對位置應該如何實現呢?
  • 跟著Nature microbiology學畫圖~R語言ggtree展示進化樹
    所以論文中實際的數據做的是聚類分析,而並不是進化樹。他這裡做聚類分析也能夠獲得每個節點對應的支持率。這個如何實現我暫時還不知道。為了模仿這個圖,下面的輸入數據我直接使用進化樹文件了,因為構建進化樹的時候能夠很方便的獲得節點的支持率信息。
  • facet_plot: 關聯數據和進化樹的通用方法
    ggtree 提供gheatmap 可視化熱圖和 msaplot 可視化多重序列比對,並且和進化樹關聯起來。
  • 用圖層疊加方法繪製環形進化樹
    使用這些web工具仍然很難將外部數據與進化樹進行整合。前幾年的一款基於python開發的GraPhlan(Asnicar et al.2015),可以實現在環形進化樹外圈添加相關數據信息。但其支持的幾何圖層有限,而且一開始的配置文件對於大多數研究者都很難構建,其支持的樹文件格式也較少,支持的可視化進化樹的布局也只有circular。
  • GraPhlAn:最美進化樹或層級分類樹學習筆記
    是一個可視化進化樹和基於分類等級繪製層級分類樹的工具。可以製作分類樹是它不同於R包ggtree和iTOL的地方。然就進化樹而言,iTOL功能最為全面,ggtree最容易上手,從功能上來講graphlan很多地方不如iTOL,比如,iTOL無限制添加的數據集,外環可以製作各種圖形包括箱線圖等,可以使用多種符號填充外環,但是Graphlan就不能這麼隨便了,只能使用兩個符號填充外環。再多的環屬性也就是設置環數量和顏色,透明度了。
  • 一文解決蛋白質家族分析及進化樹構建
    構建系統發育樹有三種主要的建樹方法,分別是距離法、最大節約法(maximumparsimony,MP)和最大似然法(maximum likelihood,ML)。最大似然法考察數據組中序列的多重比對結果,優化出擁有一定拓撲結構和樹枝長度的進化樹,這個進化樹能夠以最大的概率導致考察的多重比對結果;距離樹考察數據組中所有序列的兩兩比對結果,通過序列兩兩之間的差異決定進化樹的拓撲結構和樹枝長度,基於距離的方法有UPGMA、ME(Minimum Evolution,最小進化法)和NJ(Neighbor-Joining,鄰接法)等;最大節約法考察數據組中序列的多重比對結果
  • 詳解進化樹
    圖1 進化樹的結構示意圖根據是否指定了根節點,系統發育樹可以分為有根樹和無根樹。有根樹指定了根節點,樹中可以看出各個節點的距離和祖先節點以後各個分枝分化的先後關係,因此可以用於分化時間的推斷;無根樹沒有指定祖先節點,只能看出各個節點的拓撲結構和相對距離。無根樹和有根樹圖示如圖2。
  • 淺談生態學領域科研圖表繪製的方向和未來
    Y叔的ggtree提供了facet_plot函數,用於進化樹同各種圖表的組合,最近的版本還支持了聚類對象,因此,樣本距離和這使得gtree運用起來也就多一些。這張圖形是明顯的Graphlan繪製的,但是就這上面一個個的柱狀圖是沒有辦法在同一個坐標標度中實現的,所以目前絕對只能組合圖形。基於graphlan繪製的進化樹很漂亮,但是調參數確實是巨大的問題,由於目前還很少有工具可以替代graphlan,所以我們還是經常使用這個工具,目前,R語言中ggtree的設計理念似乎可以解決這個問題,但是兩年前我就問過Y叔了,至今外環繪製只有熱圖。
  • 克隆排序和進化可視化R包:ClonEvol
    R包ClonEvol利用其他方法預先聚類的變異來推斷和可視化克隆進化樹。它還可以可視化由其他方法識別的樹。它輸入的數據是其他工具識別出的雜合變異的聚類,從而推斷一致性的克隆進化樹,並估計個體樣本克隆中的癌細胞比例(也稱為克隆頻率)。
  • 宏基因組注釋和可視化神器MEGAN入門
    原理簡要示意圖通過Diamond對序列進行比對(nr),對輸出的daa比對結果文件進行功能和物種使用MEGAN注釋。當然不止可以使用Diamond比對結果,還可以使用blast的結果。在初始情況下,也就是剛剛打開MEGAN,還沒有導入RMA文件的時候,主界面展示NCBI的分類樹,默認展示三層結構,全部展示可以使用菜單欄的工具:rank。一旦數據讀入,NCBI的分類樹就會被我們導入文件的樹所替代,樹中枝節點大小代表了注釋到該節點的物種所匹配的序列數量。雙擊節點我們可以看到一些信息,例如:匹配到該節點的序列數量,總序列數量。
  • 可交互注釋你的ggplot圖
    如果你想畫一個箭頭,點兩下滑鼠定位起點和終點,箭頭就出現在圖上,是不是比你從數據計算出位置,或者直接在代碼裡寫死位置的王八拳編程來得更爽一些?今天就要介紹這麼一個包,讓你點點滑鼠就能注釋ggplot2出的圖。
  • 菌群數據的統計和可視化方法
    微生物組研究主要分為三步走,之前已經給大家講解了實驗設計與生信分析的方法(從樣本測序數據到生成物種和功能組成表),那麼接下來為大家介紹菌群測序數據下遊分析的統計和可視化方法,包括多樣性分析、物種組成分析、微生物差異分析、相關性分析、網絡分析、機器學習(構建疾病預測模型)、進化分析、來源分析以及常用可視化方法。
  • iTOL:快速繪製超高顏值的進化樹!
    人家的樹不管是從配色還是各種注釋信息都讓人無可挑剔,而你每次花了半個月時間做的進化樹不是被老闆嫌棄配色醜,就是太單調,沒有各種輔助的注釋信息。然後你默默捧起別人的文章學習時發現他們絕大部分都是用iTOL這個在線工具來進行的系統發育樹的美化的。
  • GraPhlAn教程中文版——超炫物種樹進化樹繪製
    即分枝矩形上邊的寬,1為矩形,0為三角形;本次使用0.8為梯形分枝比較美觀,畫面留白較少而且有成簇感。clade_marker_size:設置代表樹內進化枝根的標記的大小。默認值為20.0。節點圈的大小。本次使用40比默認大一倍,最後可根據圖形整體大小調整優化。
  • 進化樹作圖專題:進化樹的幾種分類
    本期承接上期進化樹作圖專題1的內容,和大家分享一下關於進化樹圖的幾種分類。 依據不同規則,樹的分類可以有很多種。由於本專題主要針對於作圖,所以這裡主要的原則就是——樹的外形。所謂「根」,就是一棵樹上的所有基因或物種的最近共同祖先(most recent common ancestor,MRCA)。
  • 用Python構建和可視化決策樹
    你根本不需要熟悉機器學習技術就可以理解決策樹在做什麼。決策樹圖很容易解釋。利弊決策樹方法的優點是:決策樹方法的缺點是:決策樹的訓練在計算上可能很昂貴。生成決策樹的過程在計算上非常昂貴。在每個節點上,每個候選拆分欄位都必須進行排序,才能找到其最佳拆分。在某些算法中,使用欄位組合,必須搜索最佳組合權重。剪枝算法也可能是昂貴的,因為許多候選子樹必須形成和比較。
  • 基於 Python 實現交互式數據可視化的工具(用於 Web)
    鑑於我自己對Python的熱愛和Python給學生帶來的舒適體驗,我決定向他們介紹Python中神奇的(我希望是的!)軟體包,它們可以實現所有我向學生展示的內容。 Seaborn的靜態可視化鑑於我過去使用seaborn的經驗,我很高興能夠向學生介紹seaborn產生的美麗的可視化圖案。
  • 「美」與「完美」之間的區別——進化樹構建的基礎上有了熱圖的修飾!
    ,可簡明地表示生物的進化歷程和親緣關係,因此,就出現了如下方的物種進化樹。果然簡單的進化樹已經滿足不了!別著急,還有更高級的分析——帶熱圖物種進化樹,如下圖。帶熱圖的物種進化樹是在進化樹的基礎上對其可視化,用熱圖展示每個分組的豐度均值。看到這裡,大家是不是對這個高級的圖的製作很感興趣呢?