如何在R的ggplot2中实现多数据独立比例的双Y轴绘图?
问题描述
现有时间序列数据框herbs,包含日期列date、降水量列SUM_PP,以及两个NDVI信号列h_fspec_NDVI和h_L_NDVI。需要绘制以date为X轴的图表:
- 左Y轴展示降水量
SUM_PP - 右Y轴独立适配两个NDVI信号的数值范围
当前使用ggplot2的代码如下,但无法实现双Y轴独立适配,两个Y轴始终线性关联:
meteo_spec <- ggplot(herbs) + geom_bar(aes(x=date, y=SUM_PP),stat="identity", fill="cyan",colour="#006000")+ geom_line(aes(x=date, y=100*h_fspec_NDVI),stat="identity",color="red",size=1)+ geom_line(aes(x=date, y=100*h_L_NDVI), stat = "identity", colour="black",size=1)+ labs(title= "NDVI vs Precipitation", x="TIME",y="PP")+ scale_y_continuous(sec.axis=sec_axis(~.*0.01,name="NDVI")) + scale_y_continuous(sec.axis=sec_axis(~.*0.01,name="NDVI")) meteo_spec
问题核心:
- 重复调用
scale_y_continuous会覆盖之前设置,仅最后一次生效 - ggplot2的双Y轴本质是基于主Y轴的线性转换,固定缩放比例会强制两个轴关联,无法各自适配数据范围
解决方案
通过手动计算数据范围的缩放因子,将NDVI数据映射到主Y轴(降水量)的数值区间内,再通过sec_axis做逆转换,实现双Y轴独立适配各自数据:
步骤1:计算缩放参数
# 获取降水量的数值范围 pp_range <- range(herbs$SUM_PP, na.rm = TRUE) # 获取两个NDVI信号的合并数值范围 ndvi_range <- range(c(herbs$h_fspec_NDVI, herbs$h_L_NDVI), na.rm = TRUE) # 计算缩放因子:将NDVI范围映射到降水量范围的比例 scale_factor <- diff(pp_range) / diff(ndvi_range) # 计算偏移量:确保NDVI数据映射后完全落入降水量的数值区间 offset <- pp_range[1] - ndvi_range[1] * scale_factor
步骤2:绘制双Y轴图表
meteo_spec <- ggplot(herbs) + # 绘制降水量柱状图(主Y轴) geom_bar(aes(x = date, y = SUM_PP), stat = "identity", fill = "cyan", colour = "#006000") + # 绘制转换后的NDVI折线(映射到主Y轴范围) geom_line(aes(x = date, y = h_fspec_NDVI * scale_factor + offset), color = "red", size = 1) + geom_line(aes(x = date, y = h_L_NDVI * scale_factor + offset), color = "black", size = 1) + # 设置坐标轴标签 labs(title = "NDVI vs Precipitation", x = "TIME", y = "Precipitation (PP)") + # 配置主Y轴和次Y轴(次Y轴做逆转换还原NDVI原始值) scale_y_continuous( sec.axis = sec_axis( ~ (. - offset) / scale_factor, name = "NDVI" ) ) + theme_minimal() meteo_spec
代码说明
- 先将NDVI数据通过
scale_factor和offset映射到降水量的数值区间,确保折线能在主Y轴坐标系中正确显示 - 次Y轴通过
~ (. - offset) / scale_factor做逆转换,将主Y轴数值还原为NDVI原始范围,实现双Y轴各自适配数据 - 仅需一次调用
scale_y_continuous完成主、次Y轴配置
内容的提问来源于stack exchange,提问作者Cláudio Siva
相关产品推荐
相关产品推荐

