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

如何用ggplot2叠加不同x轴范围的核密度图与单箱直方图?

解决ggplot2合并核密度图与0值单箱直方图的问题

我来帮你搞定这三个核心问题,同时调整图形比例让展示更合理:

问题拆解

你的需求是同时呈现两类数据的分布:

  • 数值>0部分的核密度估计曲线
  • 数值=0部分的单箱直方图
    但当前实现存在三个明显问题:
  1. 核密度线会沿整个x轴(包括0左侧的无效区域)绘制
  2. 直方图与核密度图的比例严重失调
  3. 调整核平滑因子时出现重复的密度线条

解决方案代码

values <- c(25.222222, 6.000000, 2.057143, 0.000000, 2.142857, 0.000000, 73.666667, 4.081081, 43.133333, 18.937500, 60.822222, 23.379310, 54.954412, 8.492308, 67.646250, 15.885000, 38.585859, 46.810606, 31.565152, 39.813889, 40.620000, 25.958000, 54.821429, 9.000000, 33.040476, 50.329670, 43.525641, 33.508696, 34.265385, 57.003544, 36.690434, 48.074074, 70.372222, 77.602564, 29.997436, 71.739683, 11.320000, 2.938776, 10.101562, 35.037956)
df <- data.frame(variable = "TH_part", value=values)

library(ggplot2)

# 提前计算非0数据量和直方图组距,用于y轴转换
n_nonzero <- nrow(subset(df, value != 0))
bin_width <- 10

ggplot() +
  # 绘制0值的单箱直方图,精准包裹0值
  geom_histogram(data = subset(df, value == 0),
                 aes(x = value, y = ..count..),
                 breaks = c(-5, 5),
                 fill = "#619CFF", alpha = 0.4) +
  # 绘制>0数据的核密度线,转换为计数刻度匹配直方图
  geom_density(data = subset(df, value != 0),
               aes(x = value, y = ..density.. * n_nonzero * bin_width),
               color = "#F8766D", adjust = 0.5, size = 1) +
  # 限制x轴显示范围,避免密度线延伸到无效区域
  coord_cartesian(xlim = c(-10, 200)) +
  # 调整坐标轴标签和主题
  labs(x = "Value", y = "Count") +
  theme_bw() +
  theme(legend.position = "none")

关键调整说明

1. 解决核密度线过度延伸

  • 用coord_cartesian(xlim = c(-10, 200))替代scale_x_continuous(limits = ...):前者只是限制显示范围,不会截断核密度的计算数据,同时避免密度线跑到0左侧的无效区域。
  • 给0值直方图设置breaks = c(-5,5),让箱子刚好包裹0值,不会出现多余的空箱子。

2. 解决比例失调问题

  • 将核密度的y轴从密度转换为计数:..density.. * n_nonzero * bin_width,其中:
    • n_nonzero是非0数据的总数量
    • bin_width是直方图的组距(这里设为10)
      这样核密度线的高度就能和直方图的计数刻度完全匹配,比例协调。

3. 解决重复核密度线问题

  • 以空的ggplot()为基础,分别给geom_histogram和geom_density指定独立的数据源,避免继承全局aes导致的重复绘制。
  • 单独给geom_density设置adjust = 0.5,不会出现重复线条。

可选方案:保留密度y轴

如果你需要用密度刻度而非计数,只需调整0值直方图的y轴计算逻辑:

ggplot() +
  geom_histogram(data = subset(df, value == 0),
                 aes(x = value, y = ..density..),
                 breaks = c(-5, 5),
                 fill = "#619CFF", alpha = 0.4) +
  geom_density(data = subset(df, value != 0),
               aes(x = value, y = ..density..),
               color = "#F8766D", adjust = 0.5, size = 1) +
  coord_cartesian(xlim = c(-10, 200)) +
  labs(x = "Value", y = "Density") +
  theme_bw() +
  theme(legend.position = "none")

这种情况下,0值箱子的密度是基于整个数据集计算的,能准确反映0值在整体中的占比。

内容的提问来源于stack exchange,提问作者karla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:01:07