ggplot绘制多变量趋势线仅显示一条的原因及解决方法
问题原因分析
咱们先拆解你遇到的两个核心问题:
1. 初始代码仅显示一条趋势线
- 你在初始代码里直接用
test$year、test$SA这种外部数据引用方式,违背了ggplot的数据映射原则——ggplot期望所有变量都来自传入的data参数,外部引用会导致图层之间的映射断裂。 - 你的
geom_smooth只绑定了初始aes(x=year, y=SA, group=1)的映射,另外两条geom_line是单独指定的变量,没有和geom_smooth建立分组关联,所以ggplot只会为SA生成一条趋势线,忽略了SA1和SA2。 - 另外,SA1是除以100后绘制的,但没有在
aes里明确分组,geom_smooth无法识别需要为不同变量分别拟合趋势线。
2. 数据重塑后次坐标轴异常
- 三个变量的数值量级差异极大:SA和SA2在
1e15级别,而SA1在3e17级别。你重塑后直接用sec_axis(~.*100)的缩放比例,只适合SA1的还原,但SA和SA2不需要这个缩放,导致次轴和主轴的对应关系完全混乱,显示异常。
解决方案
核心思路是先统一变量量级,再用长格式数据让ggplot自动分组绘图,同时匹配正确的次轴缩放逻辑。
步骤1:预处理数据,统一量级
先把SA1除以100,让它的数值量级和SA、SA2接近,这样三个变量能在同一个主坐标轴上正常显示,次轴再把SA1的数值还原回去。
步骤2:转成长格式数据
用tidyr::gather(或pivot_longer)把宽格式数据转成长格式,这样ggplot可以通过group和colour参数自动区分三个变量,为每个变量单独绘制线条和趋势线。
步骤3:添加回归方程和R²(可选)
如果需要显示每个趋势线的R²和回归方程,可以用ggpmisc包的stat_poly_eq函数,它能自动为每个分组生成对应的统计信息。
完整可运行代码
library(dplyr) library(tidyr) library(ggplot2) library(ggpmisc) # 用于添加回归方程和R² # 你的原始数据 test <- structure(list(year = structure(1:11, .Label = c("2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018"), class = "factor"), SA = c(1409155313839800, 1533598052716370, 1524727969175020, 1583941250825040, 1597021832828680, 1549362217661020, 1607700438214130, 1592107298305410, 1735331260744350, 1761596167580970, 1677707298223350), SA1 = c(363273957183114432, 376734225895083200, 355896023882281984, 368398075167704192, 367791249493954048, 360257619620708800, 360061958768956736, 367763926166363648, 355088403981918272, 358140732212706304, 342823915606135936), SA2 = c(4.06998e+15, 4.05015e+15, 3.94057e+15, 3.9507e+15, 3.58963e+15, 3.53037e+15, 3.43302e+15, 3.20139e+15, 3.94638e+15, 3.03403e+15, 3.15862e+15)), row.names = c(NA, -11L ), class = "data.frame") # 数据处理+绘图 test %>% mutate(SA1 = SA1 / 100) %>% # 统一SA1的量级 gather(sa, value, -year) %>% # 转成长格式 ggplot(aes(x = year, y = value, group = sa, colour = sa)) + geom_line(linewidth = 1) + geom_smooth(method = "lm", formula = y ~ x, se = FALSE, linewidth = 1) + # 添加回归方程和R² stat_poly_eq(aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")), formula = y ~ x, parse = TRUE, size = 3.5) + scale_color_manual(values = c("black", "red", "blue"), labels = c("SA", "SA1 (scaled)", "SA2")) + scale_y_continuous( name = "Primary Axis (SA/SA2)", sec.axis = sec_axis(~ . * 100, name = "Secondary Axis (Original SA1)") ) + labs(title = "Trend Lines with Regression Equations and R²", x = "Year") + theme_minimal()
关键说明
- 用
mutate(SA1 = SA1/100)统一量级,解决了不同变量数值差异过大导致的显示问题; - 长格式数据让ggplot自动识别分组,
geom_smooth会为每个sa分组单独拟合趋势线; stat_poly_eq自动生成每个趋势线的回归方程和R²,通过parse=TRUE渲染成数学公式格式;- 次轴的
~.*100精准还原SA1的原始数值,和主轴的缩放逻辑匹配。
内容的提问来源于stack exchange,提问作者Lalantra
相关产品推荐
相关产品推荐

