如何在ggplot2中绘制含多项式函数的双Y轴折线图?
在R中实现双Y轴图表并添加多项式拟合曲线
示例实现(ggplot2版本)
下面是可直接运行的完整示例,用模拟数据演示双Y轴+多项式拟合的效果,你可以直接替换成自己的数据:
library(ggplot2) # 模拟示例数据 set.seed(123) df <- data.frame( x = 1:20, y1 = 3 + 2*x + rnorm(20, 0, 3), # 第一个Y轴数据(线性趋势) y2 = 10 - 1.5*x + 0.2*x^2 + rnorm(20, 0, 2) # 第二个Y轴数据(二次趋势) ) # 拟合y2的二次多项式模型 poly_model <- lm(y2 ~ poly(x, 2, raw = TRUE), data = df) # 生成拟合预测值 df$y2_fit <- predict(poly_model, newdata = df) # 计算双Y轴的转换比例(让两个轴的范围适配) y1_range <- range(df$y1) y2_range <- range(df$y2) scale_factor <- diff(y1_range)/diff(y2_range) shift <- y1_range[1] - y2_range[1]*scale_factor # 绘制双Y轴图表 ggplot(df, aes(x = x)) + # 第一个Y轴:散点+拟合线 geom_point(aes(y = y1), color = "#2E86AB", size = 2) + geom_smooth(aes(y = y1), method = "lm", se = FALSE, color = "#2E86AB", linetype = "dashed") + # 第二个Y轴:散点+多项式拟合线 geom_point(aes(y = y2*scale_factor + shift), color = "#F24C4E", size = 2) + geom_line(aes(y = y2_fit*scale_factor + shift), color = "#F24C4E", size = 1.2) + # 设置双Y轴 scale_y_continuous( name = "第一个Y轴标签", sec.axis = sec_axis(~ (. - shift)/scale_factor, name = "第二个Y轴标签") ) + labs(x = "X轴标签", title = "双Y轴+多项式拟合示例") + theme_minimal() + theme( axis.title.y = element_text(color = "#2E86AB"), axis.title.y.right = element_text(color = "#F24C4E") )
关键步骤说明
- 多项式拟合:用
lm(y ~ poly(x, n, raw=TRUE))拟合n阶多项式,raw=TRUE保证使用原始多项式项(而非正交多项式),便于理解系数含义。 - 双Y轴刻度转换:ggplot2不支持直接独立的双Y轴,需通过缩放第二个Y轴的数据适配第一个Y轴范围,再用
sec_axis反向转换显示正确刻度。 - 样式区分:用不同颜色、符号区分两个Y轴的元素,避免混淆。
Base R实现方案
如果习惯用Base R绘图,可参考以下代码:
# 模拟数据同上 set.seed(123) df <- data.frame( x = 1:20, y1 = 3 + 2*x + rnorm(20, 0, 3), y2 = 10 - 1.5*x + 0.2*x^2 + rnorm(20, 0, 2) ) # 拟合多项式模型 poly_model <- lm(y2 ~ poly(x, 2, raw=TRUE), data=df) x_seq <- seq(min(df$x), max(df$x), length.out=100) y2_fit <- predict(poly_model, newdata=data.frame(x=x_seq)) # 创建双Y轴绘图 par(mar = c(5,4,4,4) + 0.1) # 调整右侧边距 # 绘制第一个Y轴 plot(df$x, df$y1, pch=16, col="#2E86AB", xlab="X轴标签", ylab="第一个Y轴标签", main="双Y轴+多项式拟合") abline(lm(y1~x, data=df), col="#2E86AB", lty=2) # 添加第二个Y轴 par(new=TRUE) plot(df$x, df$y2, pch=17, col="#F24C4E", axes=FALSE, xlab="", ylab="") lines(x_seq, y2_fit, col="#F24C4E", lwd=2) axis(side=4) mtext("第二个Y轴标签", side=4, line=3, col="#F24C4E") legend("topleft", legend=c("Y1数据", "Y1拟合", "Y2数据", "Y2多项式拟合"), col=c("#2E86AB","#2E86AB","#F24C4E","#F24C4E"), pch=c(16,NA,17,NA), lty=c(NA,2,NA,1))
注意事项
- 双Y轴易造成数据误解,非必要场景建议避免使用;若必须使用,务必用清晰的视觉元素区分两个数据系列。
- 如果你有自己的代码片段,可以贴出来,我会帮你针对性修改。
内容的提问来源于stack exchange,提问作者Cesar Barrientos
相关产品推荐
相关产品推荐

