R ggplot2 facet_wrap分面下为各面板单独添加geom_vline竖线
问题原因
facet_wrap()默认在全量数据集上计算几何对象的统计值,直接在geom_vline()中写mean(value)会计算所有样本的总均值,不会按分面分组单独计算,因此无法匹配每个子图的对应参考值。
实现方法
核心是提前单独生成每个分面对应的参考线数据集,再传入geom_vline()做映射,即可让参考线自动匹配对应子图。
1. 数据预处理
首先将数据转换为长格式,再单独计算每个参数对应的估计值均值(红色实线)、真实参数值(蓝色虚线),生成专用的参考线数据框:
library(tidyverse) # 生成长格式绘图数据,变量和原ggarrange方案保持一致 plot_df <- rebias |> pivot_longer( cols = c(g1_hat, b1_hat, ra_hat, g2_hat, b3_hat, rf_hat), names_to = "key", values_to = "value" ) # 调整分面排列顺序,和原ggarrange排版一致 plot_df$key <- factor( plot_df$key, levels = c("g1_hat", "b1_hat", "ra_hat", "g2_hat", "b3_hat", "rf_hat") ) # 生成参考线数据 vline_df <- plot_df |> group_by(key) |> # 计算每个参数的估计值均值(红色实线) summarise(est_mean = mean(value, na.rm = T)) |> # 匹配每个参数对应的真实值(蓝色虚线,规则和原单图代码完全一致) mutate( true_val = case_when( key == "g1_hat" ~ sqrt(unique(rebias$g1)), key == "g2_hat" ~ sqrt(unique(rebias$g2)), key == "b1_hat" ~ sqrt(unique(rebias$b1)), key == "b3_hat" ~ sqrt(unique(rebias$b3)), key == "ra_hat" ~ unique(rebias$ra), key == "rf_hat" ~ mean(rebias$rf) ) )
2. 绘图代码
密度层使用长格式主数据,竖线层使用提前生成的参考线数据,facet_wrap()会自动按照key字段将参考线匹配到对应分面:
ggplot(plot_df, aes(x = value)) + geom_density(alpha = 0.3) + # 红色实线:估计值均值 geom_vline( data = vline_df, aes(xintercept = est_mean), color = "red", linetype = "solid", linewidth = 1 ) + # 蓝色虚线:真实参数值 geom_vline( data = vline_df, aes(xintercept = true_val), color = "blue", linetype = "dashed", linewidth = 1 ) + facet_wrap(~key, nrow = 2, scales = "free_x") + labs(x = "Parameter values", y = "Density") + theme_bw(12)
补充说明
- 参数
scales = "free_x"允许每个分面的x轴根据自身数值范围调整刻度,和原单图单独设置坐标轴的效果一致,如果需要统一所有分面的x轴范围,删除该参数即可。 - 如果需要自定义特定分面的x轴刻度,可以使用
ggh4x包的scale_x_continuous相关函数为每个分面单独设置刻度,和原单图的刻度设置完全匹配。 - 如果需要新增
re_hat等其他参数的分面,只需在pivot_longer的cols参数中加入对应列名,同时在vline_df的case_when中补充该参数对应的真实值计算规则即可。
内容的提问来源于stack exchange,提问作者lf_araujo
相关产品推荐
相关产品推荐

