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

使用ggplot2绘制森林图报错及添加数据列的技术求助

问题1:初始森林图报错修复

报错原因

代码仅添加了参考线,但未绘制任何对应数据的几何对象(如点、线段),导致ggplot无法识别y轴的有效映射,触发报错;同时多余的scale_y_discrete设置也干扰了因子水平的识别。

修复后代码

library(ggplot2)
library(ggpubr)

# 数据赋值
basdai_data <- structure(list(explanatory_variables = structure(1:15, levels = c("Age", 
"Disease duration", "Smoking", "BMI", "HLA-B27", "Uveitis", "TNFi start year", 
"csDMARD", "CRP", "Psoriasis", "Arthritis", "NSAID", "Enthesitis", 
"TNFi type", "IBD"), class = "factor"), unadj_coef = c(0.93, 
0.92, 1.13, 1, 1.02, 1.32, 0.93, 0.83, 0.76, 1.42, 1.77, 0.04, 
1.26, 0.93, 1.3), adj_coef = c(0.91, 0.91, 1.13, 1, 1.02, 1.33, 
0.92, 0.83, 0.76, 1.42, 1.77, 0.04, 1.26, 0.93, 1.3), pct_change = c(-1.8, 
-0.9, 0.6, -0.5, 0.4, 0.3, -0.2, -0.2, 0.1, 0.1, 0.1, -0.1, -0.1, 
0, 0)), row.names = c(NA, -15L), class = "data.frame")

# 按pct_change绝对值降序排序
basdai_data <- basdai_data[order(abs(basdai_data$pct_change), decreasing = TRUE),]

# 重新排序因子水平
basdai_data$explanatory_variables <- factor(basdai_data$explanatory_variables, 
                                            levels = as.character(basdai_data$explanatory_variables))

# 绘制森林图
ggplot(basdai_data, aes(x = pct_change, y = explanatory_variables)) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray50") +
  geom_point(size = 3, color = "#2c3e50") +  # 添加数据点
  scale_x_continuous(breaks = seq(-3, 3, 1)) +
  labs(x = "Percentage change", y = "Explanatory variable") +
  theme_pubr() +
  theme(text = element_text(size = 15, family = "Calibri"),
        axis.title = element_text(size = 20))

问题2:森林图前添加数据列

通过geom_text在不同x坐标位置添加各列数据,同时扩展x轴范围容纳文本:

ggplot(basdai_data, aes(y = explanatory_variables)) +
  # 可选:添加灰色背景行
  geom_hline(aes(yintercept = as.integer(explanatory_variables)), 
             linewidth = 1.5, color = "gray90") +
  # 左侧数据列文本
  geom_text(aes(x = -5, label = explanatory_variables), hjust = 0, size = 4) +
  geom_text(aes(x = -2, label = unadj_coef), size = 4) +
  geom_text(aes(x = 0, label = adj_coef), size = 4) +
  geom_text(aes(x = 2, label = pct_change), size = 4) +
  # 森林图部分
  geom_vline(xintercept = 4, linetype = "dashed", color = "gray50") +
  geom_point(aes(x = 4 + pct_change), size = 3, color = "#2c3e50") +
  # 设置x轴
  scale_x_continuous(breaks = c(-5, -2, 0, 2, 4),
                     labels = c("Variable", "Unadj. coef.", "Adj. coef.", "Change (%)", ""),
                     limits = c(-6, 7)) +
  labs(x = NULL, y = NULL) +
  theme_pubr() +
  theme(text = element_text(size = 15, family = "Calibri"),
        axis.text.x = element_text(face = "bold"),
        axis.ticks = element_blank())

问题3:p2图的离散值报错修复

报错原因是y = explanatory_variables为离散因子,但geom_hline使用了连续数值的yintercept,两者不兼容。解决方法是将y轴转换为连续变量,同时保留原标签:

# 数据赋值
basdai_level3 <- structure(list(explanatory_variables = c("Age", "TNFi type", 
                                                          "TNFi start year", "CRP", "Smoking", "Disease duration", "HLA-B27", 
                                                          "NSAID", "csDMARD", "BMI", "Uveitis", "Psoriasis", "IBD", "Arthritis", 
                                                          "Enthesitis"), ID = c(11753, 11753, 11753, 8661, 9991, 8063, 
                                                                                7074, 5204, 6776, 6585, 5635, 5541, 5601, 3955, 4903), 
                                countries = c(15, 15, 15, 13, 14, 11, 14, 10, 15, 13, 10, 10, 10, 9, 9), 
                                unadj_coef = c(0.67, 0.67, 0.67, 0.38, 0.84, 0.59, 0.78, -0.2, 0.66, 0.75, 1.1, 1.2, 1.08, 1.56, 1.03), 
                                adj_coef = c(0.61, 0.67, 0.66, 0.38, 0.86, 0.56, 0.79, -0.2, 0.65, 0.74, 1.12, 1.2, 1.08, 1.57, 1.03), 
                                change = c(-0.06, 0, 0, 0, 0.02, -0.03, 0.02, 0, -0.01, -0.01, 0.02, 0, 0, 0, 0), 
                                pct_change = c(-8.9, 0.4, -0.4, 1.2, 2.3, -4.7, 2.3, -0.4, -1.3, -1.4, 1.4, 0.4, -0.1, 0.2, -0.4), 
                                unadj_coef_pvalue = c(0.037, 0.037, 0.037, 0.319, 0.016, 0.138, 0.054, 0.689, 0.125, 0.072, 0.017, 0.01, 0.02, 0.004, 0.039), 
                                adj_coef_pvalue = c(0.058, 0.037, 0.038, 0.314, 0.013, 0.158, 0.048, 0.69, 0.13, 0.076, 0.016, 0.01, 0.02, 0.003, 0.039), 
                                interaction = c(NA, NA, NA, NA, NA, NA, -2.46, NA, NA, NA, NA, 5.07, NA, NA, NA)), row.names = c(NA, 15L), class = "data.frame")

# 排序数据
basdai_level3 <- basdai_level3[order(basdai_level3$pct_change, decreasing = TRUE),]

# 转换因子为连续数值,保留原标签
basdai_level3$y_pos <- as.integer(factor(basdai_level3$explanatory_variables, 
                                         levels = as.character(basdai_level3$explanatory_variables)))
y_labels <- basdai_level3$explanatory_variables
names(y_labels) <- basdai_level3$y_pos

# 绘制p2图
p2 <- ggplot(basdai_level3, aes(x = 1, y = y_pos)) +
  geom_hline(yintercept = basdai_level3$y_pos, linewidth = 13, color = "gray92") +
  geom_text(aes(label = explanatory_variables), hjust = 0) +
  geom_text(aes(x = 3, label = unadj_coef)) +
  geom_text(aes(x = 4, label = adj_coef)) +
  geom_text(aes(x = 5, label = pct_change)) +
  geom_text(aes(x = 6, label = ifelse(is.na(interaction), "", interaction))) +  # 处理NA值
  scale_x_continuous(NULL, breaks = c(1, 3, 4, 5, 6), limits = c(1, 7),
                     labels = c('Variable', 'Unadj. coef.', 'Adj. coef.',
                                'Change (%)', 'Interaction'), position = 'top') +
  scale_y_continuous(NULL, breaks = basdai_level3$y_pos, labels = y_labels) +
  theme_void() +
  theme(axis.text.x.top = element_text(hjust = c(0, 0.5, 0.5, 0.5),
                                       face = "bold", family = "Calibri"),
        axis.text.y = element_text(hjust = 1))
print(p2)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 01:55:19