ggplot2堆叠柱状图:如何按日期排序、自定义颜色并修改图例
堆叠柱状图解决方案
核心需求
- 按
week分组,每星期一列;堆叠顺序为每周最早日期(周四)在底部,最晚日期(周三)在顶部; - 为每个
tp_code使用数据中定义的tp_color自定义颜色; - 图例以
tp_code作为标签。
数据集
session_df <- structure(list(date = structure(c(19570, 19571, 19572, 19573, 19574, 19575, 19576, 19577, 19578, 19579, 19580, 19581, 19582, 19583), class = "Date"), metric = c(2, 8, 12, 18, 6, 12, 20, 2, 6, 9, 7, 19, 4, 17), tp_code = c("Off", "ReEntry", "Strength", "Match 1", "Recovery", "Activation", "Match 2", "Off", "Strength", "Speed", "Activation", "Match 1", "ReEntry-Activation", "Match 2" ), week = structure(c(19566, 19566, 19566, 19573, 19573, 19573, 19573, 19573, 19573, 19573, 19580, 19580, 19580, 19580), class = "Date"), tp_color = c("grey", "lightgreen", "blue", "darkgreen", "chartreuse", "lightyellow", "darkgreen", "grey", "blue", "yellow", "lightyellow", "darkgreen", "lightgreen", "darkgreen")), row.names = c(NA, -14L), class = c("tbl_df", "tbl", "data.frame"))
问题根源
之前的尝试要么将fill映射到date导致图例错误,要么映射到tp_code但使用全局因子水平控制堆叠,无法适配不同周内tp_code对应的日期顺序差异。ggplot的堆叠顺序默认由fill的因子水平决定,但我们需要按每个周内的日期顺序独立控制堆叠,同时保留tp_code作为填充映射以保证图例和颜色正确。
解决方案
步骤1:预处理数据,生成周内堆叠顺序标记
按周分组,对每个周内的行按日期升序排序,生成每个行在周内的堆叠顺序编号:
library(tidyverse) session_df_processed <- session_df %>% group_by(week) %>% arrange(date) %>% # 每周内按日期从早到晚(周四→周三)排序 mutate(stack_order = row_number()) %>% # 生成周内堆叠顺序编号,1为最早日期 ungroup() %>% # 保留tp_code的因子水平,确保颜色映射正确 mutate(tp_code = factor(tp_code, levels = distinct(session_df, tp_code, tp_color)$tp_code))
步骤2:绘制堆叠柱状图
通过group = stack_order指定堆叠顺序,同时保留fill = tp_code以保证图例和颜色正确:
# 提取tp_code与自定义颜色的映射关系 cols <- distinct(session_df, tp_code, tp_color) %>% deframe() session_df_processed %>% ggplot(aes(x = week, y = metric, fill = tp_code)) + geom_bar( stat = "identity", position = position_stack(reverse = FALSE), # reverse=FALSE让编号小的(最早日期)在底部 aes(group = stack_order) # 关键:按周内的stack_order控制堆叠顺序 ) + scale_fill_manual(values = cols) + # 应用自定义颜色 theme_minimal() + labs(x = "周", y = "指标值", fill = "训练类型")
效果验证
- 堆叠顺序:每个周内最早日期(周四)在底部,最晚日期(周三)在顶部;
- 颜色:每个
tp_code的颜色与数据中tp_color完全匹配; - 图例:显示
tp_code作为标签,清晰对应训练类型。
内容的提问来源于stack exchange,提问作者seansteele
相关产品推荐
相关产品推荐

