前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用patchwork进行拼图的一些细节

使用patchwork进行拼图的一些细节

作者头像
医学和生信笔记
发布2022-11-15 10:35:01
4.2K0
发布2022-11-15 10:35:01
举报
文章被收录于专栏:医学和生信笔记

说到拼图,那必须得好好学习patchwork包,这个包是Thomas大佬的作品,一经推出就火了,迅速取代了R中其他的拼图包。

大佬很强,除了这个包,还有很多好用的包都是他开发的,比如gganimate/ggraph/tidygraph/ggforce等,是不是也有一些你常用的包呢。

如果你仔细扒一扒,就会发现,我们常用的包,都是出自那几个人之手。。。

本期目录:

  • 安装
  • 拼图!
    • 简单拼图
    • 嵌套拼图
    • 和非`ggplot2`对象拼图
    • 堆叠和成组
    • 快速拼很多图
  • 修改子图形
    • 修改全部子图形
  • 控制整体布局
    • 增加空白占位图形
  • 控制行列数
  • 行列的精细控制
  • Fixed aspect plots
  • 插入图形
  • 控制图例
  • 标题、副标题和说明文字
  • 给子图添加序号
  • 修改整个图形的外观

安装

代码语言:javascript
复制
# 2选1
install.packages('patchwork')

# install.packages("devtools")
devtools::install_github("thomasp85/patchwork")

拼图!

代码语言:javascript
复制
library(patchwork)

首先创建一些基本图形用于演示。

代码语言:javascript
复制
library(ggplot2)
p1 <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 1')

p2 <- ggplot(mtcars) + 
  geom_boxplot(aes(gear, disp, group = gear)) + 
  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')

简单拼图

使用起来真的是简单,直接用+连起来就行了。

代码语言:javascript
复制
p1 + p2

plot of chunk unnamed-chunk-4

嵌套拼图

默认会在图形左边添加图形,所以如果你先把2个图拼一起,在和第3个图拼,就会像下面这样:

代码语言:javascript
复制
patch <- p1 + p2
p3 + patch

plot of chunk unnamed-chunk-5

但是呢,也是可以调节的,简单换个顺序就不一样了:

代码语言:javascript
复制
patch + p3

plot of chunk unnamed-chunk-6

这种情况下还可以用-,又是不一样的效果,处处都是细节!

代码语言:javascript
复制
patch - p3

plot of chunk unnamed-chunk-7

和非ggplot2对象拼图

和表格拼:

代码语言:javascript
复制
p1 + gridExtra::tableGrob(mtcars[1:10, c('mpg', 'disp')])

plot of chunk unnamed-chunk-8

base plot拼图:

代码语言:javascript
复制
p1 + ~plot(mtcars$mpg, mtcars$disp, main = 'Plot 2')

plot of chunk unnamed-chunk-9

但是有个问题,拼出来对不齐,这时候就需要其他函数辅助对齐了:

代码语言:javascript
复制
old_par <- par(mar = c(0, 2, 0, 0), bg = NA)
p1 + wrap_elements(panel = ~plot(mtcars$mpg, mtcars$disp), clip = FALSE)

plot of chunk unnamed-chunk-10

代码语言:javascript
复制
par(old_par)

文字大小还是不太一样,还可以继续调整:

代码语言:javascript
复制
old_par <- par(mar = c(0, 0, 0, 0), mgp = c(1, 0.25, 0), 
               bg = NA, cex.axis = 0.75, las = 1, tcl = -0.25)
p1 + 
  wrap_elements(panel = ~plot(mtcars$mpg, mtcars$disp), clip = FALSE) + 
  ggtitle('Plot 2') + 
  theme(plot.margin = margin(5.5, 5.5, 5.5, 35))

plot of chunk unnamed-chunk-11

代码语言:javascript
复制
par(old_par)

和文本内容也可以拼:

代码语言:javascript
复制
p1 + grid::textGrob('Some really important text')

plot of chunk unnamed-chunk-12

但是呢你要注意,如果你写反了,就拼不出来了:

代码语言:javascript
复制
grid::textGrob('Text on left side') + p1
## NULL

如果你非要反着写,那要借助wrap_elements()才能显示出来:

代码语言:javascript
复制
wrap_elements(grid::textGrob('Text on left side')) + p1

plot of chunk unnamed-chunk-14

堆叠和成组

  • + 简单拼图
  • | 左右拼
  • / 上下拼
代码语言:javascript
复制
p1 / p2

plot of chunk unnamed-chunk-15

代码语言:javascript
复制
p1 | p2

plot of chunk unnamed-chunk-16

