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

ggplot2分面图中实现各分面独立适配的次坐标轴

解决分面ggplot2中每个面板独立缩放次Y轴的问题

这个需求确实戳中了ggplot2原生功能的一个小局限——默认的sec_axis是全局统一的变换规则,没法给每个分面单独定制次坐标轴的缩放逻辑。不过我们可以通过数据线性缩放+分面自定义坐标轴的组合方法来实现你要的效果,下面是具体步骤和代码:

核心思路

  1. 先把每个分面的折线图数据(wind)线性缩放到主Y轴的固定范围(这里是0-30),这样折线就能占满每个分面的绘图高度;
  2. 再给每个分面单独设置次Y轴,通过反向变换把主Y轴的数值转换回wind的原始范围,实现每个分面次轴范围独立匹配自身数据。

具体实现代码

我们需要用到dplyr处理数据,ggh4x包来实现分面自定义坐标轴(这个包是ggplot2的常用扩展,专门解决这类分面定制问题)。

第一步:准备并转换数据

library(ggplot2)
library(dplyr)
library(ggh4x)

# 你的原始数据
temp <- data.frame(
  region = c("1", "1", "1", "1", "1", "2", "2", "2", "2", "2"),
  year = c(2010, 2011, 2012, 2013, 2014, 2010, 2011, 2012, 2013, 2014),
  temp = c(22, 23, 20, 17, 26, 21, 28, 19, 17, 22)
)
wind <- data.frame(
  region = c("1", "1", "1", "1", "1", "2", "2", "2", "2", "2"),
  year = c(2010, 2011, 2012, 2013, 2014, 2010, 2011, 2012, 2013, 2014),
  wind = c(112, 125, 124, 119, 108, 7, 3, 8, 5, 2)
)

# 计算每个region的wind范围,并将wind缩放到主Y轴0-30的区间
wind_scaled <- wind %>%
  group_by(region) %>%
  mutate(
    wind_min = min(wind),
    wind_max = max(wind),
    # 线性缩放公式:new_value = main_min + (value - data_min) * (main_max - main_min)/(data_max - data_min)
    wind_transformed = 0 + (wind - wind_min) * (30 - 0)/(wind_max - wind_min)
  ) %>%
  ungroup()

第二步:自动化生成分面坐标轴配置

为了避免手动输入每个region的wind范围,我们可以自动化生成每个分面的次轴规则:

# 提取每个region的wind参数
wind_params <- wind_scaled %>% distinct(region, wind_min, wind_max)

# 生成每个分面的Y轴配置列表
y_scales <- purrr::map2(
  wind_params$wind_min,
  wind_params$wind_max,
  function(min_w, max_w) {
    scale_y_continuous(
      sec.axis = sec_axis(
        # 反向转换回wind原始值:original_value = data_min + (main_value - main_min)*(data_max - data_min)/(main_max - main_min)
        ~ min_w + (. - 0)*(max_w - min_w)/(30 - 0),
        name = "wind"
      ),
      limits = c(0, 30),
      expand = c(0, 0)
    )
  }
)
names(y_scales) <- wind_params$region

第三步:绘制最终图形

ggplot() +
  # 主图:柱状图,使用原始temp数据
  geom_bar(data = temp, aes(year, temp, fill = region), stat = "identity") +
  # 折线图:使用缩放后的wind数据,匹配主Y轴高度
  geom_line(data = wind_scaled, aes(year, wind_transformed, color = region), linewidth = 1) +
  # 分面设置
  facet_wrap(~region, nrow = 2) +
  # 主Y轴固定为0-30
  scale_y_continuous(name = "temp", limits = c(0, 30), expand = c(0, 0)) +
  # 应用分面自定义的次坐标轴
  facetted_pos_scales(y = y_scales) +
  theme_minimal()

效果说明

运行后你会看到:

  • 两个分面的左侧主Y轴都是固定的0-30;
  • 第一个分面的右侧次Y轴范围是108-125(对应该region的wind极值);
  • 第二个分面的右侧次Y轴范围是2-8(对应该region的wind极值);
  • 每个分面的折线都完美占满了绘图区域的高度。

注意事项

  • 如果你的主Y轴范围不是固定值,而是每个分面自己的temp数据范围,只需要把主Y轴的min/max也按分面计算,再调整缩放公式即可;
  • ggh4x包需要先安装:install.packages("ggh4x")。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:03:32