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

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:修改原代码(无需新增依赖)

只需要改三处:

  1. 给table_base和forest_plot设置完全一致的绘图边距,删掉table_base里x轴文本多余的margin参数
  2. 删掉tab1、tab2里geom_text多余的y = rev(domain)映射,和主图共用同一套y轴刻度规则
  3. 给两个表格图也加上和主图一致的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 19:27:28