如何在ggplot2的geom_histogram中使同fill类别子组堆叠展示?
问题描述
我想要创建一个直方图,使用数据集的一列作为填充色(fill),另一列作为分组(group),两者均在aes()中定义,并为每个组添加白色边框,且组的数量多于填充类别。
问题在于,定义group后,同一fill类别下的子组并未在条形中堆叠在一起,而是呈现随机排列。尝试在传入ggplot()前按fill列对data.frame排序,但并未解决问题。
需求:即使子组不同、x轴日期不同,同一fill类别的观测仍能堆叠在一起。
示例数据
# Set seed for reproducibility: set.seed(123) # Set start date: start_date <- as.Date("2024-01-01") # Set end date: end_date <- as.Date("2024-04-01") # Create data.frame: data <- data.frame( onset_date = sample(seq(start_date, end_date, by = "day"), 100, replace = TRUE), category = sample(c("A", "B"), 100, replace = TRUE)) # Add row names for grouping: data$grouping <- as.numeric(row.names(data)) # Create epicurve_breaks epicurve_breaks <- seq.Date( from = start_date, to = end_date, by = "week")
问题现象
- 无分组的直方图(
geom_histogram仅设置fill = category):同一fill类别的元素会正常堆叠。 - 添加
group = grouping后的直方图:category A和B的区块随机分散,无法聚集。
解决方法
核心原因是直接设置group = grouping会将每一行视为独立分组,打乱了ggplot默认按fill堆叠的逻辑。要实现同类别子组聚集+每个子组带白色边框,推荐先预处理数据,再用geom_bar替代geom_histogram,具体如下:
步骤1:预处理数据
先将日期映射到指定的周区间,同时按区间和类别排序,确保同类别子组排列在一起:
library(dplyr) library(ggplot2) # 为每条数据分配对应的周区间 data$interval <- cut(data$onset_date, breaks = epicurve_breaks, closed = "left", include.lowest = TRUE) # 按区间、类别排序,保证同类别子组在堆叠时聚集 data_sorted <- data %>% arrange(interval, category, grouping)
步骤2:绘制堆叠直方图
使用geom_bar的position = "stack"参数,结合排序后的数据实现需求:
p3 <- ggplot(data_sorted, aes(x = interval, fill = category, group = grouping)) + geom_bar(position = "stack", colour = "white") + # 简化x轴日期标签,只显示起始日期 scale_x_discrete(labels = function(x) substr(x, 1, 10)) + labs(x = "Onset Date") print(p3)
替代方案(用geom_histogram实现)
如果坚持使用geom_histogram,可以将group设置为interaction(category, grouping),同时确保数据按category排序,让同类别子组优先聚合:
# 先按category排序 data_sorted <- data %>% arrange(category) p4 <- ggplot(data_sorted, aes(x = onset_date, fill = category, group = interaction(category, grouping))) + geom_histogram(breaks = epicurve_breaks, closed = 'left', colour = "white") print(p4)
内容的提问来源于stack exchange,提问作者Amy M
相关产品推荐
相关产品推荐

