R tips:ggplot无缝拼图

冰糖 生信菜鸟团 2023-07-08 12:02 发表于山东

ggplot2及其衍生包可以绘制各种各样的复杂绘图,常见的使用场景是使用ggplot2绘制单图,使用ggpubr、cowplot、gridExtra及patchwork等工具包进行拼图,尤其是patchwork包,它的函数设计理念很优秀,使用很方便 。

拼图可以解放很多ggplot2的绘图限制,是一个非常有意思的话题。但是如果做过拼图的人就会发现,拼图只是简单的将两个图摆放在一起,图与图之间依然保留着很多空白空间。

图片

ggplot_1

假如可以去除这个空白空间,那就可以实现无缝拼图,可以在很多复杂图表的绘制中发挥作用。

图片

ggplot_2

为了更清晰的展示这个图的两个子图,可以在子图的panel上添加一个边框,可以发现两个子图的绘图区域的确是无缝拼接。

图片

ggplot_2

复现上面的拼图

下面先复现一下上面的两个图:

library(ggplot2)
library(magrittr)
library(patchwork)

# 1. 常规拼图
p <- 
  iris %>%
  ggplot(aes(x = Species, y = Sepal.Length, fill = Species)) +
  geom_boxplot()

p/p

# 2. 无缝拼图
p_clean <-
  p +
  theme(
    axis.title.x = element_blank(), # 去除x轴标题
    axis.text.x  = element_blank(), # 去除x轴标签
    axis.ticks.x = element_blank(), # 去除x轴ticks
    axis.ticks.length.x = unit(0"mm"), # ticks去除的关键,ticks的绘图区域调为0
    plot.margin         = margin() # 去除绘图margin
  ) +
  scale_y_discrete(expand = c(00)) # 若为白色背景,还需要去除轴两侧的空白填充

p_clean / p_clean

# 3. 无缝拼图,添加边框
p_clean2 <- p_clean + 
  theme(
    panel.background = element_rect(fill = NA, colour = "black")
  )

p_clean2/p_clean2

无缝拼接的经验总结

一个图在拼接的时候,需要处理的细节有:

  1. 轴标题、轴标签、轴刻度是显而易见的阻挡无缝拼接的绘图元素,需要去除。需要注意的是,真正去除刻度的命令是靠axis.ticks.length主题属性设为0才实现的。

  2. 隐形的阻挡无缝拼接的原始是绘图的margin,可以通过将plot.margin主题属性设为0来关闭。

  3. 如果绘制的图是白色背景,那么还会有一部分空白区域是轴的expand属性带来的,可以通过scale_*系列函数来将其设置为0。

  4. 当需要设置ticks的length的时候,传递的参数是一个unit对象,比如上面使用的unit(0, "mm")。当需要设置plot.margin的时候,需要传递的是一个margin对象,比如上面使用的margin(),margin函数默认就是生成一个0边界的margin。

  5. 拼图一般是拼接的不同的图表,注意此时可能需要使用xlim、ylim或者scale_*函数的limits属性来控制拼图的轴范围是一致的。因为去除了轴标签之后,两个图是共用一个轴标签的,只有轴标签范围一致才能保证绘制的图表是正确的。

  6. 另借助patchwork的plot_spacer和plot_layout,并通过使用wrap_plots精细调整每个拼图的占据比例,可以实现非常复杂多变的图形拼接,比如aplot擅长的添加轴图表。但是aplot有局限,不能把两个aplot拼在一起,但是无缝拼接的思路就可以很容易的实现‘多拼多’。

这里有点抽象,举个例子:

# 令p为常规ggplot2绘图对象

# aplot可以完成如下工作:
p %>% insert_right(p) %>% insert_right(p) %>% insert_right(p)

# 但是无法完成如下工作:
p_a1 <- p %>% insert_right(p)
p_a2 <- p %>% insert_right(p)

p_a1 %>% insert_right(p_a2)

虽然从逻辑上,这两个图的绘制结果应该是一样的。

但是本文的所说的patchwork无缝拼图就不存在这个问题,任意组合、任意拼接、任意嵌套。

复杂绘图往往比较个性化,具体情况就不展开了,最后留一个小问题:

如果仔细看的话,会发现本文所举例子中的无缝拼图中间x轴上有两个细微的空白gaps,这个是怎么造成的?

微信扫一扫
关注该公众号