代码语言:javascript
复制
p1 / (p2 | p3)

plot of chunk unnamed-chunk-17

快速拼很多图

如果你有多个图形组成的列表,再使用+可能就不太方便了,可以直接使用warap_plots()函数:

代码语言:javascript
复制
wrap_plots(p1,p2,p3,p4)

plot of chunk unnamed-chunk-18

修改子图形

默认操作都会传给最后一个图形。

代码语言:javascript
复制
p1 + p2 + geom_jitter(aes(gear, disp))

plot of chunk unnamed-chunk-19

可以通过修改子集的方式达到精准控制某个图形细节:

代码语言:javascript
复制
patchwork <- p1 + p2
patchwork[[1]] <- patchwork[[1]] + theme_minimal() # 修改第1个
patchwork

plot of chunk unnamed-chunk-20

修改全部子图形

  • &:将主题修改应用到所有子图形
  • *:将主题修改应用到当前嵌套水平的子图形
代码语言:javascript
复制
patchwork <- p3 / (p1 | p2)
patchwork & theme_minimal()

plot of chunk unnamed-chunk-21

代码语言:javascript
复制
patchwork * theme_minimal() 

plot of chunk unnamed-chunk-22

控制整体布局

还是先建立一些基本图形用于演示。

代码语言:javascript
复制
library(ggplot2)
p1 <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 1')

p2 <- ggplot(mtcars) + 
  geom_boxplot(aes(gear, disp, group = gear)) + 
  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')

增加空白占位图形

顾名思义,增加几个空白图形,纯属占位子用的。

代码语言:javascript
复制
p1 + plot_spacer() + p2 + plot_spacer() + p3 + plot_spacer()

plot of chunk unnamed-chunk-24

控制行列数

使用plot_layout()控制行列数:

代码语言:javascript
复制
p1 + p2 + p3 + p4 + 
  plot_layout(ncol = 3)

plot of chunk unnamed-chunk-25

还可以控制不同行列的高度和宽度:

代码语言:javascript
复制
p1 + p2 + p3 + p4 + 
  plot_layout(widths = c(2, 1),
              heights = c(3, 2)
              )

plot of chunk unnamed-chunk-26

行列的精细控制

使用自定义布局达到对行列数的精细控制。

代码语言:javascript
复制
# 3行6列,4个图形,#表示占位符
layout <- "
##BBBB
AACCDD
##CCDD
"
p1 + p2 + p3 + p4 + 
  plot_layout(design = layout)

plot of chunk unnamed-chunk-27

合理使用布局,可以达到叠加的效果:

代码语言:javascript
复制
layout <- c(
  area(t = 2, l = 1, b = 5, r = 4), # 上左下右
  area(t = 1, l = 3, b = 3, r = 5)
)
p1 + p2 + 
  plot_layout(design = layout)

plot of chunk unnamed-chunk-28

wrap_plots()也是可以用布局的:

代码语言:javascript
复制
layout <- '
A#B
#C#
D#E
'
wrap_plots(D = p1, C = p2, B = p3, design = layout) # 指定字母代表的图形

plot of chunk unnamed-chunk-29

Fixed aspect plots

有些图形是固定好坐标轴比例的,这时候的拼图操作是不会影响原本比例的:

代码语言:javascript
复制
p_fixed <- ggplot(mtcars) + 
  geom_point(aes(hp, disp)) + 
  ggtitle('Plot F') + 
  coord_fixed()
p_fixed + p1 + p2 + p3

plot of chunk unnamed-chunk-30

代码语言:javascript
复制
p_fixed + p1 + p2 + p3 + plot_layout(widths = 1) # 比例不变

plot of chunk unnamed-chunk-31

插入图形

把一张图插在另一张图上,使用insert_element()函数。

代码语言:javascript
复制
p1 + inset_element(p2, left = 0.6, bottom = 0.6, right = 1, top = 1)

plot of chunk unnamed-chunk-32

代码语言:javascript
复制
p1 + inset_element(p2, left = 0, bottom = 0.6, right = 0.4, top = 1, align_to = 'full')

plot of chunk unnamed-chunk-33

边距都是可以设置的:

代码语言:javascript
复制
p1 + inset_element(
  p2, 
  left = 0.5, 
  bottom = 0.5, 
  right = unit(1, 'npc') - unit(1, 'cm'), 
  top = unit(1, 'npc') - unit(1, 'cm')
)

plot of chunk unnamed-chunk-34

控制图例

对于多张图图例都一样时,可以直接用一个图例:

代码语言:javascript
复制
p1 + p2 + p3 + p4 +
  plot_layout(guides = 'collect')

