使用R基于预计算频数与区间绘制带密度曲线的叠加直方图
问题
我是编程新手,首次提问若表述不够简洁还请见谅。我想要为3组样本(Vehicle、SB-3CT、SB-3CT + OVZ)的像素强度绘制叠加直方图,并为每组添加密度曲线,效果类似附图。
目前我没有原始数据,只有预计算好的直方图频数和区间:共64个区间,对应像素强度0-63,每个区间内包含三组的频数数据,数据结构如下:
# A tibble: 6 × 4 `Pixel intensity` Vehicle `SB-3CT` `SB-3CT + OVZ` <dbl> <dbl> <dbl> <dbl> 1 0 0.0896 0.0896 0.104 2 1 0.383 0.383 0.408 3 3 1.35 1.35 1.36 4 4 3.43 3.43 3.79 5 5 6.91 6.91 7.45 6 6 12.0 12.0 13.5
我曾尝试使用ggplot2.histogram函数,但由于是预计算数据,该函数只会计算频数的出现频率,不符合我的需求。请问能否使用ggplot2或类似工具实现我想要的绘图效果?
解决方法
1. 数据格式转换
ggplot2更适配长格式数据,先把你的宽格式数据转为长格式:
library(tidyverse) # 假设你的数据框名为pixel_data pixel_data_long <- pixel_data %>% pivot_longer( cols = -`Pixel intensity`, # 保留像素强度列,转换其他分组列 names_to = "Group", # 生成分组列的列名 values_to = "Frequency" # 生成频数列的列名 ) %>% # 计算每组的密度(将频数归一化) group_by(Group) %>% mutate(Density = Frequency / sum(Frequency)) %>% ungroup()
2. 绘制叠加直方图+密度曲线
用geom_area实现叠加的直方图效果,再用平滑曲线模拟密度曲线:
ggplot(pixel_data_long, aes(x = `Pixel intensity`)) + # 叠加直方图区域 geom_area( aes(y = Frequency, fill = Group), position = "identity", # 设置为叠加显示 alpha = 0.5, # 添加透明度避免分组遮挡 stat = "identity" # 使用预计算的频数,不重新统计 ) + # 绘制密度曲线(用loess平滑拟合频数趋势) geom_line( aes(y = Density * max(pixel_data$Frequency), color = Group), stat = "smooth", method = "loess", se = FALSE, size = 1 ) + # 设置双y轴:左侧显示频数,右侧显示密度 scale_y_continuous( name = "Frequency", sec.axis = sec_axis(~ . / max(pixel_data$Frequency), name = "Density") ) + # 设置标签和图例 labs( x = "Pixel intensity", fill = "Sample Group", color = "Sample Group" ) + theme_minimal()
关键说明
- 替代
geom_histogram:因为你有预计算的频数,geom_area可以直接使用现有数据绘制类似直方图的区域,不需要重新统计频数。 - 密度曲线适配:由于没有原始数据,用
loess平滑函数对频数趋势进行拟合,同时通过比例转换让曲线和直方图在同一坐标系显示,双y轴分别展示频数和密度。 - 柱状直方图替代:如果偏好柱状效果,可将
geom_area替换为geom_col(width = 1),同样设置position="identity"实现叠加。
内容的提问来源于stack exchange,提问作者user22915468
相关产品推荐
相关产品推荐

