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

R & ggplot2:用次Y轴实现100%堆叠柱状图+平均值折线图

解决ggplot2中100%堆叠柱状图+次Y轴平均值折线图的缩放问题

核心思路

100%堆叠柱的Y轴是0-100的百分比区间,而观测平均值的量级通常远大于这个范围,必须先把平均值线性缩放到0-100区间,再通过次Y轴反向转换回原始数值,才能让两个图层都正常显示。

示例数据(模拟你的场景)

set.seed(123)
df <- data.frame(
  category = rep(c("A", "B", "C", "D"), each = 3),
  group = rep(c("X", "Y", "Z"), 4),
  value = sample(10:50, 12, replace = TRUE),
  avg_value = rep(c(120, 90, 150, 110), each = 3) # 每组的观测平均值
)

正确实现代码

library(ggplot2)
library(dplyr)

# 计算堆叠柱的百分比(自动处理100%堆叠)
df <- df %>%
  group_by(category) %>%
  mutate(percent = value / sum(value) * 100) %>%
  ungroup()

# 计算缩放因子:把平均值的最大值映射到100(百分比轴的上限)
scale_factor <- max(df$avg_value) / 100
# 对平均值做缩放,适配百分比轴范围
df$scaled_avg <- df$avg_value / scale_factor

# 绘图
ggplot(df, aes(x = category)) +
  # 100%堆叠柱状图
  geom_col(aes(y = percent, fill = group), position = "fill") +
  # 叠加缩放后的平均值折线+点
  geom_line(aes(y = scaled_avg, group = 1), color = "#ff4d4d", size = 1.2) +
  geom_point(aes(y = scaled_avg), color = "#ff4d4d", size = 2) +
  # 设置双Y轴
  scale_y_continuous(
    name = "占比",
    labels = function(x) paste0(x, "%"),
    # 次Y轴:把缩放后的值转回到原始平均值
    sec.axis = sec_axis(
      trans = ~ . * scale_factor,
      name = "观测平均值"
    )
  ) +
  labs(fill = "分组", x = "类别") +
  theme_minimal()

关键细节说明

  1. 100%堆叠柱的实现:用position = "fill"可以自动把每组的数值转换为百分比,不需要手动计算总和再除法(手动计算也可,效果一致)。
  2. 缩放逻辑:用平均值的最大值除以100得到缩放因子,确保最大的平均值刚好对应百分比轴的100%位置,避免折线被压缩或超出图表范围。
  3. 次Y轴转换:通过sec_axis的trans参数反向计算,把缩放后的数值还原为原始平均值,这样次Y轴显示的就是真实的平均数值。
  4. Power BI适配:在Power BI的R视觉中使用时,要先在代码开头加载ggplot2和dplyr包,同时确保数据的分组列(category、group)是文本/因子类型,避免排序混乱。

内容的提问来源于stack exchange,提问作者KRH

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:57:35