ggplot2双Y轴多折线图绘制求助:两组变量各含两条折线
双Y轴折线图(ggplot2)问题解决
需求说明
需要用ggplot2绘制两组变量的折线图:
- 蒸散量(ET)的两条折线(
ET_IRRIGATION、ET_CONTROL)对应左Y轴,范围0-0.5 - 土壤湿度(SMOIS)的两条折线(
SMOIS_IRRIGATION、SMOIS_CONTROL)对应右Y轴,范围10-30
双Y轴刻度独立,互不干扰。
可复现数据代码
# 创建数据向量 set.seed(1) Time <- 1:200 ET_IRRIGATION <- runif(n = 200, min = 0, max = 0.5) ET_CONTROL <- runif(n = 200, min = 0, max = 0.5) SMOIS_IRRIGATION <- runif(n = 200, min = 10, max = 30) SMOIS_CONTROL <- runif(n = 200, min = 10, max = 30) # 合并为数据框 Ensemble1.df <- data.frame(Time, ET_IRRIGATION, ET_CONTROL, SMOIS_IRRIGATION, SMOIS_CONTROL)
尝试过的代码及问题
尝试代码
# 设置轴范围 ylim.prim <- c(0, 0.5) ylim.sec <- c(10, 30) b <- diff(ylim.prim)/diff(ylim.sec) a <- ylim.prim[1] - b*ylim.sec[1] # 此处存在问题 # 绘图 ggplot(Ensemble1.df, aes(Time)) + geom_line(aes(y= ET_IRRIGATION), color= "blue", size= 1) + geom_line(aes(y= ET_CONTROL), color= "red", size= 1) + geom_line(aes(y= SMOIS_IRRIGATION), color= "skyblue", size= 1) + geom_line(aes(y= SMOIS_CONTROL), color= "orange", size= 1) + scale_y_continuous("ET [mm/hour]", sec.axis = sec_axis(~ (. - a)/b, name = "Soil Moisture [mm]")) + xlab("Time") + theme_bw() + theme(text= element_text(size= 22)) + theme(axis.text.y= element_text(size= 25, color= "black")) + theme(axis.text.x= element_text(angle= 0, hjust= 1, size= 18, color= "black")) + theme(legend.position= "none", legend.spacing.x= unit(1, "cm"))
存在问题
- 双Y轴刻度错误:左Y轴未正确显示0-0.5区间,右Y轴未正确显示10-30区间
- 折线映射错误:SMOIS系列折线未关联右Y轴,所有折线共用左Y轴刻度,导致SMOIS数据被压缩到0-0.5范围显示
解决方案
核心是将SMOIS数据线性转换到左Y轴的刻度区间,再通过逆转换生成右Y轴的刻度,确保两组数据分别对应各自的轴范围。
修正后代码
library(ggplot2) # 定义轴范围 ylim_et <- c(0, 0.5) # 左Y轴ET范围 ylim_smois <- c(10, 30) # 右Y轴SMOIS范围 # 转换函数:将SMOIS值映射到ET轴的区间 convert_smois_to_et <- function(x) { (x - ylim_smois[1]) * diff(ylim_et) / diff(ylim_smois) + ylim_et[1] } # 逆转换函数:将ET轴刻度转换回SMOIS原始范围(用于右轴显示) convert_et_to_smois <- function(x) { (x - ylim_et[1]) * diff(ylim_smois) / diff(ylim_et) + ylim_smois[1] } ggplot(Ensemble1.df, aes(x = Time)) + # ET系列:直接使用原始值,对应左Y轴 geom_line(aes(y = ET_IRRIGATION), color = "blue", size = 1) + geom_line(aes(y = ET_CONTROL), color = "red", size = 1) + # SMOIS系列:使用转换后的值,映射到左轴空间,对应右Y轴 geom_line(aes(y = convert_smois_to_et(SMOIS_IRRIGATION)), color = "skyblue", size = 1) + geom_line(aes(y = convert_smois_to_et(SMOIS_CONTROL)), color = "orange", size = 1) + # 设置双Y轴:固定左轴范围,右轴用逆转换生成刻度 scale_y_continuous( name = "ET [mm/hour]", limits = ylim_et, sec.axis = sec_axis( trans = convert_et_to_smois, name = "Soil Moisture [mm]", limits = ylim_smois ) ) + xlab("Time") + theme_bw() + theme( text = element_text(size = 22), axis.text.y = element_text(size = 25, color = "black"), axis.text.x = element_text(angle = 0, hjust = 1, size = 18, color = "black"), legend.position = "none" )
关键说明
- 转换函数
convert_smois_to_et将SMOIS的10-30范围线性映射到ET的0-0.5范围,让SMOIS折线能在图表中占据正确的空间位置 - 右轴通过逆转换函数
convert_et_to_smois把左轴刻度转换回SMOIS原始值,确保刻度显示准确 - 用
limits参数固定左右轴范围,避免数据自动缩放导致的刻度偏移
内容的提问来源于stack exchange,提问作者climsaver
相关产品推荐
相关产品推荐

