使用geom_rect绘制颜色占比矩形并叠加geom_line展示观测总数
解决方案:用
geom_rect展示月度颜色占比 + 叠加总观测数折线 核心思路
要实现geom_rect的堆叠效果,需要先把宽格式的占比数据转成长格式,再计算每个颜色区块的上下边界(ymin/ymax)和左右边界(xmin/xmax),最后合并总观测数数据完成绘图。
步骤1:构造示例数据(模拟你的两个数据框)
先模拟你提到的两个数据结构,方便后续演示:
# 颜色月度占比数据框(宽格式) color_proportions <- data.frame( month = seq.Date(as.Date("2023-01-01"), as.Date("2023-06-01"), by = "month"), orange = c(0.2, 0.3, 0.25, 0.15, 0.3, 0.28), red = c(0.3, 0.25, 0.2, 0.3, 0.2, 0.22), green = c(0.25, 0.2, 0.3, 0.25, 0.25, 0.25), yellow = c(0.25, 0.25, 0.25, 0.3, 0.25, 0.25) ) # 月度总观测数数据框 total_observations <- data.frame( month = seq.Date(as.Date("2023-01-01"), as.Date("2023-06-01"), by = "month"), total = c(100, 120, 150, 130, 160, 140) )
步骤2:处理占比数据,生成矩形边界参数
geom_rect需要每个区块的xmin/xmax(月份区间)和ymin/ymax(占比/观测数区间),所以要先做数据转换:
library(tidyverse) # 1. 宽格式转长格式,方便按颜色分组 color_long <- color_proportions %>% pivot_longer(cols = -month, names_to = "color", values_to = "proportion") %>% arrange(month, color) # 固定颜色排序,保证堆叠顺序一致 # 2. 计算每个颜色的上下边界(累计占比) color_long <- color_long %>% group_by(month) %>% mutate( ymin = lag(cumsum(proportion), default = 0), # 上边界:前面所有颜色占比之和 ymax = cumsum(proportion) # 下边界:到当前颜色的累计占比 ) %>% ungroup() # 3. 计算每个月份的左右边界(覆盖整个月的时间区间) color_long <- color_long %>% group_by(month) %>% mutate( xmin = month, xmax = lead(month, default = last(month) + months(1)) # 下一个月的日期作为右边界 ) %>% ungroup()
步骤3:绘图(两种可选方案)
方案1:用实际观测数作为Y轴(推荐,无双轴问题)
把占比转换成实际观测数,让矩形和折线共用同一Y轴,更直观:
library(ggplot2) # 合并总观测数,转换占比为实际观测数 color_long <- color_long %>% left_join(total_observations, by = "month") %>% mutate( ymin_actual = ymin * total, ymax_actual = ymax * total ) # 绘图 ggplot() + # 绘制颜色矩形区块 geom_rect(data = color_long, aes(xmin = xmin, xmax = xmax, ymin = ymin_actual, ymax = ymax_actual, fill = color), color = "white") + # 白色边框区分不同颜色 # 绘制总观测数折线+点 geom_line(data = total_observations, aes(x = month, y = total), color = "black", linewidth = 1) + geom_point(data = total_observations, aes(x = month, y = total), color = "black", size = 2) + # 指定颜色填充值 scale_fill_manual(values = c(orange = "#FFA500", red = "#FF0000", green = "#008000", yellow = "#FFFF00")) + # 坐标轴与图例标签 labs(x = "月份", y = "观测数", fill = "颜色") + # 简约主题 theme_minimal()
方案2:用占比作为Y轴,叠加总观测数双轴
如果需要保留占比Y轴,可通过缩放总观测数实现双轴(注意:双轴可能带来视觉误导,谨慎使用):
# 计算缩放比例,让总观测数适配0-1的占比轴 max_total <- max(total_observations$total) scale_factor <- 1 / max_total ggplot() + geom_rect(data = color_long, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = color), color = "white") + geom_line(data = total_observations, aes(x = month, y = total * scale_factor), color = "black", linewidth = 1) + geom_point(data = total_observations, aes(x = month, y = total * scale_factor), color = "black", size = 2) + scale_fill_manual(values = c(orange = "#FFA500", red = "#FF0000", green = "#008000", yellow = "#FFFF00")) + # 设置双Y轴 scale_y_continuous( name = "颜色占比", sec.axis = sec_axis(~ . / scale_factor, name = "总观测数") ) + labs(x = "月份", fill = "颜色") + theme_minimal()
内容的提问来源于stack exchange,提问作者Daniel AG
相关产品推荐
相关产品推荐

