ggplot2中stat_function与geom_col叠加异常问题求助
问题原因与解决方案
为什么蓝色线条会显示为f(x)=0?
这个问题我之前也碰到过,本质是ggplot的y轴自动适配逻辑在搞鬼:
- 当你添加
geom_col(color = "red")时,ggplot会自动把y轴范围设定为适配数据中quantity列的数值区间。 - 而你用
dgamma计算出的Gamma概率密度值,和quantity的数值量级差得特别大——比如你设置的alpha=1.2、beta=0.01,在x的常见取值范围内,dgamma的结果可能小到1e-6甚至更小,远小于quantity的数值。 - 这样一来,PDF曲线就被直接压缩到y轴的最底部,看起来就是一条和x轴重合的直线(也就是你看到的f(x)=0)。
实用解决方案
这里给你三种不同场景下的解决方法,你可以根据需求选择:
1. 使用双y轴(推荐,兼顾柱状图和PDF展示)
通过缩放PDF值,让它能和柱状图在同一坐标系下显示,同时添加第二个y轴还原原始PDF数值:
analyzeGamma <- function(csvPath, alpha, beta) { dfSamples <- read.csv(file = csvPath, header = TRUE, sep = ",") # 计算缩放因子:让PDF的最大值匹配quantity的最大值 x_seq <- seq(min(dfSamples$value), max(dfSamples$value), length.out = 1000) pdf_max <- max(dgamma(x_seq, shape = alpha, rate = beta)) quantity_max <- max(dfSamples$quantity) scale_factor <- quantity_max / pdf_max base <- ggplot(dfSamples, aes(x = value)) + geom_col(aes(y = quantity), color = "red") + geom_vline(xintercept = qgamma(seq(0.1, 0.9, by = 0.1), alpha, beta)) + stat_function( fun = function(x) dgamma(x, shape = alpha, rate = beta) * scale_factor, colour = "blue" ) + scale_y_continuous( name = "Sample Quantity", sec.axis = sec_axis(~ . / scale_factor, name = "Gamma Probability Density") ) return(base) }
2. 手动设置y轴范围(适合关注分布形状的场景)
如果你的重点是对比柱状图和PDF的分布形状,而非quantity的具体数值,可以手动扩展y轴范围以包含PDF的取值:
analyzeGamma <- function(csvPath, alpha, beta) { dfSamples <- read.csv(file = csvPath, header = TRUE, sep = ",") # 计算PDF的取值范围 x_range <- range(dfSamples$value) pdf_values <- dgamma(seq(x_range[1], x_range[2], length.out = 1000), alpha, beta) base <- ggplot(dfSamples, aes(x = value, y = quantity)) + geom_col(color = "red") + geom_vline(xintercept = qgamma(seq(0.1, 0.9, by = 0.1), alpha, beta)) + stat_function( fun = dgamma, args = list(shape = alpha, rate = beta), colour = "blue" ) + ylim(0, max(c(dfSamples$quantity, pdf_values))) return(base) }
注意:如果quantity远大于PDF值,柱状图会显得极高,PDF曲线依然很矮,视觉效果可能不够理想。
3. 拆分两个独立图表(最直观,无坐标轴冲突)
把柱状图和PDF曲线分成两个子图,各自使用合适的y轴:
library(gridExtra) # 需要先安装这个包:install.packages("gridExtra") analyzeGamma <- function(csvPath, alpha, beta) { dfSamples <- read.csv(file = csvPath, header = TRUE, sep = ",") # 柱状图 p_col <- ggplot(dfSamples, aes(x = value, y = quantity)) + geom_col(color = "red") + geom_vline(xintercept = qgamma(seq(0.1, 0.9, by = 0.1), alpha, beta)) + labs(title = "Sample Quantity Distribution", y = "Quantity") # PDF曲线 p_pdf <- ggplot(data.frame(x = seq(min(dfSamples$value), max(dfSamples$value), length.out = 1000)), aes(x = x)) + stat_function(fun = dgamma, args = list(shape = alpha, rate = beta), colour = "blue") + geom_vline(xintercept = qgamma(seq(0.1, 0.9, by = 0.1), alpha, beta)) + labs(title = "Gamma Probability Density Function", y = "Density") # 排列两个图 grid.arrange(p_col, p_pdf, ncol = 1) }
内容的提问来源于stack exchange,提问作者Gilad BA
相关产品推荐
相关产品推荐

