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

forestploter多置信区间条与相邻文本对齐问题求助

问题描述

参照forestploter教程的多CI列章节,希望在森林图每行展示3组置信区间条,但当前设置下,区间条与右侧OR (95% CI)格式的统计文本无法对齐。以下是复现问题的模拟数据及代码:

library(forestploter)

dat <- data.frame(outcome=c(rep('A',3),
                            rep('B',3),
                            rep('C',3)),
                  exposure=rep(c('x','y','z'),3),
                  number=c(1,2,5,6,7,8,9,3,4),
                  o_OR=c(rnorm(9,70,10)),
                  o_lci=c(rnorm(9,30,15)),
                  o_uci=c(rnorm(9,80,10)),
                  p_OR=c(rnorm(9,70,10)),
                  p_lci=c(rnorm(9,30,15)),
                  p_uci=c(rnorm(9,80,10)),
                  q_OR=c(rnorm(9,70,10)),
                  q_lci=c(rnorm(9,30,15)),
                  q_uci=c(rnorm(9,80,10)),
                  ` `=paste(rep('                        ', 9),
                            collapse=' '),
                  `OR (95% CI)`=c('0.853 (0.000, 1.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)',
                                  '1.853 (0.287, 4.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)',
                                  '0.853 (0.000, 1.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)',
                                  '0.853 (0.000, 1.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)',
                                  '0.853 (0.000, 1.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)',
                                  '0.853 (0.000, 1.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)',
                                  '0.853 (0.000, 1.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)',
                                  '0.853 (0.000, 1.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)',
                                  '0.853 (0.000, 1.348)\n0.382 (0.129, 6.321)\n3.212 (1.129, 10.321)'),
                  `p-value`=c('0.014\n0.314\n0.614',
                              '0.014\n0.314\n0.614',
                              '0.014\n0.314\n0.614',
                              '0.014\n0.314\n0.614',
                              '0.014\n0.314\n0.614',
                              '0.014\n0.314\n0.614',
                              '0.014\n0.314\n0.614',
                              '0.014\n0.314\n0.614',
                              '0.014\n0.314\n0.614'))

tm <- forest_theme(base_size = 10,
                   refline_col = "#969696",
                   refline_lty = 'solid',
                   ci_lwd = 1.9,
                   ci_Theight = 0.3,
                   title_just = 'center',
                   arrow_type = "closed",
                   legend_name = 'Method',
                   ci_col = c('#440154ff', '#287d8eff', '#73d055ff'),
                   legend_value = c('IVW', 'Egger', 'Weighted Median'),
                   arrow_label_just = "end",
                   core= list(padding=unit(c(4,3), 'mm')),
                   colhead=list(fg_params=list(hjust=0.5, x=0.5)))

forest(dat[,c(2,1,3, 13:15)],
       est = list(as.numeric(dat$o_OR),
                  as.numeric(dat$p_OR),
                  as.numeric(dat$q_OR)),
       lower = list(as.numeric(dat$o_lci),
                    as.numeric(dat$p_lci),
                    as.numeric(dat$q_lci)), 
       upper = list(as.numeric(dat$o_uci),
                    as.numeric(dat$p_uci),
                    as.numeric(dat$q_uci)),
       ci_column = 4,
       ref_line = 1,
       title='A title',
       xlab='OR',
       theme=tm)
解决方案

问题根源在于:每行的3组CI条是垂直居中排列,但右侧OR (95% CI)和p-value是多行堆叠文本,导致视觉上无法一一对应对齐。需要重构数据结构并调整绘图参数,让每组CI条对应单独一行的统计文本,同时通过合并单元格保持视觉分组:

修改步骤

  1. 重构数据:将原来每行的多组统计文本拆分,让每行仅对应一组CI条和一行统计文本
  2. 合并分组行:使用merge_rows参数将同一outcome和exposure的行合并,保持视觉上的单行分组效果
  3. 调整主题边距:微调行内边距,确保对齐美观

修改后完整代码

library(forestploter)
library(dplyr)
library(stringr)

# 重构数据:拆分多行文本为单独行
dat_long <- dat %>%
  select(outcome, exposure, number, starts_with(c("o_", "p_", "q_")), `OR (95% CI)`, `p-value`) %>%
  # 拆分OR和p-value的多行文本
  mutate(
    OR_list = str_split(`OR (95% CI)`, "\n"),
    p_list = str_split(`p-value`, "\n")
  ) %>%
  unnest(c(OR_list, p_list)) %>%
  # 匹配对应的CI值
  mutate(
    method = rep(c("IVW", "Egger", "Weighted Median"), nrow(.)/3),
    OR = case_when(
      method == "IVW" ~ o_OR,
      method == "Egger" ~ p_OR,
      method == "Weighted Median" ~ q_OR
    ),
    lci = case_when(
      method == "IVW" ~ o_lci,
      method == "Egger" ~ p_lci,
      method == "Weighted Median" ~ q_lci
    ),
    uci = case_when(
      method == "IVW" ~ o_uci,
      method == "Egger" ~ p_uci,
      method == "Weighted Median" ~ q_uci
    )
  ) %>%
  select(outcome, exposure, number, OR, lci, uci, `OR (95% CI)` = OR_list, `p-value` = p_list)

# 创建合并行的索引:同一outcome+exposure的行合并
merge_idx <- dat_long %>%
  group_by(outcome, exposure) %>%
  group_indices()

# 定义主题
tm <- forest_theme(
  base_size = 10,
  refline_col = "#969696",
  refline_lty = 'solid',
  ci_lwd = 1.9,
  ci_Theight = 0.3,
  title_just = 'center',
  arrow_type = "closed",
  legend_name = 'Method',
  ci_col = c('#440154ff', '#287d8eff', '#73d055ff'),
  legend_value = c('IVW', 'Egger', 'Weighted Median'),
  arrow_label_just = "end",
  core= list(padding=unit(c(2,3), 'mm')), # 缩小行内边距,让对齐更紧凑
  colhead=list(fg_params=list(hjust=0.5, x=0.5))
)

# 绘制森林图
forest(dat_long[,c(2,1,3,6,7)],
       est = dat_long$OR,
       lower = dat_long$lci,
       upper = dat_long$uci,
       ci_column = 4,
       ref_line = 1,
       title='A title',
       xlab='OR',
       theme=tm,
       merge_rows = merge_idx, # 合并分组行
       ci_col = rep(c('#440154ff', '#287d8eff', '#73d055ff'), 9) # 为每行设置对应CI颜色
)

效果说明

修改后,每组置信区间条会和右侧对应的OR (95% CI)、p-value文本精准对齐,同时通过合并单元格,outcome、exposure和number列仍保持单行展示,不影响整体视觉分组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:27:07