如何用ggplot2单次填充绘图的两个对立侧区域?
解决ggplot2单次geom_area填充双侧拒绝域的问题
问题原因
geom_area的xlim参数仅支持接收单一连续区间(长度为2的向量),传入多个区间时只会识别第一个区间,因此第二个区间(23,30)被忽略。
解决方案:自定义概率密度函数
通过自定义一个函数,仅在目标拒绝域区间内返回正态分布的密度值,其余区间返回0,这样单次geom_area就能同时填充两个不连续的拒绝区域。
完整代码示例
library(ggplot2) # 预先计算均值和标准差,提升代码可读性 n <- 30 p <- 0.6 mu <- n * p sigma <- sqrt(n * p * (1 - p)) # 自定义拒绝域的密度函数:仅在(0,13)和(23,30)返回dnorm值,其余为0 dnorm_reject <- function(x) { ifelse((x >= 0 & x <= 13) | (x >= 23 & x <= 30), dnorm(x, mean = mu, sd = sigma), 0) } # 绘制图形:使用更平滑的x序列保证填充效果 ggplot(data.frame(x = seq(0, 30, length.out = 1000)), aes(x = x)) + # 绘制原H0分布曲线 stat_function(fun = dnorm, args = list(mean = mu, sd = sigma), aes(col = "H0")) + # 填充拒绝域 geom_area(stat = "function", fun = dnorm_reject, aes(fill = "alpha"), alpha = 0.3) + # 自定义颜色和标签 scale_color_manual(values = "black", labels = "H₀分布") + scale_fill_manual(values = "red", labels = "拒绝域") + labs(x = "样本统计量", y = "概率密度", color = "", fill = "") + theme_minimal()
关键说明
- 自定义函数
dnorm_reject通过ifelse判断x是否在拒绝域内,非拒绝域返回0,这样geom_area只会在有效区域填充。 - 将x轴数据从
0:30改为seq(0,30,length.out=1000),生成更多连续点,避免离散点导致的填充断层。 - 添加
alpha参数调整填充透明度,让原分布曲线更清晰。
内容的提问来源于stack exchange,提问作者wysk
相关产品推荐
相关产品推荐

