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

