打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
绘图专题 | ggplot2拼图神器patchwork

https://github.com/thomasp85/patchwork

The goal of patchwork is to make it ridiculously simple to combine separate ggplots into the same graphic. As such it tries to solve the same problem as gridExtra::grid.arrange() and cowplot::plot_grid but using an API that incites exploration and iteration.

安装加载:

  1. p_load_gh('thomasp85/patchwork')

1、合并对象

两个ggplot2对象,通过'+'可以直接合并在一张图中 (默认左右等面积排布):

  1. p_load(ggplot)

  2. p1 = ggplot(mtcars) + geom_point(aes(mpg, disp))

  3. p2 = ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))

  4. p1 + p2

如果未正常加载patchwork包,则会报错:

错误: Don't know how to add p2 to a plot

2、 plot_layout() 自定义排布:

You can use this call to determine the dimensions you want the plots to be arranged in, and the size of the plots.

  1. p1 + p2 + plot_layout(ncol = 1)    # 按1列排布

  2. p1 + p2 + plot_layout(ncol = 1, heights = c(3, 1))    # 两图高度比3:1

3、 plot_spacer() 增加图形间距:

  1. p1 + plot_spacer() + p2        # 默认一个对象宽度的空白间距

  2. p1 + plot_spacer() + p2 + plot_layout(nrow = 1, width = c(5, 1, 5))        # 自定义间距

通过上示用法,已经可以很方便的完成很多形式的排布:

  1. mtcars$cyl = as.factor(mtcars$cyl)

  2. p1 = p1 + labs(tag = 'A')    # 给每个图添加标签

  3. p2 = p2 + labs(tag = 'B')

  4. p3 = ggplot(mtcars, aes(wt, mpg, color = cyl, shape = cyl)) + geom_point() + geom_smooth(method = lm, se = F, fullrange = T) + theme_classic() + scale_color_brewer(palette = 'Dark2') + theme(legend.position = 'top') + labs(tag = 'C')


  5. # 两种不同的显示效果

  6. p1 + p2 + p3 + plot_layout(nrow = 2, height = c(2, 1))    # p3在左侧

  7. p1 + p2 + plot_spacer() + p3 + plot_layout(ncol = 2, height = c(2, 1))    # p3在右侧

那么,如何调整为如下的排布呢?

对此,patchwork包中也提供了极为简便的操作符!

4、操作符:

https://rdrr.io/github/thomasp85/patchwork/man/plot_arithmetic.html

通过前文,我们知道 + 合并ggplot2对象,结合 plot_layout() 可以灵活的对图形进行排布。

patchwork包中其实有更便捷的方法, | 操作符用于设置水平排布, / 操作符垂直排布。所以对于上示问题的解决办法,至少有如下三种:

  1. # 方法1

  2. (p1 + p2)/p3 + plot_layout(height = c(2, 1))

  3. # 方法2

  4. (p1 | p2)/p3 + plot_layout(height = c(2, 1))

  5. # 方法3

  6. (p1 + p2)-p3 + plot_layout(ncol = 1, height = c(2, 1))    # 此处'-'左边的'()'可省略

几点说明:

1、'/'其实看起来与算术表达式略有相似,'/'右侧的在分母位置,即下方

2、 '()' 或者 '{}' 用于表示嵌套关系

You can make nested plots layout by wrapping part of the plots in parentheses - in these cases the layout is scoped to the different nesting levels.

3、方法3中,操作符 -不能当做减法)是将其左右两侧的对象置于同一嵌套水平(平级),即 p1+p2p3 应当做两个对象去处理,故需要明确是按行还是按列排布,如按列排布,则要设置 ncol=1

否则会报出 警告,并默认按行排布!

Warning message:In xList[i] <- valuelist="" :="">

那么,方法3中能否将 - 替换成 + 呢?

- will behave like + but put the left and right side in the same nesting level (as opposed to putting the right side into the left sides nesting level).

  1. (p1 + p2)+p3 + plot_layout(ncol = 1, height = c(2, 1))

结果如下:

可见,其结果等同于去除括号后的结果,且由于参数 height 只设置了两个值,所以同时会报出警告:

Warning message:In xList[i] <- valuelist="" :="">

更多复杂的排布:

  1. p4 = ggplot(diamonds, aes(x = price, colour = cut, fill = cut)) + geom_density(alpha = 0.5) + guides(alpha = FALSE) + theme_bw() + labs(tag = 'D')


  2. ((p1 + p2/p3) - p4) + plot_layout(width = c(2, 1))

  1. (((p1 + p2)/p3) | p4) + plot_layout(width = c(2, 1))  # 此处'|'可替换为'-'

此时,我们看到,上示图形中虽然已经完成了排布,但是其风格完全不同:有灰色网格背景、白色网格背景和纯白色背景,也有四方框、半边框和无边框...这归因于单独对于某些图形的调整,那么如果是想统一呢?

很简单,对每个图形都做相同的设置,例如都用纯白背景:

  1. p + theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())

这里,p要分别替换为p1、p2、p3、p4,代码里也就会有4段高度一致的脚本...

所幸,patchwork包中也替我们考虑到了这个问题:

In order to reduce code repetition patchwork provides two operators for adding ggplot elements (geoms, themes, facets, etc.) to multiple/all plots in an assemble. * will add the element to all plots in the current nesting level, while & will recurse into nested cells.

  1. ((((p1 + p2)/p3) | p4) + plot_layout(width = c(2, 1))) & (theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())

如图,全部统一为纯白背景,但是有个问题,C图的图例放在了图的右侧(之前都是在上部),这是因为 theme_bw() 覆盖了之前的 theme() 设置。提供一种解决方法:

  1. ((((p1 + p2)/p3) | p4) + plot_layout(width = c(2, 1))) & (theme(panel.background = element_rect(fill = 'white', colour = 'black', size = 1), panel.grid.major = element_blank(), panel.grid.minor = element_blank()))

最终显示效果如下:

所以, & 可以将设置递归地应用到所有的嵌套水平,即拼图中所有的子图上。类似的还有个 * 操作符,只能将设置应用在当前嵌套水平上!

* will only affect the plots on the current nesting level, whereas & will recurse into nested levels

  1. #(p1 + p2 + p4) * theme_bw()

  2. T1 = wrap_elements((p1 + p2 + p4) * theme_bw()) + ggtitle('p1 + p2 + p4') + theme(plot.title = element_text(size = 15, hjust = 0.5, color = 'red'))

  3. #(p1 + p2 - p4) * theme_bw()

  4. T2 = wrap_elements((p1 + p2 - p4) * theme_bw()) + ggtitle('p1 + p2 - p4') + theme(plot.title = element_text(size = 15, hjust = 0.5, color = 'red'))

  5. # 拼图组合

  6. T1 - T2 + plot_layout(ncol = 1)

如图所示,对于 p1+p2+p4p1p2p4三者属于同一嵌套水平,所以 * 操作符将 theme_bw() 应用在了每个图中。而对于 p1+p2-p4p1+p2p4 则属两个平级的嵌套层,所以 p1+p2 的图面积与 p4 的一样,而 * 只将 theme_bw() 应用在了当前嵌套水平的 p4 上,p1p2算是子一级水平!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
用R来拼图和排版,告别AI和PS(三):添加注释信息
如何用patchwork拼R语言大部分类型出图和图片
ggplot2分面图形大改造
R语言可视化——ggplot的theme订制
利用ggplot2画双坐标轴曲线
ggplot文字标签设置(geom_text_repel函数)的一个小例子
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服