R语言grid.arrange排列森林图与附表时数值行对齐问题
对齐失效原因
行错位是两个问题叠加导致的:
- y轴顺序重复反转:主图
forest_plot已经通过scale_y_discrete(limits = rev)将y轴条目从上到下反转为7、6…1的顺序,但tab1、tab2的geom_text层又额外设置了y = rev(domain),等于二次反转y轴顺序,本身行对应关系就错了 - 子图边距不统一:主图默认保留了y轴元素的占位空间,同时
table_base里给x轴文本设置了t=20的上外边距,把表格整体内容向下挤压,三个子图的绘图区上下起始位置、行高基线完全不匹配,调整hjust、position参数自然没有效果。
修复方案
方案1:修改原代码(无需新增依赖)
只需要改三处:
- 给
table_base和forest_plot设置完全一致的绘图边距,删掉table_base里x轴文本多余的margin参数 - 删掉
tab1、tab2里geom_text多余的y = rev(domain)映射,和主图共用同一套y轴刻度规则 - 给两个表格图也加上和主图一致的y轴反转设置,保证刻度位置完全对齐
修复后的完整可运行代码:
library(ggplot2) library(gridExtra) d = data.frame( domain = c("1","2","3","4","5","6","7"), odd_ratio = c(5.0, 7.4, 1.0, 4.6, 1.3, 10.0, 6.6), lower = c(3.13, 3.4, 0.6, 1.55, 0.09, 3.42, 1.55), upper = c(10.8, 19.53, 1.8, 9.56, 17.32, 23.96, 30.21), CI = c("5.0 (3.13 - 10.8)", "7.4 (3.4 - 19.53)", "1.0 (0.6 - 1.8)", "4.6 (1.55 - 9.56)", "1.3 (0.09 - 17.32)", "10.0 (3.42 - 23.96)", "6.6 (1.55 - 30.21)") ) # 统一设置全图边距,消除不同子图的留白差 common_margin <- margin(t = 5, r = 5, b = 5, l = 5) forest_plot = ggplot(d, aes(y = domain, x = odd_ratio)) + geom_point(shape = 18, size = 5) + geom_errorbarh(aes(xmin = lower, xmax = upper), height = 0.25) + geom_vline(xintercept = 1, color = "red", linetype = "dashed", linewidth = 1, alpha = 0.5)+ scale_x_log10(name = "OR", breaks=c(0.1,0.2,0.5,1,5,10,30), minor_breaks = NULL)+ scale_y_discrete(limits = rev)+ theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank(), axis.line = element_blank(), plot.margin = common_margin) table_base <- ggplot(d, aes(y=domain)) + ylab(NULL) + xlab(NULL) + scale_y_discrete(limits = rev) + # 和主图保持完全一致的y轴反转规则 theme(plot.title = element_text(hjust = 0.5, size=12), axis.text = element_blank(), # 直接隐藏不需要的轴文本,不要用白色文字+偏移的方法避免错位 axis.ticks = element_blank(), axis.line = element_blank(), axis.title = element_blank(), legend.position = "none", panel.background = element_blank(), panel.border = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), plot.background = element_blank(), plot.margin = common_margin) ## OR值表格 tab1 <- table_base + geom_text(aes(x = 1,label = sprintf("%0.1f", round(odd_ratio, digits = 1))), size = 4) + ggtitle("OR") ## 95%CI表格 tab2 <- table_base + geom_text(aes(x = 1, label = CI), size = 4) + ggtitle("95% CI") lay <- matrix(c(1,1,1,1,1,1,1,1,1,1,2,3,3,3), nrow = 1) grid.arrange(forest_plot, tab1, tab2, layout_matrix = lay)
方案2:用patchwork包实现自动对齐(推荐)
grid.arrange本身不会自动对齐不同子图的绘图区,换用专门为ggplot拼版设计的patchwork包,不需要手动微调边距就能自动对齐坐标轴,代码更简洁:
library(ggplot2) library(patchwork) # 主图和方案1的forest_plot完全一致 forest_plot = ggplot(d, aes(y = domain, x = odd_ratio)) + geom_point(shape = 18, size = 5) + geom_errorbarh(aes(xmin = lower, xmax = upper), height = 0.25) + geom_vline(xintercept = 1, color = "red", linetype = "dashed", linewidth = 1, alpha = 0.5)+ scale_x_log10(name = "OR", breaks=c(0.1,0.2,0.5,1,5,10,30), minor_breaks = NULL)+ scale_y_discrete(limits = rev)+ theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank(), axis.line = element_blank()) tab1 <- ggplot(d, aes(y = domain, x = 1)) + geom_text(aes(label = sprintf("%0.1f", odd_ratio)), size =4) + scale_y_discrete(limits = rev) + ggtitle("OR") + theme_void() + theme(plot.title = element_text(hjust=0.5, size=12)) tab2 <- ggplot(d, aes(y = domain, x =1)) + geom_text(aes(label = CI), size=4) + scale_y_discrete(limits = rev) + ggtitle("95% CI") + theme_void() + theme(plot.title = element_text(hjust=0.5, size=12)) # 直接拼接,自动对齐y轴,可通过widths参数调整各部分宽度 forest_plot + tab1 + tab2 + plot_layout(widths = c(10,1,3))
注意:不管用哪种方案,三个子图的y轴映射、刻度顺序、范围必须完全一致,不要单独修改某一个图的y轴参数,否则会再次出现错位。
内容的提问来源于stack exchange,提问作者M. waal
相关产品推荐
相关产品推荐

