折线图和散点图能显示数据的走势,但走势本身要靠读者自己判断:下个月会继续上升还是回落?两个季度的波动是否属于同一趋势?趋势线把这条走势画成一条数学曲线,回归方程和 R² 则给出量化的答案。
在 Excel 里添加趋势线原本要经过"右键系列 → 添加趋势线 → 选择类型 → 勾选显示方程"几个步骤。当图表由脚本生成时,这些操作都可以写进代码。这篇文章用 Spire.XLS for Python 演示如何为图表的各个系列添加不同类型的趋势线、显示回归方程与拟合优度,并在保存后读回方程。
环境准备
安装 Spire.XLS 并引入模块:
bash
pip install Spire.XLS
python
from spire.xls import *
from spire.xls.common import *
创建基础图表
先准备一组六个月的销售数据,并生成一张带数据点的折线图。趋势线必须挂在一个已经存在的系列上,所以图表要先建好:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.CreateEmptySheets(1)
sheet = workbook.Worksheets[0]
months = ["Jan.", "Feb.", "Mar.", "Apr.", "May.", "Jun."]
planned = [3.3, 2.5, 2.0, 3.7, 4.5, 4.0]
sheet.Range["A1"].Value = "Month"
sheet.Range["B1"].Value = "Planned"
for i in range(len(months)):
sheet.Range[i + 2, 1].Value = months[i]
sheet.Range[i + 2, 2].NumberValue = planned[i]
# 创建折线图,并以 B 列数据作为数据源
chart = sheet.Charts.Add(ExcelChartType.LineMarkers)
chart.DataRange = sheet.Range["B1:B7"]
chart.SeriesDataFromRange = False
chart.ChartTitle = "Planned Sales"
# 设置分类轴标签
chart.Series[0].CategoryLabels = sheet.Range["A2:A7"]
workbook.SaveToFile("BaseChart.xlsx", ExcelVersion.Version2013)
workbook.Dispose()

CreateEmptySheets(1) 创建一个空白工作表;Charts.Add(ExcelChartType.LineMarkers) 在表内新建图表,并从 DataRange 指定的区域读取数据。SeriesDataFromRange = False 表示数据的系列名称和分类标签另行指定,而不是从区域首行首列推断。
添加线性趋势线并显示方程
趋势线通过系列的 TrendLines 集合添加,Add() 的参数是趋势线类型。下面的代码在刚刚生成的 BaseChart.xlsx 上继续操作:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("BaseChart.xlsx")
chart = workbook.Worksheets[0].Charts[0]
# 为第一个系列添加线性趋势线
trendline = chart.Series[0].TrendLines.Add(TrendLineType.Linear)
# 在图表上显示回归方程和 R²
trendline.DisplayEquation = True
trendline.DisplayRSquared = True
workbook.SaveToFile("LinearTrendline.xlsx", ExcelVersion.Version2013)
workbook.Dispose()

DisplayEquation 打开后,图表上会出现形如 y = 0.32x + 2.2133 的标签;DisplayRSquared 则附加 R² 值,用来衡量数据点与趋势线的贴合程度。两者默认都是关闭的,需要显式打开。
其他趋势线类型
TrendLineType 提供五种类型:Linear(线性)、Logarithmic(对数)、Exponential(指数)、Polynomial(多项式)和 Moving_Average(移动平均)。同一个系列可以添加多条趋势线,用于对比不同模型的拟合效果:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("BaseChart.xlsx")
series = workbook.Worksheets[0].Charts[0].Series[0]
# 五种类型各加一条
series.TrendLines.Add(TrendLineType.Linear)
series.TrendLines.Add(TrendLineType.Logarithmic)
series.TrendLines.Add(TrendLineType.Exponential)
series.TrendLines.Add(TrendLineType.Polynomial)
series.TrendLines.Add(TrendLineType.Moving_Average)
workbook.SaveToFile("TrendlineTypes.xlsx", ExcelVersion.Version2013)
workbook.Dispose()

几种类型对数据有不同的前提:对数趋势线要求 x 值为正,指数趋势线要求 y 值全为正,移动平均则不适合外推预测。多项式趋势线还可以调整阶数,Order 属性控制最高次项,默认是 2:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("BaseChart.xlsx")
series = workbook.Worksheets[0].Charts[0].Series[0]
polynomial = series.TrendLines.Add(TrendLineType.Polynomial)
polynomial.Order = 3
workbook.SaveToFile("PolynomialTrendline.xlsx", ExcelVersion.Version2013)
workbook.Dispose()

