乐于分享
好东西不私藏

R包神器 | ape (九) 基本和高级功能 – 几何及复合图形,自建函数

R包神器 | ape (九) 基本和高级功能 – 几何及复合图形,自建函数

Emmanuel Paradis January 3, 2022
x:/Program Files/R/R-x.x.x/library/ape/doc/DrawingPhylogenies

6 几何及复合图形

6.1 单绘图区

现在,我们可以在绘制树图时看到图形的一些几何细节。我们首先设置外边距 (Outer margins图形参数oma),默认为0,然后通过调用box() 3次并使用适当的选项来显示内、外边距:

# oma: 预设外边距的宽度par(oma = rep(24))# [1] 2 2 2 2plot(mytr)# 从内到外4个区域:"plot"(默认), "figure", "inner" and "outer"box(lty = 3) # lty - 设置线条样式(Line type),可取0123456,分别表示:不划线;实线;虚线;点线;点划线;长划线;点长划线box("figure", col = "blue")# mtext: 将文本写至图形的边距(Margins)# 顺序(顺时针):下、左、上、右# 预设的外边距宽度不足时,影响此文本的展示for (i in 1:4)    mtext("Outer margin", i, 0.5, outer = TRUE, font = 2, col = "blue")box("outer") # 在整个绘图区的最外层画框for (i in 1:4)    mtext("Inner margin", i, 0.5, outer = FALSE, font = 2, col = "brown")

1. par()的oma选项: 预设外边距的宽度(默认无外边距);2. 从内到外4个区域:”plot”(默认), “figure”, “inner” and “outer”;3. mtext(): 将文本写至图形的边距(Margins),顺序(顺时针):下、左、上、右,预设的外边距宽度不足时,影响此文本的展示。

当然,也可以使用par(mar = ….)更改边距。请注意,在运行plot(mytr)之前,进行plot(mytr, no.margin = TRUE)与调用parpar(mar = rep(0, 4))是相同的。

plot(mytr, no.margin = TRUE)box("plot", lty = 3)
如何调整”Pan”与其下方虚线之间的距离?(都属于”plot”区)

6.2 多重布局 (Multiple Layout)

通过先使用layout函数拆分图形设备,可在同一图形上绘制多棵树。在这种情况下,每个图形都有自己的1组内边距 (可与下个示例中的不同),但外边距是图形的”全局“(Global)边距:

matrix(1:4, 2, 2)#      [,1] [,2]# [1,]    1    3# [2,]    2    4layout(matrix(1:4, 2, 2))par(oma = rep(2, 4))for (i in 1:4) {    par(mar = rep(i, 4))    plot(mytr)    box(lty = 3)    box("figure", col = "blue")}for (i in 1:4)    mtext("Outer margin", i, 0.5, outer = TRUE, font = 2, col = "blue")box("outer")
每个图形中的”Pan”,与其下方虚线之间的距离均未改变,如何改变?

分割图形设备的另1种方法是调用par(mfcol = c(2, 2))。但是,建议使用更灵活、强大的layout函数:

· layout具有widthheight选项,提供图形的行和列的(相对)大小。

· 作为layout主要参数的矩阵是图形布局的符号表示:单个图形可跨越矩阵的多个单元;例如,layout(matrix(c(1, 2, 1, 3), 2, 2))将在设备上指定3个绘图,第1个绘图跨越第一行,第2行拆分为2个绘图:

layout(matrix(c(1213), 22))for (i in 1:3) plot(rtree(5))

7 构建自己的代码和函数

在本节中,我们将研究利用ape的图形功能来构建代码或函数的2种方法。

7.1 获取已录入的参数

每次调用plot.phylo时,一些数据和参数都保存在特定的R环境(R的一组对象所占用的计算机内存的一部分)中,然后nodelabels等函数使用。此环境称为.PlotPhyloEnv,可供所有用户访问,因此可通过以下方式获取列表(List) last_plot.phylo

(pp <- get("last_plot.phylo", envir = .PlotPhyloEnv))$type[1] "phylogram"$use.edge.length[1] TRUE$node.pos[1] 1$node.depth[1] 1$show.tip.label[1] TRUE$show.node.label[1] FALSE$font[1] 3$cex[1] 0.83$adj[1] 0$srt[1] 0$no.margin[1] FALSE$label.offset[1] 0$x.lim[1] 0.000000 2.565094$y.lim[1] 1 5$direction[1] "rightwards"$tip.color[1] "black"$Ntip[1] 5$Nnode[1] 4$root.timeNULL$align.tip.label[1] FALSE$edge     [,1] [,2][1,]    6    1[2,]    6    7[3,]    7    2[4,]    7    8[5,]    8    9[6,]    9    3[7,]    9    4[8,]    8    5$xx[1] 0.3416120 0.9779764 1.9980659 2.3773992 1.5240125 0.0000000 0.8540463 1.2019900 1.5262024$yy[1] 1.0000 2.0000 3.0000 4.0000 5.0000 2.0625 3.1250 4.2500 3.5000

