调整Secondary Axis匹配Primary Axis:实现次轴起始于0的方法
解决ggplot2次轴下限强制为0的问题
需求说明
- 主轴(Avg. Asking Rate)始终使用自身数据的最小值作为下限
- 次轴(Vacancy Rate)强制从0开始,不允许出现负值
问题根源
原代码的train_sec函数使用了次轴数据的完整范围(range(secondary))进行缩放转换,导致次轴下限会跟随原始数据的最小值变动,无法固定为0。
修改方案
调整次轴的缩放基准范围,强制将次轴的转换起始点设为0,而非原始数据的最小值。以下是修改后的完整代码:
library(dplyr) library(scales) library(ggplot2) # 示例数据 stats <- data.frame( Snapshot.Date = as.Date(c("2020-09-30", "2020-12-31", "2021-03-31", "2021-06-30", "2021-09-30", "2021-12-31")), avg_asking_rate = c( 4.93799293627304, 4.99132174488857, 4.97053998470495, 4.90321494004932, 4.93494348159945, 4.91379691657121 ), vacancy_rate = c( 9.94185919399802, 11.5989188611645, 12.9308555110482, 13.9590437469142, 13.5155036299108, 12.8472483323431 ) ) # 修改后的次轴转换函数:强制次轴从0开始 train_sec <- function(primary, secondary, na.rm = TRUE) { # 次轴范围改为从0到最大值 from <- c(0, max(secondary, na.rm = na.rm)) to <- range(primary, na.rm = na.rm) forward <- function(x) { rescale(x, from = from, to = to) } reverse <- function(x) { rescale(x, from = to, to = from) } list(fwd = forward, rev = reverse) } # 主轴下限取0.5的倍数(保持原逻辑) y_lm <- floor((min(stats$avg_asking_rate))*2)/2 # 生成转换规则 sec <- with(stats, train_sec(stats$avg_asking_rate, stats$vacancy_rate)) # 绘图 stats %>% ggplot(., aes(x = `Snapshot.Date`, y = avg_asking_rate))+ ggtitle("Rent") + geom_col(aes(fill = "Avg. Asking Rate"))+ geom_line(aes(y = sec$fwd(vacancy_rate), colour = "Vacancy Rate"), size = 1) + scale_x_date(name = NULL)+ scale_y_continuous(name = "", sec.axis = sec_axis(~sec$rev(.), name = "Vacancy Rate"))+ coord_cartesian(ylim=c(y_lm,NA)) + scale_fill_manual(name = NULL, values = c("Avg. Asking Rate" = "blue", "Vacancy Rate" = "green"), guide = guide_legend(order = 1))+ scale_colour_manual(name = NULL, values = c("Vacancy Rate" = "green"), guide = guide_legend())
关键修改点
- 在
train_sec函数中,将次轴的缩放范围from从range(secondary)改为c(0, max(secondary, na.rm=na.rm)),强制次轴以0为下限 - 主轴的下限逻辑保持不变,仍然基于自身数据最小值取0.5的倍数
- 次轴的反向转换会自动基于新的范围生成,确保刻度从0开始
预期效果

内容的提问来源于stack exchange,提问作者wigglesthe3rd
相关产品推荐
相关产品推荐