阶数越高,曲线对数据点的贴合越紧,但过高的阶数容易把噪声也拟合进去,通常从 2 阶开始尝试即可。
向前与向后预测
趋势线除了描述已有数据,还可以按分类轴的步长向后延伸或向前外推。Forward 和 Backward 属性以"多少个分类单位"为单位:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("LinearTrendline.xlsx")
trendline = workbook.Worksheets[0].Charts[0].Series[0].TrendLines[0]
# 向后延伸 0.5 个单位、向前预测 2 个单位
trendline.Backward = 0.5
trendline.Forward = 2
workbook.SaveToFile("ForecastTrendline.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
取值是浮点数,表示分类轴上的单位数。需要注意的是 Backward 的取值范围是 0 到 0.5,超出这个范围会抛出异常;Forward 没有这个限制。向后延伸只在有历史数据的方向上有意义,向前预测的长度则取决于数据的稳定程度------外推过远时,趋势线的误差会明显放大。
命名趋势线与设置标签格式
默认趋势线没有名字。系列中同时存在多条趋势线时,给它们命名并在标签上统一小数格式,图例和方程就更容易区分:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("LinearTrendline.xlsx")
trendline = workbook.Worksheets[0].Charts[0].Series[0].TrendLines[0]
# 命名趋势线,并把标签数字格式化为两位小数
trendline.Name = "Baseline"
trendline.DataLabel.NumberFormat = "#,##0.00"
workbook.SaveToFile("TrendlineLabel.xlsx", ExcelVersion.Version2013)
workbook.Dispose()
Name 会写入图表 XML 的 trendline 节点,在图表上作为趋势线标签的一部分显示;DataLabel.NumberFormat 则控制方程与 R² 中数字的显示格式。
读回趋势线方程
趋势线的方程也会保存在文件里,可以在后续脚本中读出来做汇总或校验。加载文件后,通过 Formula 属性取得方程字符串:
python
from spire.xls import *
from spire.xls.common import *
workbook = Workbook()
workbook.LoadFromFile("TrendlineTypes.xlsx")
series = workbook.Worksheets[0].Charts[0].Series[0]
for i in range(series.TrendLines.Count):
trendline = series.TrendLines[i]
try:
print(trendline.Type, "->", trendline.Formula)
except Exception:
# 移动平均没有回归方程
print(trendline.Type, "-> no equation")
workbook.Dispose()
输出类似:
ini
TrendLineType.Linear -> y = 0.32x + 2.2133
TrendLineType.Logarithmic -> y = 0.7006Ln(x) + 2.5651
TrendLineType.Exponential -> y = 2.3001e^(0.0954x)
TrendLineType.Polynomial -> y = 0.1196x^2 - 0.5175x + 3.33
TrendLineType.Moving_Average -> no equation
需要注意,移动平均是把相邻若干点取平均后连成的线,它不是回归模型,因此没有方程;对这类趋势线调用 Formula 会抛出异常,读取时要先判断类型或做异常处理。
实用技巧
- 先建系列再加趋势线 :
TrendLines挂在Series上,图表和数据源准备好之后再添加。 - 方程与 R² 要显式开启 :
DisplayEquation、DisplayRSquared默认关闭,不开就看不到标签。 - 类型有前提条件:对数要求 x 为正、指数要求 y 为正,否则 Excel 会画出错误或空白的趋势线。
- 阶数从低到高 :多项式趋势线先用
Order = 2,贴合不够再提高,避免过拟合。 - 移动平均不能外推 :它没有方程,也不适合做
Forward预测。 - 读取方程时处理异常 :只有回归类趋势线有
Formula,批量读取时加类型判断。 - 及时释放资源 :每个工作簿用完调用
Dispose()。
结论
这篇文章演示了在 Python 中为 Excel 图表添加趋势线:先创建带数据标签的折线图,再通过 Series.TrendLines.Add() 添加线性、对数、指数、多项式或移动平均趋势线,用 DisplayEquation 和 DisplayRSquared 在图上显示回归方程与拟合优度,用 Forward / Backward 做预测延伸,用 Name 与 DataLabel.NumberFormat 区分和格式化多条趋势线,最后在加载文件后通过 Formula 读回方程。把这些步骤放进报表生成脚本,图表就不只是展示数据,还能直接给出趋势的量化结论。