如何用ggplot2绘制左轴log10刻度、右轴线性刻度的双Y轴图?
双Y轴(log10左轴 + 线性右轴)对齐解决方案
要实现左轴log10刻度、右轴线性刻度且两者对齐,核心是将右侧变量的数值范围线性映射到左侧log刻度的数值范围,再通过反向转换生成右轴刻度。以下是完整代码和说明:
library(tidyverse) # 原始数据框 df <- tibble( TIME = 0:19, VAL1 = seq(from = 10, to = 2500, length.out = 20), VAL2 = seq(from = 1, to = 30, length.out = 20)) # 计算左右轴的范围参数 log_range <- log10(range(df$VAL1)) # 左轴log10后的范围 lin_range <- range(df$VAL2) # 右轴线性范围 # 定义转换函数:将VAL2映射到左轴log范围 val2_to_log <- function(x) { (x - lin_range[1]) / (lin_range[2] - lin_range[1]) * (log_range[2] - log_range[1]) + log_range[1] } # 定义反向转换函数:将左轴log值转回VAL2的线性值(用于右轴刻度) log_to_val2 <- function(x) { (x - log_range[1]) / (log_range[2] - log_range[1]) * (lin_range[2] - lin_range[1]) + lin_range[1] } # 绘制对齐的双Y轴图 ggplot(df, aes(x = TIME)) + # 左轴折线:VAL1,用log10转换后的值绘制 geom_line(aes(y = log10(VAL1), color = "VAL1"), size = 1) + # 右轴折线:VAL2,用转换到log范围的值绘制 geom_line(aes(y = val2_to_log(VAL2), color = "VAL2"), size = 1) + # 设置Y轴:左轴显示原始VAL1的log10刻度,右轴生成对应VAL2的线性刻度 scale_y_continuous( name = "VAL1 (log10)", breaks = seq(log_range[1], log_range[2], by = 0.5), labels = ~ 10^.x, # 将log值转回原始数值显示 sec.axis = sec_axis( trans = log_to_val2, name = "VAL2 (linear)", breaks = seq(lin_range[1], lin_range[2], by = 5) # 自定义右轴刻度间隔 ) ) + scale_color_manual(values = c("VAL1" = "#2c3e50", "VAL2" = "#e74c3c")) + labs(x = "TIME") + theme_minimal() + theme(legend.position = "top")
关键说明
- 范围映射:通过
val2_to_log将VAL2的线性范围拉伸/压缩到VAL1的log10数值范围,保证两条折线的垂直位置在图上对齐。 - 反向转换:
log_to_val2用于将左轴的log刻度值转换为VAL2的原始线性值,确保右轴刻度与左轴的空间位置一一对应。 - 刻度自定义:可以通过调整
breaks参数修改左右轴的刻度间隔,适配数据分布。
内容的提问来源于stack exchange,提问作者jsgraydon
相关产品推荐
相关产品推荐

