You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:41:27