plot of chunk unnamed-chunk-35

合理使用括号改变组图顺序,达到把单个图例放到整张图右边的效果:

代码语言:javascript
复制
# 默认就是auto
((p2 / p3 + plot_layout(guides = 'auto')) | p1) + plot_layout(guides = 'collect')

plot of chunk unnamed-chunk-36

代码语言:javascript
复制
# 改成keep
((p2 / p3 + plot_layout(guides = 'keep')) | p1) + plot_layout(guides = 'collect')

plot of chunk unnamed-chunk-37

可以自动移除重复图例,比如正常的拼图会像下面这样,mpg这个图例出现了2次:

代码语言:javascript
复制
p1a <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp, colour = mpg, size = wt)) + 
  ggtitle('Plot 1a')

p1a | (p2 / p3)

plot of chunk unnamed-chunk-38

使用guides = 'collect'后,重复图例被去掉了:

代码语言:javascript
复制
(p1a | (p2 / p3)) + plot_layout(guides = 'collect')

plot of chunk unnamed-chunk-39

还可以把图例单独放到一个子图中:

代码语言:javascript
复制
p1 + p2 + p3 + guide_area() + 
  plot_layout(guides = 'collect')

plot of chunk unnamed-chunk-40

标题、副标题和说明文字

默认图形用于演示。

代码语言:javascript
复制
library(ggplot2)
p1 <- ggplot(mtcars) + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 1')

p2 <- ggplot(mtcars) + 
  geom_boxplot(aes(gear, disp, group = gear)) + 
  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')

使用plot_annotation()给整个图形添加标题、副标题和说明文字:

代码语言:javascript
复制
patchwork <- (p1 + p2) / p3
patchwork + plot_annotation(
  title = 'The surprising truth about mtcars',
  subtitle = 'These 3 plots will reveal yet-untold secrets about our beloved data-set',
  caption = 'Disclaimer: None of these plots are insightful'
)

plot of chunk unnamed-chunk-42

给子图添加序号

用大写的A就是大写字母,用小写的a就是小写字母:

代码语言:javascript
复制
patchwork + plot_annotation(tag_levels = 'A')

plot of chunk unnamed-chunk-43

当然外观是可以修改的:

代码语言:javascript
复制
patchwork + 
  plot_annotation(tag_levels = 'A') & 
  theme(plot.tag = element_text(size = 8))

plot of chunk unnamed-chunk-44

还可以在子图内部使用不同的序号:

代码语言:javascript
复制
patchwork[[1]] <- patchwork[[1]] + plot_layout(tag_level = 'new')
patchwork + plot_annotation(tag_levels = c('A', '1'))

plot of chunk unnamed-chunk-45

在序号前添加前缀:

代码语言:javascript
复制
patchwork + plot_annotation(tag_levels = c('A', '1'), tag_prefix = 'Fig. ',
                            tag_sep = '.', tag_suffix = ':')

plot of chunk unnamed-chunk-46

修改序号外观:

代码语言:javascript
复制
patchwork + 
  plot_annotation(tag_levels = c('A', '1'), tag_prefix = 'Fig. ', tag_sep = '.', 
                  tag_suffix = ':') & 
  theme(plot.tag.position = c(0, 1),
        plot.tag = element_text(size = 8, hjust = 0, vjust = 0))

plot of chunk unnamed-chunk-47

使用自定义列表的形式为不同的子图安排不同的序号:

代码语言:javascript
复制
patchwork + 
  plot_annotation(tag_levels = list(c('#', '&'), '1'))

plot of chunk unnamed-chunk-48

修改整个图形的外观

代码语言:javascript
复制
patchwork + 
  plot_annotation(title = 'The surprising truth about mtcars') & 
  theme(text = element_text('mono'))

plot of chunk unnamed-chunk-49

代码语言:javascript
复制
patchwork + 
  plot_annotation(title = 'The surprising truth about mtcars',
                  theme = theme(plot.title = element_text(size = 18))) & 
  theme(text = element_text('mono'))

plot of chunk unnamed-chunk-50

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 医学和生信笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装
  • 拼图!
    • 简单拼图
      • 嵌套拼图
        • 和非ggplot2对象拼图
          • 堆叠和成组
            • 快速拼很多图
            • 修改子图形
              • 修改全部子图形
              • 控制整体布局
                • 增加空白占位图形
                • 控制行列数
                • 行列的精细控制
                • Fixed aspect plots
                • 插入图形
                • 控制图例
                • 标题、副标题和说明文字
                • 给子图添加序号
                • 修改整个图形的外观
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档