在ggplot中为直方图添加正态密度图的后续问题
错误原因
- 子集匹配错误:你的数据中只有
Metric1和Metric12两个分组,但第二个geom_line里写了dat$met == 'Metric2',导致提取的val是空向量,min(.)和max(.)返回Inf和-Inf,seq()函数无法生成有效序列,触发报错。 - 管道符号错误:代码里的
%>%是HTML转义后的字符,实际应该用dplyr的标准管道符号%>%。 - 正态分布拟合逻辑错误:当前
dnorm()调用没有使用对应分组数据的均值和标准差,画出来的是标准正态分布(均值0,标准差1),不是贴合该组数据的拟合曲线。 - 代码冗余:重复提取相同分组的子集,既不高效也容易出错。
解决方法
以下是修正后的代码,同时优化了逻辑和可读性:
library(ggplot2) library(dplyr) set.seed(1) dat <- rbind( data.frame(val = rnorm(100), met = 'Metric1'), data.frame(val = rt(100, 2), met = 'Metric12') ) # 提前为每个分组生成正态拟合曲线的数据 norm_curve_data <- dat %>% group_by(met) %>% summarise( mean_val = mean(val), sd_val = sd(val), x = seq(min(dat$val), max(dat$val), length.out = 1000), y = dnorm(x, mean = mean_val, sd = sd_val) ) ggplot() + # 上方直方图:Metric1 geom_histogram( data = filter(dat, met == 'Metric1'), breaks = seq(-10, 10, 0.5), aes(x = val, y = after_stat(density)), colour = "black", alpha = 0.3 ) + # 下方直方图:Metric12 geom_histogram( data = filter(dat, met == 'Metric12'), breaks = seq(-10, 10, 0.5), aes(x = val, y = -after_stat(density)), colour = "black", alpha = 0.3 ) + # 上方正态曲线:Metric1 geom_line( data = filter(norm_curve_data, met == 'Metric1'), aes(x = x, y = y, color = met), linewidth = 1 ) + # 下方正态曲线:Metric12(y取反) geom_line( data = filter(norm_curve_data, met == 'Metric12'), aes(x = x, y = -y, color = met), linewidth = 1 ) + coord_cartesian(xlim = c(-10, 10)) + scale_color_manual(values = c('Metric1' = 'red', 'Metric12' = 'blue')) + labs(color = '分组')
关键修正点说明
- 修正分组名称:把
Metric2改为数据中存在的Metric12,解决空子集问题。 - 替换管道符号:将
%>%改为标准的%>%,确保管道逻辑正常运行。 - 生成贴合数据的拟合曲线:用
group_by()+summarise()为每个分组计算均值、标准差,传入dnorm()生成对应拟合曲线,而非默认的标准正态分布。 - 优化代码结构:提前生成曲线数据,避免重复提取子集,同时用分组名映射颜色,自动生成清晰图例。
内容的提问来源于stack exchange,提问作者Bogaso
相关产品推荐
相关产品推荐