大多数记录的参数对应于plot.phylo的参数。该列表中存储的最后2个向量xxyy是树的尖端和节点(Tip+Node 逆时针顺序?)的坐标

7.2 布局覆盖 (Overlaying Layouts)

graphics包无法轻松地与多重布局(Multiple layout)上的图形交互。例如,在调用layout并完成第2个绘图之后,就无法向第1个图形添加元素 (点、箭头等),这限制了以图形方式连接这些绘图的可能性。但是,命令par(new = TRUE)提供了1种方法,如这里所述。

其思想是跟踪整个图形设备上节点 (及其它图形元素 (如果需要)) 的坐标。但是,由于图形/plots很可能使用不同的坐标系 (例如,由于分枝长度的比例不同),因此必须将这些坐标转换为图形/graphical设备上的物理单位 (通常为英寸)。由于par()在许多参数中返回绘图区域/Plotting region、边距/Margins设备物理尺寸(英寸),并分别使用参数“pin”、“mai”和“din” (figure大小也有“fin”,其不包括外边距,如果这些外部边距不为0,则需要使用)。我们将在这里使用的另1个图形参数由par(“usr”)给出,给出绘图区域坐标的极值

步骤如下:

1. 重新缩放(Rescale)每个树形图的节点坐标,使其介于0和1之间。

2. 通过将这些坐标与“fin”中的相关值相乘,并添加相关边距的大小(英寸),以英寸为单位转换这些坐标。这将给出每个图形/Figure(即,包括边距)以英寸为单位的坐标

3. 使用layout最终定义的几何图形添加到上一步输出的坐标中。

完成这3个步骤后,我们将获得整个设备上节点的坐标,单位为英寸,与每个绘图/Plot中使用的各种标尺(Scales)无关。然后,对par(new = TRUE)的调用使得没有绘制任何内容,并且R不会删除设备上已经绘制的内容。然后,我们调用plot(NA),选项为type = “n”ann = FALSEaxes = FALSE,从而生成一个“裸/Bare”图。这里的重要选项是[x|y]lim = 0:1,用于设置每个轴上的比例尺(Scale),以及[x|y]axs = “i”,用于设置轴(Axes)以精确扩展到数据的范围或指定的限制(Limits) (默认情况下,xaxsyaxs等于“r”,这将在数据范围或限制的两边各添加4%)

然而,在类似于本(代码.R)文档的小实例(Vignette)中,每次调用plot都会打开一个新设备(Device),因此无法交互地执行上述步骤。相反,下一组命令包含一些注释并打印一些中间结果。在此示例中,将绘制两棵随机树,并用箭头将第1棵树的第1个尖端连接到第2棵树的根

matrix(1:22)#      [,1]# [1,]    1# [2,]    2## split the device into 2:layout(matrix(1:22))## plot the 1st treeplot(rtree(4))## get the parameters of this first plot:pp <- get("last_plot.phylo", envir = .PlotPhyloEnv)## keep the coordinates of the first tip:x <- pp$xx[1]y <- pp$yy[1]## extremes of the coordinates on both axes:(pu <- par("usr"))# [1] -0.04985097  1.29612512  0.88000000  4.12000000## fraction of the plot region:(x - pu[1]) / (pu[2] - pu[1])# [1] 0.78789(y - pu[3]) / (pu[4] - pu[3])# [1] 0.03703704## get the dimensions of plotting region and margins in inches:pi <- par("pin")mi <- par("mai")## convert the coordinates into inches:xi1 <- (x - pu[1]) / (pu[2] - pu[1]) * pi[1] + mi[2]yi1 <- (y - pu[3]) / (pu[4] - pu[3]) * pi[2] + mi[1]## xi1 and yi1 are the final coordinates of this tip in inches## plot the 2nd tree:plot(rtree(4))## same as above:pp <- get("last_plot.phylo", envir = .PlotPhyloEnv)## ... except we take the coordinates of the root:x <- pp$xx[5]y <- pp$yy[5]pu <- par("usr")pi <- par("pin")mi <- par("mai")xi2 <- (x - pu[1]) / (pu[2] - pu[1]) * pi[1] + mi[2]yi2 <- (y - pu[3]) / (pu[4] - pu[3]) * pi[2] + mi[1]## xi2 and yi2 are the final coordinates of this root in inches## we add the height of this second plot to the 'y' coordinate## of the first tip of the first tree which is above the second## one according to layout()yi1 <- yi1 + par("fin")[2]## => this operation depends on the specific layout of plots## get the dimension of the device in inches:di <- par("din")## reset the layoutlayout(1)## set new = TRUE and the margins to zero:par(new = TRUE, mai = rep(04))## set the scales to be [0,1] on both axes (in user coordinates):plot(NA, type = "n", ann = FALSE, axes = FALSE, xlim = 0:1,     ylim = 0:1, xaxs = "i", yaxs = "i")## graphical elements can now be added:fancyarrows(xi1/di[1], yi1/di[2], xi2/di[1], yi2/di[2], 1,            lwd = 10, col = rgb(1.50.5), type = "h")

