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

ggplot求助:geom_line用sec_axis反转刻度+geom_rect不显示

问题修复方案

1. 解决geom_rect不显示的问题

你的df_rect按Date分组后,每个日期的x1和x2完全相同,导致矩形宽度为0,自然无法显示。需要按连续的相同相位分组,合并同相位的时间段:

# 加载data.table用于识别连续相同的phase(也可以用dplyr实现)
library(data.table)
df_rect <- enso_data %>%
  # 给连续相同的phase分配同一个组ID
  mutate(group_id = rleid(phase)) %>%
  group_by(group_id, phase) %>%
  summarize(x1 = first(Date), 
            x2 = last(Date), 
            .groups = "drop")

这样每个矩形会覆盖一段连续的同相位时间区间,就能正常显示了。

2. 添加反转刻度的次坐标轴

要给geom_line设置反转的次坐标轴,需要先将index的值映射到主y轴(Percentage的0-100范围),再通过sec_axis定义逆变换并反转刻度:

完整修改后的代码

library(rsoi)
library(dplyr)
library(ggplot2)
library(data.table)

# 生成dummy数据
dummy <- data.frame(Date = seq(as.Date("1981-01-01"), as.Date("2010-12-01"), by = "month"),
                    Percentage = runif(360, min = 0, max = 100))
dummy$index <- runif(360, min = -1, max =1)

# 下载并处理ENSO数据
enso <- rsoi::download_oni()
enso_data <- enso %>% 
  filter(Year >=1981 & Year <=2010) %>%
  mutate(Date = as.Date(Date)) %>%
  arrange(Date)

# 修复geom_rect的分组逻辑:按连续相同phase合并时间段
df_rect <- enso_data %>%
  mutate(group_id = rleid(phase)) %>%
  group_by(group_id, phase) %>%
  summarize(x1 = first(Date), 
            x2 = last(Date), 
            .groups = "drop")

# 绘图
ggplot(data=dummy, aes(x=Date))+
  # 主坐标轴:柱形图
  geom_col(aes(y=Percentage)) +
  # 次坐标轴:折线图,先将index映射到主y轴范围(0-100)
  geom_line(aes(y = scales::rescale(index, to = c(0, 100))), col = "red")+ 
  # 矩形层:使用修复后的df_rect,ymin/ymax设为主y轴的全范围
  geom_rect(aes(xmin=x1, xmax=x2, fill=phase),
            ymin=0, ymax=100,  # 直接用固定值更可靠
            alpha=0.2, data=df_rect, inherit.aes=F)+
  # 设置主y轴和反转的次y轴
  scale_y_continuous(
    name = "Area (%)",
    # 定义次坐标轴:逆变换回index的范围,并反转刻度
    sec.axis = sec_axis(
      trans = ~ scales::rescale(., from = c(0, 100), to = c(1, -1)),  # 反转范围:1→0,-1→100
      name = "Index"
    )
  )+
  scale_x_date(date_breaks = "1 year", date_labels = "%Y") +
  labs(x= " ") +
  coord_cartesian(expand=F) +
  theme_minimal() %+replace% theme(legend.position="bottom")

关键说明

  • 折线图的y用scales::rescale(index, to = c(0, 100))将index(-1到1)映射到主y轴的0-100范围,保证折线和柱形在同一坐标系对齐。
  • 次坐标轴通过sec_axis的trans参数实现逆变换,同时将输出范围设为c(1, -1),实现刻度反转(原本的1在顶部,-1在底部,反转后1在底部,-1在顶部)。
  • geom_rect的ymin和ymax直接用0和100,避免依赖min(dummy$Percentage)和max(dummy$Percentage)可能出现的边界问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 02:28:27