使用ggplot2为柱状图添加带次Y轴的折线图
ggplot2 次Y轴添加失败问题解决
问题背景
已实现X轴为日期、主Y轴为var1的柱状图(填充色由var2控制),尝试添加var3的折线到次Y轴时,出现警告Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.,图表显示不符合预期。
错误原因
- 重复定义Y轴刻度:代码中同时使用
ylim(0,10)和scale_y_continuous(),两者都用于设置Y轴刻度范围,ggplot2不允许重复定义同一轴的刻度,后者会直接覆盖前者,导致主Y轴设置失效,触发警告。 - 数值转换错误:将
var3乘以2000来映射到主Y轴范围,而var3的实际范围是10-160,主Y轴是0-10,这种转换会让var3的数值远超主Y轴上限,导致折线点无法正常显示在图表内。
修正后的代码
set.seed(1234) # 构造测试数据 df <- data.frame( date = seq(as.Date("2023/01/01"), by="day", length.out=10), var1 = c(5.6, 5.4, 6.7, 7.3, 6.8, 7.9, 8.5, 9.0, 7.8, 7.1), var2 = runif(10, min = 0, max = 1), var3 = runif(10, min = 10, max = 160) ) library(ggplot2) # 计算var3与主Y轴的转换关系 var3_range <- range(df$var3) main_y_range <- c(0, 10) # 将var3转换到主Y轴范围的函数 trans_to_main <- function(x) { (x - var3_range[1]) / diff(var3_range) * diff(main_y_range) + main_y_range[1] } # 将主Y轴数值转换回var3原始范围的逆函数(用于次轴刻度) trans_to_var3 <- function(x) { (x - main_y_range[1]) / diff(main_y_range) * diff(var3_range) + var3_range[1] } ggplot(df, aes(x = date, y = var1, fill = var2)) + geom_bar(stat = 'identity') + scale_fill_gradient2(mid='blue4', high="darkgoldenrod1", name="Var 2") + scale_x_date(date_breaks = "1 day") + # 统一设置主、次Y轴,替代单独的ylim scale_y_continuous( name = "Var 1", limits = main_y_range, sec.axis = sec_axis(trans = trans_to_var3, name = "Var 3") ) + theme_grey() + labs(title = "Plot title", x = "Date") + theme(axis.text.x = element_text(angle = 45, hjust = 1)) + # 使用转换后的var3值绘制折线和点 geom_point(aes(y = trans_to_main(var3)), color = 'black') + geom_line(aes(y = trans_to_main(var3), group = 1), color = 'black')
关键修改说明
- 合并Y轴设置:移除
ylim(0,10),改用scale_y_continuous()的limits参数定义主Y轴范围,同时在同一个函数内设置次Y轴,避免重复定义轴刻度的冲突。 - 正确数值转换:通过线性转换公式,将
var3的10-160范围映射到主Y轴的0-10区间,确保折线能在图表内正常显示;次轴使用逆转换函数,将主Y轴刻度转换回var3的原始数值,保证次轴刻度准确。 - 简化代码结构:合并重复的
labs()调用,让代码更简洁。
内容的提问来源于stack exchange,提问作者sermomon
相关产品推荐
相关产品推荐

