原文链接: 2 Manipulating Tree with Data
2.1使用Tidy接口操作树文件
所有被treeio解析/合并的树数据 treeio (Wang et al., 2020)都可以使用 tidytree包转换成tidy格式数据。tidytree包提供了tidy接口来操作带有关联数据的树。例如,可以将外部数据与系统发育联系起来,也可以使用tidyverse verbs合并从不同来源获得的进化数据。在处理完树数据后,可以将其转换回一个树数据对象并导出到单个树文件中,在R中进一步分析或使用ggtree (Yu et al., 2017)和 ggtreeExtra (Xu, Dai, et al., 2021)进行可视化。
2.1.1 phylo对象
phylo是R语言中系统发育分析包包 ape 中的基础命令 (Paradis et al., 2004)。该领域的大部分R包广泛依赖于phylo对象。tidytree 包提供了 as_tibble 方法,将 phylo 对象转换为 tidy 数据框架,一个tbl_tree对象。
library(ape)
set.seed(2017)
tree <- rtree(4)
tree
##
## Phylogenetic tree with 4 tips and 3 internal nodes.
##
## Tip labels:
## t4, t1, t3, t2
##
## Rooted; includes branch lengths.
x <- as_tibble(tree)
x
## # A tibble: 7 × 4
## parent node branch.length label
##
## 1 5 1 0.435 t4
## 2 7 2 0.674 t1
## 3 7 3 0.00202 t3
## 4 6 4 0.0251 t2
## 5 5 5 NA
## 6 5 6 0.472
## 7 6 7 0.274
可以使用 as.phylo() 方法将 tbl_tree 对象转换回 phylo 对象。
as.phylo(x)
##
## Phylogenetic tree with 4 tips and 3 internal nodes.
##
## Tip labels:
## t4, t1, t3, t2
##
## Rooted; includes branch lengths.
x <- as_tibble(tree)
x
## # A tibble: 7 × 4
## parent node branch.length label
##
## 1 5 1 0.435 t4
## 2 7 2 0.674 t1
## 3 7 3 0.00202 t3
## 4 6 4 0.0251 t2
## 5 5 5 NA
## 6 5 6 0.472
## 7 6 7 0.274
tbl_tree对象可以使用as.phylo()方法转换回一个phylo对象。
as.phylo(x)
##
## Phylogenetic tree with 4 tips and 3 internal nodes.
##
## Tip labels:
## t4, t1, t3, t2
##
## Rooted; includes branch lengths.
使用tbl_tree对象使树和数据操作更有效、更容易(参见FAQ中的示例)。例如,我们可以使用dplyr命令full_join()将进化信息与phylogeny联系起来:
d <- tibble(label = paste0('t', 1:4),
trait = rnorm(4))
y <- full_join(x, d, by = 'label')
y
## # A tibble: 7 × 5
## parent node branch.length label trait
##
## 1 5 1 0.435 t4 0.943
## 2 7 2 0.674 t1 -0.171
## 3 7 3 0.00202 t3 0.570
## 4 6 4 0.0251 t2 -0.283
## 5 5 5 NA NA
## 6 5 6 0.472 NA
## 7 6 7 0.274 NA
2.1.2 treedata对象
tidytree包定义了treedata类来存储带有相关数据的系统发育树。在将外部数据映射到树结构之后,tbl_tree对象可以转换为一个树数据对象。
as.treedata(y)
## 'treedata' S4 object'.
##
## ...@ phylo:
##
## Phylogenetic tree with 4 tips and 3 internal nodes.
##
## Tip labels:
## t4, t1, t3, t2
##
## Rooted; includes branch lengths.
##
## with the following features available:
## 'trait'.
treeio包(Wang et al., 2020)中使用treedata类来存储,由常用软件(BEAST、EPA、HyPhy、MrBayes、pml、PHYLDOG、PPLACER、r8s、RAxML和RevBayes等)推断的进化证据(详见第一章)。
tidytree包还提供了as_tibble()方法来将treedata对象转换为tidy数据框架。系统发生树结构和进化信息存储在tbl_tree对象中,使得操作不同软件推断的进化统计数据和将外部数据连接到相同的树结构变得一致和容易。
y %>% as.treedata %>% as_tibble
## # A tibble: 7 × 5
## parent node branch.length label trait
##
## 1 5 1 0.435 t4 0.943
## 2 7 2 0.674 t1 -0.171
## 3 7 3 0.00202 t3 0.570
## 4 6 4 0.0251 t2 -0.283
## 5 5 5 NA NA
## 6 5 6 0.472 NA
## 7 6 7 0.274 NA
2.1.3 访问相关的节点
dplyr语句可以直接应用于tbl_tree来操作树数据。此外,tidytree还提供了几个语句来过滤相关节点,包括child()、parent()、offspring()、ancestor()、sibling()和MRCA()。
这些语句接受一个tbl_tree对象和一个可以是节点号或标签的选定节点。
child(y, 5)
## # A tibble: 2 × 5
## parent node branch.length label trait
##
## 1 5 1 0.435 t4 0.943
## 2 5 6 0.472 NA
parent(y, 2)
## # A tibble: 1 × 5
## parent node branch.length label trait
##
## 1 6 7 0.274 NA
offspring(y, 5)
## # A tibble: 6 × 5
## parent node branch.length label trait
##
## 1 5 1 0.435 t4 0.943
## 2 7 2 0.674 t1 -0.171
## 3 7 3 0.00202 t3 0.570
## 4 6 4 0.0251 t2 -0.283
## 5 5 6 0.472 NA
## 6 6 7 0.274 NA
ancestor(y, 2)
## # A tibble: 3 × 5
## parent node branch.length label trait
##
## 1 5 5 NA NA
## 2 5 6 0.472 NA
## 3 6 7 0.274 NA
sibling(y, 2)
## # A tibble: 1 × 5
## parent node branch.length label trait
##
## 1 7 3 0.00202 t3 0.570
MRCA(y, 2, 3)
## # A tibble: 1 × 5
## parent node branch.length label trait
##
## 1 6 7 0.274 NA
所有这些方法也是在treeio中实现的,用于处理phylo和treedata对象。您可以尝试使用树对象访问相关节点。例如,下面的命令将输出所选内部节点5的子节点:
child(tree, 5)
## [1] 1 6
注意,树对象的方法输出相关的节点号,而tbl_tree对象的方法输出一个包含相关信息的tibble对象。
2.2 数据集成
2.2.1 结合树的数据
treeio包(Wang et al., 2020)作为一种基础工具,可将从通用分析程序推断出的各种类型的系统发育数据导入r中并使用。例如,由 CODEML估计的dN/dS或祖先序列,以及由BEAST/MrBayes推断出的进化支持值(后向)。此外,treeio支持将外部数据与系统发育联系起来。它将这些外部系统发育数据(来自软件输出或外部来源)带到R社区,并使其可用于R中的进一步分析。此外,treeio还可以将多个系统发育树与它们的节点/分支特定的属性数据组合成一个。因此,从本质上讲,一个这样的属性(如替换率)可以映射到同一节点/分支的另一个属性(如dN/dS),以便进行比较和进一步计算(Yu et al., 2017; Yu et al., 2018))。
之前发表的一组数据,76个H3血凝素基因序列包含猪和人甲型流感病毒(Liang et al., 2014),在这里被用来证明比较不同软件推断的进化统计数据的实用性。利用BEAST对数据集进行时间尺度估计,CODEML对数据集进行同义和非同义替换估计。在这个例子中,我们首先使用read.beast()函数将BEAST的输出解析为两个树数据对象,然后使用read.codeml()函数将CODEML的输出解析为两个树数据对象。然后,通过merge_tree()函数将这两个包含独立的特定于节点/分支的数据集的对象合并。
beast_file <- system.file("examples/MCC_FluA_H3.tree", package="ggtree")
rst_file <- system.file("examples/rst", package="ggtree")
mlc_file <- system.file("examples/mlc", package="ggtree")
beast_tree <- read.beast(beast_file)
codeml_tree <- read.codeml(rst_file, mlc_file)
merged_tree <- merge_tree(beast_tree, codeml_tree)
merged_tree
## 'treedata' S4 object that stored information
## of
## '/home/ygc/R/library/ggtree/examples/MCC_FluA_H3.tree',
## '/home/ygc/R/library/ggtree/examples/rst',
## '/home/ygc/R/library/ggtree/examples/mlc'.
##
## ...@ phylo:
##
## Phylogenetic tree with 76 tips and 75 internal nodes.
##
## Tip labels:
## A/Hokkaido/30-1-a/2013, A/New_York/334/2004,
## A/New_York/463/2005, A/New_York/452/1999,
## A/New_York/238/2005, A/New_York/523/1998, ...
##
## Rooted; includes branch lengths.
##
## with the following features available:
## 'height', 'height_0.95_HPD', 'height_median',
## 'height_range', 'length', 'length_0.95_HPD',
## 'length_median', 'length_range', 'posterior', 'rate',
## 'rate_0.95_HPD', 'rate_median', 'rate_range', 'subs',
## 'AA_subs', 't', 'N', 'S', 'dN_vs_dS', 'dN', 'dS',
## 'N_x_dN', 'S_x_dS'.
合并beast_tree和codeml_tree对象后,从BEAST和CODEML输出文件导入的所有特定于节点/分支的数据都可以在merged_tree对象中使用。使用整洁树包将树对象转换为整洁的数据帧,并将其可视化为CODEML推断的dN/dS、dN和dS与BEAST推断的相同分支上的速率(以替换单位/站点/年计算的替换率)的hexbin散点图。
library(dplyr)
df <- merged_tree %>%
as_tibble() %>%
select(dN_vs_dS, dN, dS, rate) %>%
subset(dN_vs_dS >=0 & dN_vs_dS <= 1.5) %>%
tidyr::gather(type, value, dN_vs_dS:dS)
df$type[df$type == 'dN_vs_dS'] <- 'dN/dS'
df$type <- factor(df$type, levels=c("dN/dS", "dN", "dS"))
ggplot(df, aes(rate, value)) + geom_hex() +
facet_wrap(~type, scale='free_y')
合并beast_tree和codeml_tree对象后,从BEAST和CODEML输出文件导入的所有特定于节点/分支的数据都可以在merged_tree对象中使用。使用整洁树包将树对象转换为整洁的数据帧,并将其可视化为CODEML推断的dN/dS、dN和dS与BEAST推断的相同分支上的速率(以替换单位/站点/年计算的替换率)的hexbin散点图。
输出如图2.1所示。然后,我们可以使用Pearson相关性测试这些节点/分支特定数据的相关性,在本例中,这表明dN和dS,而不是dN/dS与速率显著(p值)相关。
使用merge_tree()函数,我们能够比较使用来自不同软件包的相同模型的分析结果,或者使用不同或相同软件的不同模型的分析结果。它还允许用户集成来自不同软件包的不同分析结果。合并树数据并不局限于软件发现,也允许将外部数据与分析发现联系起来。merge_tree()函数是可链接的,允许几个树对象合并成一个。
phylo <- as.phylo(beast_tree)
N <- Nnode2(phylo)
d <- tibble(node = 1:N, fake_trait = rnorm(N), another_trait = runif(N))
fake_tree <- treedata(phylo = phylo, data = d)
triple_tree <- merge_tree(merged_tree, fake_tree)
triple_tree
## 'treedata' S4 object that stored information
## of
## '/home/ygc/R/library/ggtree/examples/MCC_FluA_H3.tree',
## '/home/ygc/R/library/ggtree/examples/rst',
## '/home/ygc/R/library/ggtree/examples/mlc'.
##
## ...@ phylo:
##
## Phylogenetic tree with 76 tips and 75 internal nodes.
##
## Tip labels:
## A/Hokkaido/30-1-a/2013, A/New_York/334/2004,
## A/New_York/463/2005, A/New_York/452/1999,
## A/New_York/238/2005, A/New_York/523/1998, ...
##
## Rooted; includes branch lengths.
##
## with the following features available:
## 'height', 'height_0.95_HPD', 'height_median',
## 'height_range', 'length', 'length_0.95_HPD',
## 'length_median', 'length_range', 'posterior', 'rate',
## 'rate_0.95_HPD', 'rate_median', 'rate_range', 'subs',
## 'AA_subs', 't', 'N', 'S', 'dN_vs_dS', 'dN', 'dS',
## 'N_x_dN', 'S_x_dS', 'fake_trait', 'another_trait'.
##
## # The associated data tibble abstraction: 151 × 28
## # The 'node', 'label' and 'isTip' are from the phylo tree.
## node label isTip height height_0.95_HPD
##
## 1 1 A/Hokkaido/30-1-… TRUE 0
## 2 2 A/New_York/334/2… TRUE 9
## 3 3 A/New_York/463/2… TRUE 8
## 4 4 A/New_York/452/1… TRUE 14
## 5 5 A/New_York/238/2… TRUE 8
## 6 6 A/New_York/523/1… TRUE 15
## 7 7 A/New_York/435/2… TRUE 13
## 8 8 A/New_York/582/1… TRUE 17
## 9 9 A/New_York/603/1… TRUE 17
## 10 10 A/New_York/657/1… TRUE 19
## # … with 141 more rows, and 23 more variables:
## # height_median , height_range ,
## # length , length_0.95_HPD ,
## # length_median , length_range ,
## # posterior , rate , rate_0.95_HPD ,
## # rate_median , rate_range , subs ,
## # AA_subs , t , N , S , …
上面显示的triple_tree对象包含了从BEAST和CODEML获得的分析结果,以及从外部来源获得的进化特征。所有这些信息都可以使用ggtree (Yu et al., 2017)和ggtreeExtra (Xu, Dai, et al., 2021)来注释树。
2.2.2 连接外部数据与系统发育
除上述与树相关的分析结果外,还有广泛的异质性数据,包括表型数据、实验数据和临床数据等,需要整合并与系统发育联系起来。例如,在病毒进化的研究中,树节点可能与流行病学信息相关,如位置、年龄和亚型。功能注释可能需要映射到基因树,以进行比较基因组学研究。为了便于数据集成,treeio提供了full_join()方法来将外部数据链接到系统发育,并将其存储在phylo或treedata对象中。请注意,将外部数据链接到一个门系对象将产生一个树数据对象来存储具有关联数据的输入门系。full_join方法也可以在整洁的数据帧级(即前面描述的tbl_tree对象)和ggtree级(在第7章中描述)使用 (Yu et al., 2018)。
下面的示例计算引导值,并通过匹配它们的节点号将这些值与树(一个门系对象)合并。
library(ape)
data(woodmouse)
d <- dist.dna(woodmouse)
tr <- nj(d)
bp <- boot.phylo(tr, woodmouse, function(x) nj(dist.dna(x)))
## 'treedata' S4 object'.
##
## ...@ phylo:
##
## Phylogenetic tree with 15 tips and 13 internal nodes.
##
## Tip labels:
## No305, No304, No306, No0906S, No0908S, No0909S, ...
##
## Unrooted; includes branch lengths.
##
## with the following features available:
## 'bootstrap'.
##
## # The associated data tibble abstraction: 28 × 4
## # The 'node', 'label' and 'isTip' are from the phylo tree.
## node label isTip bootstrap
##
## 1 1 No305 TRUE NA
## 2 2 No304 TRUE NA
## 3 3 No306 TRUE NA
## 4 4 No0906S TRUE NA
## 5 5 No0908S TRUE NA
## 6 6 No0909S TRUE NA
## 7 7 No0910S TRUE NA
## 8 8 No0912S TRUE NA
## 9 9 No0913S TRUE NA
## 10 10 No1103S TRUE NA
## # … with 18 more rows
另一个例子演示了通过匹配它们的提示标签来将进化特征与树(一个treedata对象)合并。
file <- system.file("extdata/BEAST", "beast_mcc.tree", package="treeio")
beast <- read.beast(file)
x <- tibble(label = as.phylo(beast)$tip.label, trait = rnorm(Ntip(beast)))
full_join(beast, x, by="label")
## 'treedata' S4 object that stored information
## of
## '/home/ygc/R/library/treeio/extdata/BEAST/beast_mcc.tree'.
##
## ...@ phylo:
##
## Phylogenetic tree with 15 tips and 14 internal nodes.
##
## Tip labels:
## A_1995, B_1996, C_1995, D_1987, E_1996, F_1997, ...
##
## Rooted; includes branch lengths.
##
## with the following features available:
## 'height', 'height_0.95_HPD', 'height_median',
## 'height_range', 'length', 'length_0.95_HPD',
## 'length_median', 'length_range', 'posterior', 'rate',
## 'rate_0.95_HPD', 'rate_median', 'rate_range', 'trait'.
##
## # The associated data tibble abstraction: 29 × 17
## # The 'node', 'label' and 'isTip' are from the phylo tree.
## node label isTip height height_0.95_HPD
##
## 1 1 A_1995 TRUE 18
## 2 2 B_1996 TRUE 17
## 3 3 C_1995 TRUE 18
## 4 4 D_1987 TRUE 26
## 5 5 E_1996 TRUE 17
## 6 6 F_1997 TRUE 16
## 7 7 G_1992 TRUE 21
## 8 8 H_1992 TRUE 21
## 9 9 I_1994 TRUE 19
## 10 10 J_1983 TRUE 30
## # … with 19 more rows, and 12 more variables:
## # height_median , height_range ,
## # length , length_0.95_HPD ,
## # length_median , length_range ,
## # posterior , rate , rate_0.95_HPD ,
## # rate_median , rate_range , trait
操纵树对象会因为用于处理对象格式的碎片化函数而难以处理,更不用说将外部数据连接到系统发育结构了。使用treeio包 (Wang et al., 2020),可以很容易地组合来自不同来源的树数据。此外,使用tidytree包,使用整洁的数据原理操作树更容易,并且与已经广泛使用的工具(包括dplyr、tidyr、ggplot2和ggtree)一致 (Yu et al., 2017)。
2.2.3分组分类单元
groupOTU()和groupClade()方法被设计用来向输入树对象添加分类单元分组信息。这些方法分别在tidytree、treeio和ggtree中实现,以支持为tbl_tree、phylo和tredata以及ggtree对象添加分组信息。这个分组信息可以在树的可视化中直接使用ggtree(图6.5)(e.g., coloring a tree based on grouping information)。
2.2.3.1 groupClade
groupClade()方法接受一个内部节点或内部节点的向量,以添加所选clade/clades的分组信息。
nwk <- '(((((((A:4,B:4):6,C:5):8,D:6):3,E:21):10,((F:4,G:12):14,H:8):13):
13,((I:5,J:2):30,(K:11,L:11):2):17):4,M:56);'
tree <- read.tree(text=nwk)
groupClade(as_tibble(tree), c(17, 21))
## # A tibble: 25 × 5
## parent node branch.length label group
##
## 1 20 1 4 A 1
## 2 20 2 4 B 1
## 3 19 3 5 C 1
## 4 18 4 6 D 1
## 5 17 5 21 E 1
## 6 22 6 4 F 2
## 7 22 7 12 G 2
## 8 21 8 8 H 2
## 9 24 9 5 I 0
## 10 24 10 2 J 0
## # … with 15 more rows
2.2.3.2 groupOTU
set.seed(2017)
tr <- rtree(4)
x <- as_tibble(tr)
## the input nodes can be node ID or label
groupOTU(x, c('t1', 't4'), group_name = "fake_group")
## # A tibble: 7 × 5
## parent node branch.length label fake_group
##
## 1 5 1 0.435 t4 1
## 2 7 2 0.674 t1 1
## 3 7 3 0.00202 t3 0
## 4 6 4 0.0251 t2 0
## 5 5 5 NA 1
## 6 5 6 0.472 1
## 7 6 7 0.274 1
groupClade()和groupOTU()都可以使用tbl_tree、phylo和tredata以及ggtree对象。下面是一个将groupOTU()与一个 phylo tree 对象一起使用的例子。
groupOTU(tr, c('t2', 't4'), group_name = "fake_group") %>%
as_tibble
## # A tibble: 7 × 5
## parent node branch.length label fake_group
##
## 1 5 1 0.435 t4 1
## 2 7 2 0.674 t1 0
## 3 7 3 0.00202 t3 0
## 4 6 4 0.0251 t2 1
## 5 5 5 NA 1
## 6 5 6 0.472 1
## 7 6 7 0.274 0
另一个使用ggtree对象的例子可以在6.4章节中找到。
groupOTU将从输入节点回溯到最近的公共祖先。在这个例子中,节点1、4、5和6被分组在一起( (4 (t2) -> 6 -> 5 and 1 (t4) -> 5).
相关的操作分类单位(OTUs)是分组的,它们不一定在一个进化支内。它们可以是单系的(枝),多系的或副系的。
cls <- list(c1=c("A", "B", "C", "D", "E"),
c2=c("F", "G", "H"),
c3=c("L", "K", "I", "J"),
c4="M")
as_tibble(tree) %>% groupOTU(cls)
## # A tibble: 25 × 5
## parent node branch.length label group
##
## 1 20 1 4 A c1
## 2 20 2 4 B c1
## 3 19 3 5 C c1
## 4 18 4 6 D c1
## 5 17 5 21 E c1
## 6 22 6 4 F c2
## 7 22 7 12 G c2
## 8 21 8 8 H c2
## 9 24 9 5 I c3
## 10 24 10 2 J c3
## # … with 15 more rows
如果在回溯到最近的共同祖先时出现冲突,用户可以将 overlap 参数设置为origin(第一个计数)、overwrite(默认值,最后一个计数)或abandon(取消选择以便分组)。
2.3 树的置根
系统发生树可以用指定的外群重新根化。ape包实现了一个root()方法来重新根化存储在phylo对象中的树,而treeio包为treedata对象提供了root()方法。此方法设计用于使用与指定外组相关的数据或基于在 ape 包中实现的root()在指定节点上重新建立系统发育树的根。
我们首先使用left_join()将外部数据链接到树,并将所有信息存储在一个树数据对象trda中。
library(ggtree)
library(treeio)
library(tidytree)
library(TDbook)
# load `tree_boots`, `df_tip_data`, and `df_inode_data` from 'TDbook'
trda <- tree_boots %>%
left_join(df_tip_data, by=c("label" = "Newick_label")) %>%
left_join(df_inode_data, by=c("label" = "newick_label"))
trda
## 'treedata' S4 object'.
##
## ...@ phylo:
##
## Phylogenetic tree with 7 tips and 6 internal nodes.
##
## Tip labels:
## Rangifer_tarandus, Cervus_elaphus, Bos_taurus,
## Ovis_orientalis, Suricata_suricatta,
## Cystophora_cristata, ...
## Node labels:
## Mammalia, Artiodactyla, Cervidae, Bovidae,
## Carnivora, Caniformia
##
## Rooted; includes branch lengths.
##
## with the following features available:
## '', 'vernacularName', 'imageURL', 'imageLicense',
## 'imageAuthor', 'infoURL', 'mass_in_kg',
## 'trophic_habit', 'ncbi_taxid', 'rank',
## 'vernacularName.y', 'infoURL.y', 'rank.y',
## 'bootstrap', 'posterior'.
##
## # The associated data tibble abstraction: 13 × 17
## # The 'node', 'label' and 'isTip' are from the phylo tree.
## node label isTip vernacularName imageURL
##
## 1 1 Rangifer_tarand… TRUE Reindeer http://…
## 2 2 Cervus_elaphus TRUE Red deer http://…
## 3 3 Bos_taurus TRUE Cattle https:/…
## 4 4 Ovis_orientalis TRUE Asiatic moufl… http://…
## 5 5 Suricata_surica… TRUE Meerkat http://…
## 6 6 Cystophora_cris… TRUE Hooded seal http://…
## 7 7 Mephitis_mephit… TRUE Striped skunk http://…
## 8 8 Mammalia FALSE
## 9 9 Artiodactyla FALSE
## 10 10 Cervidae FALSE
## # … with 3 more rows, and 12 more variables:
## # imageLicense , imageAuthor ,
## # infoURL , mass_in_kg ,
## # trophic_habit , ncbi_taxid , rank ,
## # vernacularName.y , infoURL.y ,
## # rank.y , bootstrap , posterior
然后,我们可以用关联到分支和节点的数据映射来重新根化树,如图2.2所示。这个图是使用ggtree实现的(参见第4章和第5章)。
# reroot
trda2 <- root(trda, outgroup = "Suricata_suricatta", edgelabel = TRUE)
# The original tree
p1 <- trda %>%
ggtree() +
geom_nodelab(
mapping = aes(
x = branch,
label = bootstrap
),
nudge_y = 0.36
) +
xlim(-.1, 4) +
geom_tippoint(
mapping = aes(
shape = trophic_habit,
color = trophic_habit,
size = mass_in_kg
)
) +
scale_size_continuous(range = c(3, 10)) +
geom_tiplab(
offset = .14,
) +
geom_nodelab(
mapping = aes(
label = vernacularName.y,
fill = posterior
),
geom = "label"
) +
scale_fill_gradientn(colors = RColorBrewer::brewer.pal(3, "YlGnBu")) +
theme(legend.position = "right")
# after reroot
p2 <- trda2 %>%
ggtree() +
geom_nodelab(
mapping = aes(
x = branch,
label = bootstrap
),
nudge_y = 0.36
) +
xlim(-.1, 5) +
geom_tippoint(
mapping = aes(
shape = trophic_habit,
color = trophic_habit,
size = mass_in_kg
)
) +
scale_size_continuous(range = c(3, 10)) +
geom_tiplab(
offset = .14,
) +
geom_nodelab(
mapping = aes(
label = vernacularName.y,
fill = posterior
),
geom = "label"
) +
scale_fill_gradientn(colors = RColorBrewer::brewer.pal(3, "YlGnBu")) +
theme(legend.position = "right")
plot_list(p1, p2, tag_levels='A', ncol=2)
图2.2:对一个树进行置根。原始树(A)和重根树(B)与相关的数据正确地映射到树的分支或节点。(A)和(B)分别出现在通向根尖节Suricata_suricatta的分枝生根前和生根后。
outgroup参数表示特定的新outgroup,它可以是节点标签(字符)或节点编号。如果它是一个值,这意味着使用本技巧下面的节点作为新根;如果它有多个值,这意味着最近的常见值将被用作新根。注意,如果节点标签应该被视为边缘标签,则应该将edgelabel设置为TRUE,以返回节点和相关数据之间的正确关系。有关re-root的更多细节,包括注意事项和陷阱,请参阅综述文章 (Czech et al., 2017)
。
2.4 调节分支
系统发育数据可以合并进行联合分析(图2.1)。它们可以作为更复杂的注释显示在相同的树结构上,以帮助可视化地检查它们的进化模式。存储在树数据对象中的所有数值数据都可以用于重新缩放树分支。例如,CodeML推断dN/dS、dN和dS,所有这些统计数据都可以用作分支长度(图2.3)。所有这些值也可以用来为树着色(会话4.3.4),并且可以投影到垂直维度以创建一个二维树或表现型图(会话4.2.2和图4.5和4.11)。
p1 <- ggtree(merged_tree) + theme_tree2()
p2 <- ggtree(rescale_tree(merged_tree, 'dN')) + theme_tree2()
p3 <- ggtree(rescale_tree(merged_tree, 'rate')) + theme_tree2()
plot_list(p1, p2, p3, ncol=3, tag_levels='A')
图2.3:重新缩放树枝树的分支按时间(从根开始的年份)缩放(A)。使用dN作为分支长度(B)重新缩放树。使用替换率(C)重新缩放树。
2.5用数据划分树的子集
2.5.1在系统发育树中去除tips
有时,我们希望从系统发育树中删除所选择的tps。这是由于序列质量低、序列组装错误、部分序列比对错误、系统发育推断错误等原因造成的。
假设我们想从树中删除三个提示(红色)(图2.4A), drop.tip()方法删除指定的提示并更新树(图2.4B)。所有相关的数据将在更新后的树中进行维护。
f <- system.file("extdata/NHX", "phyldog.nhx", package="treeio")
nhx <- read.nhx(f)
to_drop <- c("Physonect_sp_@2066767",
"Lychnagalma_utricularia@2253871",
"Kephyes_ovata@2606431")
p1 <- ggtree(nhx) + geom_tiplab(aes(color = label %in% to_drop)) +
scale_color_manual(values=c("black", "red")) + xlim(0, 0.8)
nhx_reduced <- drop.tip(nhx, to_drop)
p2 <- ggtree(nhx_reduced) + geom_tiplab() + xlim(0, 0.8)
plot_list(p1, p2, ncol=2, tag_levels = "A")
图2.4:移除树中的tips梢。原始树有三个tips(红色)要删除(A)。更新后的树删除选中的tips(B)。
2.5.2根据tip laber 划分树的子集
有时一棵树可能很大,很难只看到感兴趣的部分。tree_子集()函数是在treeio包中创建的(Wang et al., 2020),以提取树部分的子集,同时仍然保持树部分的结构。图2.5A中的beast_tree有点拥挤。显然,我们可以让图形变高以给标签留出更多的空间(类似于在FigTree中使用扩展滑块),或者我们可以让文本变小。然而,当你有很多 tips 时(例如,成百上千的tips),这些解决方案并不总是适用的。特别是,当您只对树的特定tips周围的部分感兴趣时。
假设你对树中的tip /Swine/HK/168/2012 感兴趣(图2.5A),你想看看这个tips的直系亲属。
默认情况下,tree_subset()函数将在内部调用groupOTU()来从其他提示中分配指定的组提示(图2.5B)。此外,分支长度和相关的数据在子集设置后进行维护(图2.5C)。默认情况下,树的根总是锚定在子集树的零的位置,所有的距离都是相对于这个根的。如果您希望所有的距离都相对于原始根,您可以指定根位置(by root.position parameter)。位置参数)到子集树根边,即从原始根到子集树根的分支长度之和(图2.5D和E)。
beast_file <- system.file("examples/MCC_FluA_H3.tree", package="ggtree")
beast_tree <- read.beast(beast_file)
p1 = ggtree(beast_tree) +
geom_tiplab() + xlim(0, 40) + theme_tree2()
tree2 = tree_subset(beast_tree, "A/Swine/HK/168/2012", levels_back=4)
p2 <- ggtree(tree2, aes(color=group)) +
scale_color_manual(values = c("black", "red"), guide = 'none') +
geom_tiplab() + xlim(0, 4) + theme_tree2()
p3 <- p2 +
geom_point(aes(fill = rate), shape = 21, size = 4) +
scale_fill_continuous(low = 'blue', high = 'red') +
xlim(0,5) + theme(legend.position = 'right')
p4 <- ggtree(tree2, aes(color=group),
root.position = as.phylo(tree2)$root.edge) +
geom_tiplab() + xlim(18, 24) +
scale_color_manual(values = c("black", "red"), guide = 'none') +
theme_tree2()
p5 <- p4 +
geom_rootedge() + xlim(0, 40)
plot_list(p1, p2, p3, p4, p5,
design="AABBCC\nAADDEE", tag_levels='A')
图2.5:特定提示的子集树。原始树(A).子集树(B).带数据的子集树(C).将子集树相对于原始位置可视化,(D)不带根的树,(E)有根树。
2.5.3根据内部节点编号划分子树
tree_subset()函数将整个进化枝也追溯到特定的水平看进化枝的相关类群(图2.6 a和B)。我们可以使用tree_subset()函数来放大所选部分和整个树的一部分,它类似于ape::zoom()函数来查看一个非常大的树(图2.6C和D)。用户也可以使用viewClade()函数来限制树在特定演化枝上的可视化,如session 6.1所示。
clade <- tree_subset(beast_tree, node=121, levels_back=0)
clade2 <- tree_subset(beast_tree, node=121, levels_back=2)
p1 <- ggtree(clade) + geom_tiplab() + xlim(0, 5)
p2 <- ggtree(clade2, aes(color=group)) + geom_tiplab() +
xlim(0, 8) + scale_color_manual(values=c("black", "red"))
library(ape)
library(tidytree)
library(treeio)
data(chiroptera)
nodes <- grep("Plecotus", chiroptera$tip.label)
chiroptera <- groupOTU(chiroptera, nodes)
clade <- MRCA(chiroptera, nodes)
x <- tree_subset(chiroptera, clade, levels_back = 0)
p3 <- ggtree(chiroptera, aes(colour = group)) +
scale_color_manual(values=c("black", "red")) +
theme(legend.position = "none")
p4 <- ggtree(x) + geom_tiplab() + xlim(0, 5)
plot_list(p1, p2, p3, p4,
ncol=2, tag_levels = 'A')
提取一个枝支(A)。提取一个枝支并追溯它以查看它的近亲(B)。查看一棵非常大的树(C)和它的选定部分(D)。
2.6 操纵树进行可视化
尽管ggtree实现了几种可视化的数据树探索方法,但您可能希望执行一些不直接支持的操作。在本例中,您需要使用用于可视化的节点协调位置来操作树数据。这对于ggtree来说非常简单。用户可以使用内部调用 tidytree::as_tibble() 的 fortify() 方法将树转换为整洁的数据帧,并添加用于绘制树的坐标位置列(例如,x、y、分支和角度)。您也可以通过ggtree(tree)$data访问数据。
下面是一个绘制两棵面对面树的示例,类似于由ape::cophyloplot()函数生成的图(图2.7)。
library(dplyr)
library(ggtree)
set.seed(1024)
x <- rtree(30)
y <- rtree(30)
p1 <- ggtree(x, layout='roundrect') +
geom_hilight(
mapping=aes(subset = node %in% c(38, 48, 58, 36),
node = node,
fill = as.factor(node)
)
) +
labs(fill = "clades for tree in left" )
p2 <- ggtree(y)
d1 <- p1$data
d2 <- p2$data
## 以x轴翻转,并设置偏移量,使第二颗树位于第一棵树的右侧
d2$x <- max(d2$x) - d2$x + max(d1$x) + 1
pp <- p1 + geom_tree(data=d2, layout='ellipse') +
ggnewscale::new_scale_fill() +
geom_hilight(
data = d2,
mapping = aes(
subset = node %in% c(38, 48, 58),
node=node,
fill=as.factor(node))
) +
labs(fill = "clades for tree in right" )
dd <- bind_rows(d1, d2) %>%
filter(!is.na(label))
pp + geom_line(aes(x, y, group=label), data=dd, color='grey') +
geom_tiplab(geom = 'shadowtext', bg.colour = alpha('firebrick', .5)) +
geom_tiplab(data = d2, hjust=1, geom = 'shadowtext',
bg.colour = alpha('firebrick', .5))
图2.7:面对面地绘制两棵系统发育树。使用ggtree()绘制树(左边),然后通过geom_tree()添加树的另一层(右边)。绘制的树的相对位置可以手动调整,并且向每棵树添加图层(例如,提示标签和突出显示分支)是独立的。
在一个图中连接多棵树中对应的分类单元也比较容易; 例如,绘制由流感病毒所有内部基因片段构建的树形图,并在树形上连接等效菌株 (Venkatesh et al., 2018))。图2.8演示了通过组合多个geom_tree()层来绘制多棵树的用法。
z <- rtree(30)
d2 <- fortify(y)
d3 <- fortify(z)
d2$x <- d2$x + max(d1$x) + 1
d3$x <- d3$x + max(d2$x) + 1
dd = bind_rows(d1, d2, d3) %>%
filter(!is.na(label))
p1 + geom_tree(data = d2) + geom_tree(data = d3) + geom_tiplab(data=d3) +
geom_line(aes(x, y, group=label, color=node < 15), data=dd, alpha=.3)
图2.8:并排绘制多个系统发育树。使用ggtree()绘制树,然后使用geom_tree()添加多层树。
2.7 总结
treeio包允许我们将不同的系统发育相关数据导入R,然而,系统发育树的存储方式是为了便于计算处理,需要专门知识来操作和探索树数据。tidytree包为探索树数据提供了一个tidy界面,而ggtree提供了一组实用工具,可以使用图形语法可视化和探索树数据。这种完整的软件包使得普通用户可以很容易地与树状数据进行交互,并允许我们整合来自不同来源的系统发育相关数据(例如,实验结果或分析结果),这为整合和比较研究创造了可能性。此外,这个软件包套件将系统发育分析带入了tidyverse界面,并将我们带到处理系统发育数据的新的层次。