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

如何用ggplot创建双y轴并列柱状图?解决刻度差异问题

解决ggplot双y轴并列柱状图的问题

1. 实现并列柱形:数据转长格式

你当前的柱形重叠问题,根源是用两个独立geom_col图层叠加,position="dodge"只对同一图层内的分组生效。正确做法是把宽格式数据转成长格式,让变量名作为分组依据,用单个geom_col实现并列效果。

用tidyr::pivot_longer重塑数据:

library(tidyverse)

# 计算各物种的均值(与你原代码逻辑一致)
irissum <- iris %>%
  group_by(Species) %>%
  summarise(across(everything(), mean))

# 转成长格式:保留Species列,将其余列转为"变量名-数值"的键值对
irissum_long <- irissum %>%
  pivot_longer(cols = -Species, names_to = "Metric", values_to = "Value")

# 绘制仅包含Petal相关变量的并列柱状图
ggplot(irissum_long %>% filter(str_detect(Metric, "Petal")), 
       aes(x = Species, y = Value, fill = Metric)) +
  geom_col(position = position_dodge(width = 0.8), width = 0.7) +
  scale_fill_manual(values = c("Petal.Width" = "blue", "Petal.Length" = "red")) +
  labs(x = "物种", y = "数值", fill = "花瓣指标")

这样每个物种对应的两个柱形就会并列显示,不会重叠。

2. 处理刻度差异极大的双y轴需求

如果真实数据的两个变量刻度差异悬殊,trans参数无法匹配时,需要手动缩放其中一个变量,再对应调整次轴的转换逻辑。比如Petal.Width数值远小于Petal.Length,可以先给Petal.Width乘以一个缩放系数(比如3,根据你的数据范围调整),让它的数值范围与Petal.Length接近,再给次轴设置反向缩放(除以系数)还原真实刻度。

示例代码:

# 定义缩放系数(需根据你的真实数据范围调整)
scale_factor <- 3

# 预处理数据:对Petal.Width进行缩放
irissum_adjusted <- irissum %>%
  mutate(Petal.Width_scaled = Petal.Width * scale_factor)

ggplot(irissum_adjusted, aes(x = Species)) +
  # 绘制缩放后的Petal.Width
  geom_col(aes(y = Petal.Width_scaled), fill = "blue", 
           position = position_dodge(width = 0.8), width = 0.35) +
  # 绘制原始的Petal.Length
  geom_col(aes(y = Petal.Length), fill = "red", 
           position = position_dodge(width = 0.8), width = 0.35) +
  # 配置主、次y轴
  scale_y_continuous(
    name = "花瓣宽度",
    # 主轴刻度显示Petal.Width的真实值
    breaks = seq(0, max(irissum$Petal.Width), by = 0.5),
    labels = seq(0, max(irissum$Petal.Width), by = 0.5),
    expand = c(0, 0),
    # 次轴反向缩放,显示Petal.Length的真实值
    sec.axis = sec_axis(
      trans = ~ . / scale_factor,
      name = "花瓣长度",
      breaks = seq(0, max(irissum$Petal.Length), by = 1),
      labels = seq(0, max(irissum$Petal.Length), by = 1)
    )
  ) +
  theme_minimal()

额外建议:优先选择分面图替代双y轴

ggplot官方不推荐使用双y轴,因为容易误导读者。如果业务允许,优先用分面图展示不同刻度的变量,可读性更强:

ggplot(irissum_long %>% filter(str_detect(Metric, "Petal")), 
       aes(x = Species, y = Value, fill = Metric)) +
  geom_col() +
  facet_wrap(~Metric, scales = "free_y") +
  scale_fill_manual(values = c("Petal.Width" = "blue", "Petal.Length" = "red"))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 20:56:18