如何用ggplot2绘制密度与ECDF同图、校正坐标轴并生成局部放大图?
我来帮你搞定这个ggplot2的问题!你的代码里坐标轴缩放逻辑有点小偏差,而且局部放大图可以用patchwork包轻松实现,下面是一步步的解决方案:
1. 修正坐标轴缩放逻辑
首先得理清缩放关系:我们需要让密度曲线的最大值(比如你的数据里约0.4)对应ECDF的最大值1,所以得先算出密度的最大y值,再用1 / 最大密度值作为缩放因子——这样密度的最大值乘以这个因子就等于1,刚好和ECDF的最大值匹配。
先准备好数据和计算缩放因子:
library(ggplot2) library(patchwork) # 用来组合主图和放大图 set.seed(101) # 生成数据,直接构造数据框比melt更清晰 var1 = rnorm(1000, 0.5) var2 = rnorm(100000, 0.5) combine = data.frame( value = c(var1, var2), variable = rep(c("var1", "var2"), c(length(var1), length(var2))) ) # 计算两条密度曲线的最大y值,作为缩放基准 max_density <- max(density(var1)$y, density(var2)$y) scale_factor <- 1 / max_density # 密度最大值*这个因子=1,对应ECDF最大值
然后绘制修正后的主图:
main_plot <- ggplot(data = combine) + # 绘制密度曲线 geom_density(aes(x = value, color = variable), alpha = 0.2) + # 绘制ECDF,注意要把ECDF的y值(0-1)乘以缩放因子,让它和密度的y范围匹配 stat_ecdf(aes(x = value, color = variable, y = after_stat(y) * scale_factor)) + # 设置双坐标轴:左轴是密度,右轴把缩放后的ECDF值转换回0-1范围 scale_y_continuous( name = "Density", limits = c(0, max_density), # 左轴固定在0到密度最大值 sec.axis = sec_axis( ~ . / scale_factor, # 反向缩放,还原ECDF的0-1范围 name = "ECDF" ) ) + ggtitle("Density and ECDF Plot") + theme_bw() + theme( plot.title = element_text(size = 14, family = "Tahoma", face = "bold"), text = element_text(size = 12, family = "Tahoma") ) + scale_color_brewer(palette = "Accent") # 这里用color映射,所以对应scale_color_brewer
这样左Y轴就会是0到约0.4的密度范围,右Y轴是0到1的ECDF范围,而且两者的最大值完全对应上了。
2. 绘制右上25%区域的局部放大图
先筛选出右上25%的数据(也就是x值大于75%分位数的部分),然后用同样的逻辑绘制放大图:
# 计算x的75%分位数,确定右上25%的边界 x_75 <- quantile(combine$value, 0.75) # 过滤出右上25%的数据 combine_top25 <- subset(combine, value >= x_75) # 计算子集的密度最大值,重新生成缩放因子 max_density_top25 <- max( density(combine_top25$value[combine_top25$variable=="var1"])$y, density(combine_top25$value[combine_top25$variable=="var2"])$y ) scale_factor_top25 <- 1 / max_density_top25 # 绘制放大图 zoom_plot <- ggplot(data = combine_top25) + geom_density(aes(x = value, color = variable), alpha = 0.2) + stat_ecdf(aes(x = value, color = variable, y = after_stat(y) * scale_factor_top25)) + scale_y_continuous( name = "Density", limits = c(0, max_density_top25), sec.axis = sec_axis(~ . / scale_factor_top25, name = "ECDF") ) + ggtitle("Zoom: Top 25% of Values") + theme_bw() + theme( plot.title = element_text(size = 12, family = "Tahoma", face = "bold"), text = element_text(size = 10, family = "Tahoma") ) + scale_color_brewer(palette = "Accent")
3. 组合主图和放大图
用patchwork可以轻松把两个图组合起来,比如上下排列:
# 上下排列主图和放大图 main_plot / zoom_plot
如果想把放大图放在主图的右上角作为插入图,用inset_element更直观:
# 把放大图嵌入主图的右上角区域 main_plot + inset_element(zoom_plot, left = 0.6, bottom = 0.6, right = 0.98, top = 0.98)
这样你就能同时得到全范围的正确图表,以及右上25%的局部放大图啦!
内容的提问来源于stack exchange,提问作者user3978632
相关产品推荐
相关产品推荐

