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

如何在ggplot分面箱线图中为指定箱线图添加双Y轴

分面内实现独立双Y轴的箱线图解决方案

针对你需要在每个分面(type 1/2/3)中将c类箱线图放在右侧独立Y轴、用颜色区分的需求,这里提供基于ggplot2的实现方案,保留你自定义的箱线图计算规则,同时让双轴范围适配各自数据:

核心思路

ggplot2本身不支持分面内的独立双轴,所以我们通过数据缩放的方式实现:

  • 对每个分面内的c类数据单独计算缩放系数,将其数值缩放到a/b类的范围内
  • 绘制a/b和c两类箱线图并设置不同颜色
  • 添加右侧Y轴,通过反转缩放系数将轴刻度转换回c类原始数值

完整代码实现

library(ggplot2)
library(dplyr)

# 生成示例数据
set.seed(123) # 设置随机种子保证结果可复现
a1 <- rnorm(n=100, mean=5, sd=20)
a2 <- rnorm(n=100, mean=6, sd=20)
a3 <- rnorm(n=100, mean=8, sd=20)
b <- rnorm(n=100, mean=11, sd=10)
c1 <- rnorm(n=100, mean=500, sd=80)
c2 <- rnorm(n=100, mean=600, sd=80)
c3 <- rnorm(n=100, mean=800, sd=80)

letters <- c(rep("a", 300), rep("b", 300), rep("c", 300))
type <- rep(c(rep(1,100), rep(2,100), rep(3,100)),3)
dat <- data.frame(y=c(a1,a2,a3,b,b,b,c1,c2,c3), letters, type)

# 自定义箱线图统计函数(保留你的逻辑)
f <- function(x) {
  r <- quantile(x, probs = c(0.05, 0.25, 0.5, 0.75, 0.95))
  names(r) <- c("ymin", "lower", "middle", "upper", "ymax")
  r
}
o <- function(x) {
  subset(x, x < quantile(x, 0.05) | quantile(x, 0.95) < x)
}

# 计算每个type下的缩放系数:将c类数据缩放到a/b类的数值范围
scale_factors <- dat %>%
  group_by(type) %>%
  summarise(
    a_b_max = max(y[letters %in% c("a", "b")]),
    c_max = max(y[letters == "c"]),
    scale = a_b_max / c_max # 缩放系数:c类原始值 * scale = 缩放到a/b范围的值
  )

# 将缩放系数合并到原始数据
dat_scaled <- dat %>%
  left_join(scale_factors, by = "type") %>%
  mutate(
    y_scaled = ifelse(letters == "c", y * scale, y) # 仅对c类数据做缩放
  )

# 绘制分面双轴箱线图
ggplot() +
  # 绘制a/b类箱线图和异常值点(左侧Y轴)
  stat_summary(
    data = filter(dat_scaled, letters %in% c("a", "b")),
    aes(x = letters, y = y_scaled, group = letters),
    fun.data = f, geom = "boxplot", fill = "#619CFF", color = "black"
  ) +
  stat_summary(
    data = filter(dat_scaled, letters %in% c("a", "b")),
    aes(x = letters, y = y_scaled, group = letters),
    fun = o, geom = "point", color = "#619CFF"
  ) +
  # 绘制c类箱线图和异常值点(右侧Y轴,已缩放)
  stat_summary(
    data = filter(dat_scaled, letters == "c"),
    aes(x = letters, y = y_scaled, group = letters),
    fun.data = f, geom = "boxplot", fill = "#F8766D", color = "black"
  ) +
  stat_summary(
    data = filter(dat_scaled, letters == "c"),
    aes(x = letters, y = y_scaled, group = letters),
    fun = o, geom = "point", color = "#F8766D"
  ) +
  # 设置分面,每个分面独立缩放轴范围
  facet_wrap(~type, nrow = 1, scales = "free_y") +
  # 设置Y轴:左侧为a/b原始值,右侧通过缩放系数转换回c原始值
  scale_y_continuous(
    name = "a/b类指标值",
    sec.axis = sec_axis(
      trans = ~./dat_scaled$scale[dat_scaled$type == unique(type)][1], # 每个分面用自己的缩放系数
      name = "c类指标值"
    )
  ) +
  # 调整主题和标签
  labs(x = "指标类型") +
  theme_bw() +
  theme(
    axis.title.y.right = element_text(color = "#F8766D"),
    axis.text.y.right = element_text(color = "#F8766D"),
    axis.title.y = element_text(color = "#619CFF"),
    axis.text.y = element_text(color = "#619CFF")
  )

关键细节说明

  • 分面独立缩放:通过facet_wrap(..., scales = "free_y")让每个分面的Y轴范围适配自身数据
  • 颜色区分:a/b类用蓝色,c类用红色,同时右侧轴文字也对应颜色,提升可读性
  • 缩放逻辑:每个type分组计算缩放系数,确保c类数据缩放后和同组a/b类在相近范围,右侧轴通过~./scale反转缩放,还原原始数值
  • 保留自定义统计:完全复用你定义的f和o函数,保证箱线图的计算规则不变

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:15:12