You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 09:50:17