此代码必须适应于精确的布局,以便在x-y-方向上适当移动坐标。下一个bloc定义了1个函数,该函数使用上述代码绘制2个树,并从第1棵树的参数from指定的尖端,向第2棵树的根添加箭头:

foo <- function(phy1, phy2, from){    layout(matrix(1:22))    plot(phy1, font = 1)    pp <- get("last_plot.phylo", envir = .PlotPhyloEnv)    from <- which(phy1$tip.label == from)    x <- pp$xx[from]    y <- pp$yy[from]    ## fraction of the plot region:    pu <- par("usr")    ## convert into inches:    pi <- par("pin")    mi <- par("mai")    xi1 <- (x - pu[1]) / (pu[2] - pu[1]) * pi[1] + mi[2]    yi1 <- (y - pu[3]) / (pu[4] - pu[3]) * pi[2] + mi[1]    plot(phy2)    pp <- get("last_plot.phylo", envir = .PlotPhyloEnv)    to <- Ntip(phy2) + 1    x <- pp$xx[to]    y <- pp$yy[to]    ## same as above:    pu <- par("usr")    pi <- par("pin")    mi <- par("mai")    xi2 <- (x - pu[1]) / (pu[2] - pu[1]) * pi[1] + mi[2]    yi2 <- (y - pu[3]) / (pu[4] - pu[3]) * pi[2] + mi[1]    yi1 <- yi1 + par("fin")[2]    di <- par("din")    layout(1)    par(new = TRUE, mai = rep(04))    plot(NA, type = "n", ann = FALSE, axes = FALSE, xlim = 0:1,         ylim = 0:1, xaxs = "i", yaxs = "i")    fancyarrows(xi1/di[1], yi1/di[2], xi2/di[1], yi2/di[2], 1,                lwd = 10, col = rgb(1, .50, .5), type = "h")}

我们用哺乳动物目进化树尝试此功能,我们希望将其与我们的小树mytr连接:

trb <- read.tree(text = "((Primates,Carnivora),Monotremata);")par(xpd = TRUE)foo(trb, mytr, "Carnivora")# foo(trb, mytr, "Primates")

请注意,第1棵树没有分枝长度,因此两棵树的比例尺(Scales)明显不同。

这些功能的另1个用途是绘制着色矩形(Coloured rectangles)背景来划分分枝。同样,我们可以使用par(new = TRUE)plot.phyloplot=FALSE选项,该选项打开并设置图形设备,坐标取自第2.2节详述的树,但未绘制任何图形。然后,用户可以调用任何低级绘图命令,然后在par(new = TRUE)之后使用plot()。例如,如果我们想画1个矩形来显示由人类和黑猩猩组成的分枝

plot(mytr, plot = FALSE)# 继承自 已经绘制的图形(即使不可见) 的内部元素的性质:pp <- get("last_plot.phylo", envir = .PlotPhyloEnv)# 选取tip+node的坐标(逆时针),定义矩形的4个边(左、下、右、上):rect(pp$xx[5] - 0.1, pp$yy[1] - 0.1, pp$xx[1] + 2, pp$yy[2] + 0.1,     col = "yellow", border = NA)par(new = TRUE)plot(mytr)
由于不清楚如何调整”Pan”与其下方虚线(“plot”区的边缘)之间的距离,如果对黄色矩形加黑框,框的下面的线无法显示

有几种方法可以找到矩形的限制/Limits:根据经验尝试不同的值;在具有进化树的第1个草图上使用locator();或者使用类似于上一个示例的计算。?phydataplot中的例子给出了使用par(new = TRUE)的其它示例。

References

[1] L. Czech, J. Huerta-Cepas, and A. Stamatakis. A critical review on the use of support values in tree viewers and bioinformatics toolkits. Molecular Biology and Evolution, 34:1535{1542, 2017. 
[2] J. Felsenstein. Inferring Phylogenies. Sinauer Associates, Sunderland, MA, 2004. 

[3] P. Murrell. R Graphics. Chapman & Hall/CRC, Boca Raton, FL, 2006.

通过过去几篇文章对ape这个进化树领域的经典R包的了解,系统地熟悉了相关数据分析与绘图的概念、术语等,如:Tip、Node、Edge,phylogram、cladogram,coalescent … … 推测这些概念在不同的工具中大体通用,因此准确地把握这些概念非常重要。

后续将使用ape进行贝叶斯天际线图等图形的制作,继续深入学习进化树分析与可视化相关的原理和技术。

扫码、联系客服老师报名。课程介绍:
本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » R包神器 | ape (九) 基本和高级功能 – 几何及复合图形,自建函数

猜你喜欢

  • 暂无文章