如何在ggplot中将年份作为副轴显示在月份主X轴下方?
解决ggplot X轴年份分组标注问题
问题分析
原代码中sec_axis的用法有误,sec_axis的设计目的是创建基于主轴转换的副轴(如单位转换),无法实现“每个年份仅显示一次,对应其所有月份”的分组标注需求。以下是正确的实现方案:
步骤1:清理数据
先移除含缺失值的行,避免绘图异常:
df_clean <- df[!is.na(df$media), ]
步骤2:计算年份在X轴的中间位置
用dplyr计算每个年份对应的X轴中点,确保年份标签居中显示:
library(dplyr) year_positions <- df_clean %>% group_by(year) %>% summarize(x_mid = mean(as.numeric(cycle_rounded))) %>% mutate(x_mid = as.POSIXct(x_mid, origin = "1970-01-01", tz = "UTC"))
步骤3:绘制图表并添加年份标注
通过annotate在主X轴(月份)下方添加年份标签,替代错误的sec_axis用法:
library(ggplot2) ggplot(df_clean, aes(x = cycle_rounded, y = media)) + # 绘制误差带 geom_ribbon(aes(ymin = media - desvio, ymax = media + desvio), alpha = .2, fill = "red") + # 绘制折线和点 geom_line(col = "grey10", linewidth = .5) + geom_point(col = "grey10", size = 1) + # 主X轴显示月份 scale_x_datetime(date_labels = "%m", breaks = "1 month") + # 添加年份标签到X轴下方 annotate("text", x = year_positions$x_mid, y = min(df_clean$media, na.rm = TRUE) - 0.8, label = year_positions$year, size = 4, color = "black") + # 可选:添加年份分隔线,增强视觉区分 annotate("segment", x = as.POSIXct("2020-10-01", tz = "UTC"), xend = as.POSIXct("2020-11-30", tz = "UTC"), y = min(df_clean$media, na.rm = TRUE) - 0.4, yend = min(df_clean$media, na.rm = TRUE) - 0.4, color = "black") + annotate("segment", x = as.POSIXct("2020-12-01", tz = "UTC"), xend = as.POSIXct("2021-12-31", tz = "UTC"), y = min(df_clean$media, na.rm = TRUE) - 0.4, yend = min(df_clean$media, na.rm = TRUE) - 0.4, color = "black") + annotate("segment", x = as.POSIXct("2022-01-01", tz = "UTC"), xend = as.POSIXct("2022-04-30", tz = "UTC"), y = min(df_clean$media, na.rm = TRUE) - 0.4, yend = min(df_clean$media, na.rm = TRUE) - 0.4, color = "black") + # 设置标签 labs(x = "data", y = "temperatura") + # 调整主题,确保年份标签不被裁剪 theme_classic() + theme( axis.text.x = element_text(size = 12, angle = 45, vjust = 1, hjust = 1, color = "black"), axis.text.y = element_text(size = 12, color = "black"), axis.title.x = element_text(size = 14, color = "black", margin = margin(t = 20)), axis.title.y = element_text(size = 14, color = "black"), plot.margin = margin(b = 20, t = 10, l = 10, r = 10) )
关键说明
- 放弃错误的
sec_axis用法,改用annotate直接添加分组标签,更贴合“年份对应月份范围”的需求。 - 通过调整
theme中的边距参数,避免年份标签被图表边界裁剪。 - 可选的分隔线可根据需求移除,仅保留年份标签即可。
内容的提问来源于stack exchange,提问作者Wilson Souza
相关产品推荐
相关产品推荐

