R中如何绘制含堆叠+闪避效果的ggplot2三变量柱状图
ggplot2 分组堆叠百分比柱状图实现方案
需求说明
需要绘制满足以下规则的柱状图:
- 柱形采用堆叠形式,单根柱子内不同认同态度的占比累加为100%
- X轴为年份维度,同一年份下并列排布3类汽车的柱子,方便横向对比
- 每个汽车类型对应专属主色系,单类汽车的堆叠块使用同色系3种深浅,分别代表「同意/中立/不同意」三类燃油效率感知态度
示例数据
Year <- c(rep(2012, 9), rep(2013, 9), rep(2014, 9)) Car <- rep(c(rep("A", 3), rep("B",3), rep("C",3)),3) FuelEfficient <- rep(c("Agree", "Neither", "Disagree"),9) Perception <- c(0.1, 0.3, 0.6, 0.2, 0.3, 0.5, 0.4, 0.1, 0.5, 0.2, 0.4, 0.4, 0.1, 0.3, 0.6, 0.2, 0.3, 0.5, 0.4, 0.1, 0.5, 0.7, 0.1, 0.2, 0.2, 0.6, 0.2) df <- data.frame(Year, Car, FuelEfficient, Perception)
原有代码问题
- 第一版代码直接在
aes()内传入dodge=Car是无效参数,闪避逻辑需要在位置函数内配置,因此所有柱子会在同一年份下叠在一起,无法实现同时间点跨车型对比 - 第二版手动拼接年份和车型为X轴标签的方案,将车型绑定到了X轴分类上,无法实现按车型分配独立主色系的映射逻辑
完整实现代码
library(ggplot2) # 固定态度的堆叠顺序,避免不同年份色块顺序错乱 df$FuelEfficient <- factor(df$FuelEfficient, levels = c("Disagree", "Neither", "Agree")) ggplot(df, aes( x = factor(Year), y = Perception, group = Car, # 按车型分组实现闪避 fill = interaction(Car, FuelEfficient, lex.order = TRUE) # 填充色映射为车型+态度的组合 )) + geom_col( width = 0.7, # 核心配置:百分比堆叠同时设置闪避宽度,实现组间并排、组内堆叠 position = position_fill(dodge = 0.8) ) + # 手动配置配色:同车型为同色系,按深浅对应不同态度 scale_fill_manual( values = c( # 车型A 橙色系 "#d95f02", "#fc8d62", "#ffb79c", # 车型B 紫色系 "#7570b3", "#8da0cb", "#b7c7ed", # 车型C 绿色系 "#1b9e77", "#66c2a5", "#bff5e4" ), name = "燃油效率感知", labels = rep(c("不同意", "中立", "同意"), 3) ) + # 可选:添加色块内百分比标签 geom_text( aes(label = scales::percent(Perception, accuracy = 1)), position = position_fill(vjust = 0.5, dodge = 0.8), size = 3 ) + labs(x = "年份", y = "占比") + scale_y_continuous(labels = scales::percent) + theme_minimal()
代码说明
- 不需要手动拼接X轴标签,直接使用
position_fill(dodge = 宽度参数)即可同时实现「组内百分比堆叠+组间并排闪避」的效果 - 配色顺序和
interaction()生成的因子顺序严格对应,保证同车型色块属于同一色系,不会出现颜色错配 - 将态度变量转为有序因子,可以固定每个柱子内部色块的上下顺序,可视化逻辑更统一
内容的提问来源于stack exchange,提问作者Toni
相关产品推荐
相关产品推荐

