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
相关产品推荐
相关产品推荐

