专注系列化、高质量的R语言教程
推文索引 | 联系小编 | 付费合集
patchwork
是ggplot绘图系统的拓展包,主要功能是将多个ggplot
格式的图形组合成一幅大图,即组图。
patchwork
工具包十分好用,它主要利用几个类似四则运算符号的操作符进行组图,只要掌握每个操作符的功能特点及少量函数的用法,就可以很灵活地进行组图。
本篇目录如下:
0 示例图形
1 竖杠`|`和斜杠`/`
1.1 单独运算
1.2 混合运算
2 加号`+`
2.1 单独运算
2.2 plot_layout函数(上)
3.3 混合运算
3 减号`-`
3.1 单独运算
3.2 混合运算
0 示例图形
首先,参考官方文档[1],生成如下4个ggplot对象:
library(ggplot2)
p1 <- ggplot(mtcars) +
geom_point(aes(mpg, disp*100)) +
ggtitle('Plot 1')
p2 <- ggplot(mtcars) +
geom_point(aes(mpg, wt)) +
ggtitle('Plot 2')
p3 <- ggplot(mtcars) +
geom_point(aes(hp, wt, colour = mpg)) +
ggtitle('Plot 3')
p4 <- ggplot(mtcars) +
geom_bar(aes(gear)) +
facet_wrap(~cyl) +
ggtitle('Plot 4')
1 竖杠|
和斜杠/
patchwork
工具包最基础的操作符应当是加号+
,这也是继承ggplot2
工具包的符号,不过竖杠|
和斜杠/
的功能相对单纯,因此首先加以介绍。
在R语言的基础语法中,竖杠|
表示逻辑“或”,斜杠/
表示“除法”,但在这里它们被赋予了另外的功能:竖杠|
表示横向组图,斜杠/
表示纵向组图。
1.1 单独运算
分别使用|
和/
进行组图:
library(patchwork)
p1 | p2 | p3

p1 / p2 / p3

通过观察组图结果,可以发现一个特点:这两个操作符会为每个图形的plot region平均分配空间。
在推文graphics | 基础绘图系统(二)—— 绘图参数及par函数中,学堂君介绍了基础绘图系统的图形共存在4个区域,这里再展示一下:

但在默认情况下,device region、display region的边界会与figure region重叠,也就是外侧三个区域实际上是重合的,因此图形区域主要存在plot region和figure region的区别。
明白几个区域的概念,现在再来分析组图结果:
p1
的纵坐标刻度标签较其他图更长,但它的plot region仍和其他两幅图仍然一致;因为纵坐标刻度标签位于figure region内而不位于plot region,因此它的figure region较p2
更宽;同样,
p3
在figure region中包含一个图例,这也使得它的figure region较p2
更宽。
综上,可以得出结论:|
和/
操作符会平均分配各子图的plot region,而figure region内的要素则会额外分配空间。
此外,这两个操作符在组图时还严格贯彻“对齐”的审美观,尤以/
更加明显,可以看到:
在横向组图中,子图的plot region上、下边框是对齐的;在纵向组图中,尽管纵坐标刻度标签不一致以及部分子图存在图例,子图的plot region左、右边框也是对齐的;
在纵向组图中,尽管纵坐标刻度标签的宽度不一致,但纵坐标变量名标签也严格对齐,刻度标签较窄的子图在与变量名标签之间还留出一部分空间。
那么如果参与组图的子图本身就包含子图,它们会如何分配空间呢?看如下例子:
p1 | p2 | p4

p1 / p2 / p4

从组图结果可以看出,子图的子图是作为一个整体来参与平均分配plot region的。这就涉及到嵌套水平(nesting level)的概念了。以上例来说,p1
、p2
是与p4
处于同一嵌套水平,而不是与它的子图处于同一嵌套水平。
1.2 混合运算
|
和/
可以混合使用以实现更复杂的组图,那么它们运算的优先级是怎样的呢?
先看如下三个例子:
p1 | p2 / p3

p1 / p2 | p3

p1 / p2 | p3 / p4

从组图结果可以明显看出,/
的优先级高于|
。
此外,从嵌套水平的角度看,当只使用上述操作符的其中一个时,所有参与组图的子图都位于同一个嵌套水平;而当混合使用这两个操作符时,优先级高的操作符会先产生一个嵌套水平,其结果整体再与其他操作符产生一个更高的嵌套水平。
2 加号+
2.1 单独运算
从排列方向上看,加号+
的功能不是那么纯粹。在默认情况下,它会根据参与组图的图形数量决定布局:
p1 + p2

p1 + p2 + p3

p1 + p2 + p3 + p4

2.2 plot_layout函数(上)
plot_layout()
函数可以对组图的布局做进一步的调整。
调整行、列数:
p1 + p2 + p3 +
plot_layout(ncol = 2)
p1 + p2 + p3 +
plot_layout(nrow = 2)

调整排列方向的优先顺序:
p1 + p2 + p3 +
plot_layout(ncol = 2, byrow = F)

调整各列子图的plot region的宽度比例:
p1 + p2 + p3 +
plot_layout(ncol = 2, widths = c(1.5,1))

调整各行子图的plot region的高度比例:
p1 + p2 + p3 +
plot_layout(ncol = 2, heights = c(1, 1.5))

plot_layout()
函数的其他功能会在后文进一步介绍。
3.3 混合运算
加号+
与竖杠|
和斜杠/
混合运算时,优先级是怎样的呢?
先看+
与|
的优先级比较:
p1 + p2 | p3

p1 | p2 + p3

显然,+
的优先级高于|
。
再看+
与/
的优先级比较:
p1 + p2 / p3

显然,+
的优先级低于/
。
综上,三个操作符的优先级顺序为/
> +
> |
。
3 减号-
3.1 单独运算
按照工具包作者的说法,与其将-
看作是减号,还不如看作是连字符。从排列方向上看,它也是横向进行组图的,但与|
和+
存在区别。
区别主要体现在嵌套水平的产生上。其实不管是|
、/
,还是+
,单独使用它们中的一个,都会将所有子图置于同一嵌套水平,而-
每使用一次都会产生一个嵌套水平。
看如下两个例子:
p1 - p2

p1 - p2 - p3

可以看出,在连续使用两次-
时,首先会将p1
和p2
在同一嵌套水平上横向组图,然后再将组图结果作为整体与p3
在同一嵌套水平上进行横向组图。当连续使用-
时,从左往右各子图的宽度比就会是:
3.2 混合运算
在混合运算时,-
的优先级和+
是一致的。从左往右,谁先出现就先使用谁。
p1 + p2 - p3

先计算
p1 + p2
,再作为整体与p3
横向组合。
p1 - p2 + p3

这里显示
+
的功能很特殊。尽管先计算了p1 - p2
,但p3
仍然与它们处于同一嵌套水平。
-
的优先级低于/
:
p1 - p2 / p3

-
的优先级高于|
:
p1 | p2 - p3

p1 - p2 | p3

注意与
p1 - p2 + p3
的结果作比较。
综上,三个操作符的优先级顺序为/
> +
= -
> |
。
未完待续。
参考资料
[1]
patchwork: Getting Started: https://mirrors.tuna.tsinghua.edu.cn/CRAN/web/packages/patchwork/vignettes/patchwork.html