You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:10:33