如何在ggplot2中添加第三个次级Y轴以展示多类水文监测数据?
如何在ggplot2(兼容gganimate)中添加第三个Y轴展示浊度数据
ggplot2的sec_axis()仅支持添加一个次级Y轴,无法直接通过它实现第三个Y轴。但可以通过数据缩放+手动模拟轴元素的方式实现,同时兼容gganimate制作动画。
步骤1:预处理数据,计算浊度的缩放因子
为了让浊度数据适配主Y轴(流量)的显示范围,先计算缩放比例,将浊度值映射到流量的数值区间内:
# 加载所需包 library(lubridate) library(dplyr) library(ggplot2) library(gganimate) library(dataRetrieval) # 读取并清洗数据(沿用你的原有代码) siteNo <- "********" pCode <- c("00060","63680","00010") start.date <- "yyyy-mm-dd" end.date <- "yyyy-mm-dd" YS <- readNWISuv(siteNumbers = siteNo, parameterCd = pCode, startDate = start.date, endDate = end.date) YS <- renameNWISColumns(YS) YS <- YS %>% select(dateTime,Flow_Inst,Turb_Inst, Wtemp_Inst) # 计算浊度的缩放因子(基于流量和浊度的最大值) scale_turb <- max(YS$Flow_Inst, na.rm = TRUE) / max(YS$Turb_Inst, na.rm = TRUE) # 添加缩放后的浊度列 YS <- YS %>% mutate(Turb_scaled = Turb_Inst * scale_turb)
步骤2:修改ggplot代码,添加浊度图层并模拟第三个Y轴
在原有双Y轴代码基础上,添加浊度折线,再通过annotate()和theme()手动绘制第三个Y轴的刻度、标签和标题:
YSHG <- YS %>% ggplot(aes(x = dateTime)) + # 流量(主Y轴,蓝色) geom_line(aes(y = Flow_Inst, color = "Discharge")) + # 水温(缩放后对应第一个次级Y轴,红色) geom_line(aes(y = Wtemp_Inst * 3000, color = "Temperature")) + # 浊度(缩放后对应模拟的第三个Y轴,绿色) geom_line(aes(y = Turb_scaled, color = "Turbidity")) + # 主Y轴与第一个次级Y轴配置 scale_y_continuous( name = "Discharge (cfs)", sec.axis = sec_axis(~ ./3000, name = "Water Temperature (°C)"), # 确保Y轴范围覆盖所有缩放后的数据 limits = c(0, max(c(YS$Flow_Inst, YS$Wtemp_Inst*3000, YS$Turb_scaled), na.rm = TRUE)) ) + # 颜色与图例配置 scale_color_manual( values = c("Discharge" = "blue", "Temperature" = "red", "Turbidity" = "green"), name = "Parameter" ) + # 主题与轴样式调整 theme_classic() + theme( plot.background = element_blank(), panel.grid = element_blank(), panel.border = element_blank(), axis.line.x = element_line(color = "black"), # 主Y轴样式 axis.title.y.left = element_text(color = "blue"), axis.line.y.left = element_line(color = "blue"), # 第一个次级Y轴样式 axis.title.y.right = element_text(color = "red", margin = margin(l = 10)), axis.line.y.right = element_line(color = "red"), # 留出右侧空间放置第三个Y轴 plot.margin = margin(10, 80, 10, 10) ) + # 手动添加第三个Y轴的刻度线、标签和标题 annotate("segment", x = max(YS$dateTime), xend = max(YS$dateTime) + hours(6), y = seq(0, max(YS$Flow_Inst, na.rm = TRUE), length.out = 5), yend = seq(0, max(YS$Flow_Inst, na.rm = TRUE), length.out = 5), color = "green") + annotate("text", x = max(YS$dateTime) + days(1), y = seq(0, max(YS$Flow_Inst, na.rm = TRUE), length.out = 5), label = round(seq(0, max(YS$Turb_Inst, na.rm = TRUE), length.out = 5), 1), color = "green", hjust = 0) + annotate("text", x = max(YS$dateTime) + days(1), y = max(YS$Flow_Inst, na.rm = TRUE)/2, label = "Turbidity (NTU)", color = "green", hjust = 0, angle = 90) + labs(x = "Date", y = "Discharge (CFS)")
步骤3:添加gganimate动画
直接在上述ggplot对象基础上添加动画层,实现时间推进的演示效果:
# 制作时间推进动画 animated_plot <- YSHG + transition_time(dateTime) + labs(title = "Hydrological Data: {frame_time}") + ease_aes("linear") # 渲染动画(可调整fps和duration参数控制动画速度) animate(animated_plot, fps = 10, duration = 15)
注意事项
- 缩放因子需基于全局数据计算,避免动画过程中轴范围波动;
- 模拟的第三个Y轴是视觉层面的对齐,并非ggplot原生轴,需手动调整刻度位置和标签确保准确性;
- 如果浊度与流量数值范围差异极大,可改用对数转换调整缩放逻辑,保证数据可读性。
内容的提问来源于stack exchange,提问作者Parker Golliglee
相关产品推荐
相关产品推荐

