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

如何将两张forestplot合并为无元素重叠的单张图形?

合并forestplot森林图时文本与图形重叠的解决方法

问题背景

我使用forestplot包生成了多张森林图,该包绘图效果出色。但将瑞典和丹麦的两张森林图合并为单张图形时,出现了图形与文本互相重叠的问题。由于需要保留所有文本元素,无法通过裁剪内容解决,尝试了官方教程及网上多种方法均无效,寻求解决方案。

尝试过的代码(修正拼写错误后)

library(forestplot)
library(dplyr)
data("dfHRQoL")

# 创建瑞典和丹麦的单个森林图
fp_sweden <- dfHRQoL |>
  filter(group == "Sweden") |>
  mutate(est = sprintf("%.2f", mean), .after = labeltext) |>
  forestplot(labeltext = c(labeltext, est), 
             title = "Sweden",
             clip = c(-.1, Inf),
             xlab = "EQ-5D index",
             new_page = FALSE)

fp_denmark <- dfHRQoL |>
  filter(group == "Denmark") |>
  mutate(est = sprintf("%.2f", mean), .after = labeltext) |>
  forestplot(labeltext = c(labeltext, est), 
             title = "Denmark",
             clip = c(-.1, Inf),
             xlab = "EQ-5D index",
             new_page = FALSE)

# 尝试1:使用grid布局
library(grid)
grid.newpage()
borderWidth <- unit(4, "pt")
width <- unit(convertX(unit(1, "npc") - borderWidth, unitTo = "npc", valueOnly = TRUE)/2, "npc")
pushViewport(viewport(layout = grid.layout(nrow = 1, 
                                           ncol = 3, 
                                           widths = unit.c(width,
                                                           borderWidth,
                                                           width))
)
)
pushViewport(viewport(layout.pos.row = 1,
                      layout.pos.col = 1))
fp_sweden 
upViewport()
pushViewport(viewport(layout.pos.row = 1,
                      layout.pos.col = 2))
grid.rect(gp = gpar(fill = "grey", col = "red"))
upViewport()
pushViewport(viewport(layout.pos.row = 1,
                      layout.pos.col = 3))
fp_denmark 
upViewport(2)

# 尝试2:调整grid布局比例
grid.newpage()
borderWidth <- unit(4, "pt")
width <- unit(convertX(unit(1, "npc") - borderWidth, unitTo = "npc", valueOnly = TRUE)/2, "npc")
pushViewport(viewport(layout = grid.layout(nrow = 1, 
                                           ncol = 3, 
                                           widths = c(0.45, 0.1, 0.45))
)
)
pushViewport(viewport(layout.pos.row = 1,
                      layout.pos.col = 1))
fp_sweden 
upViewport()

pushViewport(viewport(layout.pos.row = 1,
                      layout.pos.col = 3))
fp_denmark 
upViewport(2)

# 尝试3:转为grob用patchwork合并
library(ggplotify)
library(patchwork)

fpd_grob <- grid2grob(print(fp_denmark))

p1 <- grid2grob(print(fp_denmark))
p2 <- grid2grob(print(fp_sweden))
p_both <- wrap_elements(p1) + wrap_elements(p2)
p_both

解决方案

重叠的核心原因是单个森林图默认按全画布尺寸渲染,即使设置new_page = FALSE,元素仍会超出分配的viewport范围。以下两种方法可解决:

方法1:生成时控制森林图元素尺寸+grid布局

在创建单个森林图时缩小字体、调整图形位置,再用grid分配准确的viewport:

library(forestplot)
library(dplyr)
library(grid)

data("dfHRQoL")

# 创建瑞典森林图:缩小字体,调整图形位置避免溢出
fp_sweden <- dfHRQoL |>
  filter(group == "Sweden") |>
  mutate(est = sprintf("%.2f", mean), .after = labeltext) |>
  forestplot(labeltext = c(labeltext, est), 
             title = "Sweden",
             clip = c(-.1, Inf),
             xlab = "EQ-5D index",
             new_page = FALSE,
             # 缩小标签字体
             txt_gp = fpTxtGp(label = gpar(cex = 0.8)),
             # 调整图形在布局中的位置,给文本留足空间
             graph.pos = 3)

# 丹麦森林图做同样设置
fp_denmark <- dfHRQoL |>
  filter(group == "Denmark") |>
  mutate(est = sprintf("%.2f", mean), .after = labeltext) |>
  forestplot(labeltext = c(labeltext, est), 
             title = "Denmark",
             clip = c(-.1, Inf),
             xlab = "EQ-5D index",
             new_page = FALSE,
             txt_gp = fpTxtGp(label = gpar(cex = 0.8)),
             graph.pos = 3)

# 用grid分两列布局,显式打印到指定viewport
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow = 1, ncol = 2, widths = c(0.5, 0.5))))

pushViewport(viewport(layout.pos.row = 1, layout.pos.col = 1))
print(fp_sweden, newpage = FALSE)
upViewport()

pushViewport(viewport(layout.pos.row = 1, layout.pos.col = 2))
print(fp_denmark, newpage = FALSE)
upViewport(2)

方法2:正确转为grob后用patchwork合并

之前的patchwork尝试失败是因为未正确限制grob范围,需用as.grob包裹打印函数,再指定布局:

library(ggplotify)
library(patchwork)

# 将森林图转为grob时,用函数包裹打印操作
p1 <- as.grob(function() print(fp_sweden, newpage = FALSE))
p2 <- as.grob(function() print(fp_denmark, newpage = FALSE))

# 强制两列等宽合并
p_both <- p1 + p2 + plot_layout(ncol = 2, widths = c(1, 1))
p_both

关键提示

  • 修正代码中的拼写错误:library(foresplot)应为library(forestplot)
  • 若文本仍溢出,可进一步缩小cex值(如0.7),或调整graph.pos参数改变图形与文本的比例
  • 必须用print()显式将森林图输出到指定viewport,直接调用对象会导致布局失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 02:45:44