如何在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
相关产品推荐
相关产品推荐

