如何在ggplot2分面森林图顶部添加统一的风险比方向标注
解决ggplot2分面森林图顶部仅添加一次效应方向标注的问题
问题说明
用ggplot2绘制分面森林图时,希望在整个绘图区域的顶部添加风险比(HR)的效应方向标注(如“有利于药物”“有利于对照”),但使用annotate()会导致每个分面顶部都重复显示标注;尝试draw_plot_label()又需要绝对坐标,无法适配不同图表的x轴数值,需要一种能自动适配且仅显示一次标注的方案。
解决方案:使用patchwork包拼接标注与森林图
通过将标注文本做成一个无背景的独立ggplot对象,再与森林图垂直拼接,既保证标注仅出现一次,又能自动匹配森林图的x轴范围,无需手动调整坐标,适合批量生成图表的场景。
完整代码
library(ggplot2) library(patchwork) # 样本数据 final_cox_dat <- data.frame( comparator = rep(c("Group A", "Group B", "Group C"), each = 2), estimate = c(1.2, 1.5, 0.8, 0.9, 1.4, 1.7), conf.low = c(1.0, 1.3, 0.7, 0.8, 1.3, 1.5), conf.high = c(1.5, 1.7, 0.9, 1.0, 1.6, 1.9), model = rep(c("Weighted", "Unweighted"), times = 3) ) # 绘制核心森林图 forest_plot <- ggplot( final_cox_dat, aes( x = estimate, y = comparator, xmin = conf.low, xmax = conf.high, color = model ) ) + geom_pointrange(position = position_dodge(width = 0.8)) + geom_vline(xintercept = 1, linetype = "dashed") + facet_wrap(~comparator, ncol = 1, scales = "free_y") + labs( title = NULL, x = "Hazard Ratio (95% CI)", y = NULL ) + theme_minimal() + theme( strip.text = element_blank(), legend.title = element_blank(), legend.position = "bottom", axis.title.y = element_blank(), axis.ticks.y = element_blank() ) + scale_color_manual( values = c("Unweighted" = "red", "Weighted" = "blue") ) + geom_text( aes( x = max(conf.high) + 0.05, group = model, label = sprintf( "%0.2f (%0.2f, %0.2f)", estimate, conf.low, conf.high ) ), hjust = 0, vjust = 0.5, size = 4.5, color = "black", position = position_dodge(width = 0.8) ) + scale_x_continuous(breaks = seq(0, max(final_cox_dat$conf.high + 0.2), by = 0.2), expand = expansion(mult = 0.1)) + theme(text = element_text(size = 18)) + guides(color = guide_legend(reverse=TRUE)) # 创建顶部标注的无背景文本图,匹配森林图x轴范围 annotation_plot <- ggplot() + geom_text(aes(x = 1, y = 1, label = "有利于药物"), hjust = 1.5, size = 6) + geom_text(aes(x = 1, y = 1, label = "有利于对照"), hjust = -0.5, size = 6) + scale_x_continuous(limits = ggplot_build(forest_plot)$layout$panel_params[[1]]$x.range) + theme_void() # 移除所有无关元素 # 拼接标注图与森林图,标注仅占极小高度 final_plot <- annotation_plot + forest_plot + plot_layout(ncol = 1, heights = c(0.05, 0.95)) # 输出最终图 print(final_plot)
方案优势
- 标注仅在整体顶部显示一次,不会随分面重复
- 自动匹配森林图的x轴范围,无需手动调整坐标,适配不同数据生成的图表
- 代码结构清晰,适合批量生成数十份图表的自动化场景
替代方案:使用grid包添加全局文本
如果不想引入patchwork包,可通过grid包直接在绘图设备的全局视口添加文本:
library(ggplot2) library(grid) # 先绘制森林图(代码同前,省略重复部分) print(forest_plot) # 获取森林图的x轴范围 x_range <- ggplot_build(forest_plot)$layout$panel_params[[1]]$x.range # 将HR=1的位置转换为视口坐标比例 hr1_pos <- (1 - x_range[1]) / (x_range[2] - x_range[1]) # 在顶部添加标注 grid.text("有利于药物", x = unit(hr1_pos + 0.1, "npc"), # 相对于HR=1的位置向右偏移 y = unit(1, "npc") - unit(0.02, "npc"), size = 6) grid.text("有利于对照", x = unit(hr1_pos - 0.1, "npc"), # 相对于HR=1的位置向左偏移 y = unit(1, "npc") - unit(0.02, "npc"), size = 6)
内容的提问来源于stack exchange,提问作者krtbris
相关产品推荐
相关产品推荐

