如何用ggplot2实现堆叠百分比柱状图与折线、散点图叠加及双Y轴设置?
解决ggplot2双Y轴堆叠百分比柱形图+折线+散点适配问题
核心思路
ggplot2没有原生支持独立双Y轴,必须手动将右侧均值数据映射到左侧百分比(0-100)的数值范围,再通过轴标签转换还原均值刻度。
步骤代码
1. 预处理数据(计算堆叠百分比)
假设你的数据集包含category(分类)、group(分组)、value(计数)、domain_mean(领域均值)、question_mean(问题均值)字段:
library(tidyverse) library(ggplot2) # 替换为你的实际数据集 df <- tibble( category = rep(c("维度1", "维度2", "维度3"), each=3), group = rep(c("满意", "一般", "不满意"), 3), value = sample(15:30, 9), domain_mean = sample(4.5:7.5, 9, replace=T), question_mean = sample(3.8:8.2, 9, replace=T) ) # 计算每组在分类内的堆叠百分比 df_percent <- df %>% group_by(category) %>% mutate(total = sum(value), percent = (value / total) * 100) %>% ungroup()
2. 计算均值到百分比的映射系数
根据你的均值实际范围,动态计算转换比例,避免硬编码:
# 获取所有均值的极值 mean_range <- range(c(df_percent$domain_mean, df_percent$question_mean)) mean_min <- mean_range[1] mean_max <- mean_range[2] # 转换系数:将均值范围拉伸到0-100 coeff <- 100 / (mean_max - mean_min) # 偏移量:让最小均值对应左侧轴的0点 shift <- -mean_min * coeff
3. 绘制复合图
ggplot(df_percent, aes(x = category)) + # 堆叠百分比柱形图 geom_col(aes(y = percent, fill = group), position = "stack", alpha = 0.8) + # domain_mean折线+点(使用转换后的值) geom_line(aes(y = (domain_mean + shift) * coeff, group = 1), color = "#E63946", size = 1.2) + geom_point(aes(y = (domain_mean + shift) * coeff), color = "#E63946", size = 3) + # question_mean散点(使用转换后的值) geom_point(aes(y = (question_mean + shift) * coeff), color = "#1D3557", size = 3.5, shape = 18) + # 配置双Y轴 scale_y_continuous( name = "占比 (%)", limits = c(0, 100), breaks = seq(0, 100, 20), # 右侧轴:将转换后的值还原为原始均值 sec.axis = sec_axis( trans = ~(. / coeff) - shift, name = "均值分数", breaks = seq(round(mean_min, 1), round(mean_max, 1), by = 0.5) ) ) + # 美化主题 labs(x = "评估维度", fill = "满意度分组") + theme_minimal() + theme( axis.title.y.right = element_text(color = "#1D3557"), axis.title.y = element_text(color = "#457B9D"), legend.position = "bottom" )
关键注意点
- 折线图必须指定
group=1,否则会按category拆分无法形成连续折线 - 转换系数必须基于实际数据的均值范围计算,否则会出现轴刻度错位
- 通过
sec_axis的trans参数反向转换刻度,还原均值的真实数值 - 用颜色区分不同图层元素,提升可读性
内容的提问来源于stack exchange,提问作者T K
相关产品推荐
相关产品推荐

