You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中消除面板图空白并排布带双分面标签的多子图(适配A4半页)

问题

需要生成适配A4纸一半版面的面板图:包含2个大类、9个亚类,其中第9个亚类仅需1张子图。尝试过facet、grid.arrange、ggarrange和cowplot,但始终无法消除子图间冗余空白,也无法精准控制分类标签,且希望避免手动调整绘图(保证可复现性)。

目标效果:
目标效果

当前生成单张子图的函数:

inter_plots <- function(data, x_id, y_id, xlab, ylab, xmin, xmax){
  ggplot(data, aes_string(x_id, y_id, fill = "probs")) +
    geom_tile(color = "white", lwd = 0, linetype = 1) +
    scale_x_continuous(expand = c(0, 0), breaks = c(-0.5, 0, 1, 2)) +
    scale_y_continuous(expand = c(0, 0), 
                       breaks = c(min(data$sqrt_ud),8.867e-07,1.755e-06), 
                       labels = my_labels) +
    labs(x = "", y = "", fill = "Selection \nprobability") +
    scale_fill_gradientn("Selection \nprobability", colors = colfunc(135)) +
    theme_classic() +
    theme(axis.text = element_text(color = "black", size = 15),
          axis.line = element_line(linewidth = 1.2),
          text = element_text(size = 20),
          legend.text = element_text(size = 15),
          legend.position = "none",
          aspect.ratio = 1,
          axis.title.x=element_text(color = "white"),
          axis.text.x=element_text(color = "white"),
          axis.ticks.x=element_blank(),
          plot.margin=unit(c(-1,1,-1,0), "cm"))
}

当前用gridExtra排布的代码:

gridExtra::grid.arrange(fall_plots[[1]], spring_plots[[1]], fall_plots[[2]], spring_plots[[2]], fall_plots[[3]], spring_plots[[3]], 
                        fall_plots[[4]], spring_plots[[4]], fall_plots[[5]], spring_plots[[5]], fall_plots[[6]], spring_plots[[6]], fall_plots[[7]], spring_plots[[7]], 
                        fall_plots[[8]], spring_plots[[8]], fall_plots[[9]], 
                        ncol = 2, nrow = 9, left = yleft, bottom = xbottom, 
                        vp = viewport(width=0.9, height=0.9))

当前效果(不符合预期):
当前效果


解决方案

1. 改用patchwork包实现精准排布

patchwork对子图组合、间距控制和标签添加的支持更灵活,是解决这类布局问题的首选工具。

2. 优化单张子图主题,消除冗余空白

修改inter_plots函数的plot.margin,移除极端负边距(易导致元素重叠或布局混乱),改用温和的边距设置,同时统一轴元素的可见性规则:

inter_plots <- function(data, x_id, y_id, xlab, ylab, xmin, xmax){
  ggplot(data, aes_string(x_id, y_id, fill = "probs")) +
    geom_tile(color = "white", lwd = 0, linetype = 1) +
    scale_x_continuous(expand = c(0, 0), breaks = c(-0.5, 0, 1, 2)) +
    scale_y_continuous(expand = c(0, 0), 
                       breaks = c(min(data$sqrt_ud),8.867e-07,1.755e-06), 
                       labels = my_labels) +
    labs(x = "", y = "", fill = "Selection \nprobability") +
    scale_fill_gradientn("Selection \nprobability", colors = colfunc(135)) +
    theme_classic() +
    theme(axis.text = element_text(color = "black", size = 15),
          axis.line = element_line(linewidth = 1.2),
          text = element_text(size = 20),
          legend.text = element_text(size = 15),
          legend.position = "none",
          aspect.ratio = 1,
          # 仅保留必要边距,消除冗余空白
          plot.margin = unit(c(0, 0.2, 0, 0), "cm"),
          # 默认隐藏x轴元素,后续按需开启
          axis.title.x = element_blank(),
          axis.text.x = element_blank(),
          axis.ticks.x = element_blank(),
          # 默认隐藏y轴元素,左侧列子图后续开启
          axis.text.y = element_blank(),
          axis.ticks.y = element_blank())
}

3. 批量调整子图的轴可见性

为避免重复元素,统一设置:

  • 仅左侧列(Fall类)的子图保留y轴文本和刻度
  • 仅底部行的子图保留x轴文本和刻度
# 调整Fall类子图(左侧列)保留y轴
fall_plots <- lapply(fall_plots, function(p) {
  p + theme(axis.text.y = element_text(color = "black"),
            axis.ticks.y = element_line(color = "black"))
})

# 调整底部行的子图保留x轴
fall_plots[[9]] <- fall_plots[[9]] + theme(axis.text.x = element_text(color = "black"),
                                           axis.ticks.x = element_line(color = "black"))
spring_plots[[8]] <- spring_plots[[8]] + theme(axis.text.x = element_text(color = "black"),
                                               axis.ticks.x = element_line(color = "black"))

4. 组合子图并添加分类标签

用patchwork的wrap_plots实现排布,同时添加大类标签和亚类标签:

library(patchwork)
library(grid)

# 定义亚类和大类标签
subcat_labels <- paste0("Subcategory ", 1:9)
cat_labels <- c("Fall", "Spring")

# 构建子图列表:前8行每行2张,第9行仅1张
plot_list <- c()
for(i in 1:8) {
  plot_list <- c(plot_list, fall_plots[[i]], spring_plots[[i]])
}
plot_list <- c(plot_list, fall_plots[[9]])

# 组合子图,控制行列布局
combined_plot <- wrap_plots(plot_list, ncol = 2, nrow = 9, heights = rep(1, 9)) +
  # 添加大类标签(左右两侧垂直排列)
  plot_annotation(
    left = textGrob(cat_labels[1], rot = 90, gp = gpar(fontsize = 20)),
    right = textGrob(cat_labels[2], rot = 270, gp = gpar(fontsize = 20))
  )

# 添加亚类标签(每行左侧)
for(i in 1:9) {
  label_grob <- textGrob(subcat_labels[i], gp = gpar(fontsize = 18))
  combined_plot <- combined_plot +
    inset_element(label_grob, 
                  left = 0, right = 0.05, 
                  top = 1 - (i-1)/9 - 0.5/9, bottom = 1 - i/9 + 0.5/9)
}

# 导出为适配A4一半的文件(A4宽21cm,一半取10cm,高度按比例设置)
ggsave("combined_plot.pdf", combined_plot, width = 10, height = 14, units = "cm")

5. 关键细节说明

  • aspect.ratio=1确保子图为正方形,配合heights=rep(1,9)保证每行高度一致
  • inset_element精准控制亚类标签的位置,避免与子图内容重叠
  • 统一轴可见性减少冗余元素,同时保证读图清晰
  • ggsave直接指定尺寸,完美适配A4纸一半版面

内容的提问来源于stack exchange,提问作者Tess H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 21:37:02