折线图边角平滑:已尝试spline与curve fitting无效,如何保原形态?
折线图平滑边角需求及解决方案
问题背景
我试了一堆spline工具和曲线拟合方法,但这些方法直接把我的图表改得面目全非。我只想让折线图的边缘变平滑,去掉那些尖锐的角,完全不想改变整体趋势。
原始代码
import numpy as np from matplotlib import pyplot as plt constant = 1.4 xdata = [52.8905, 52.7612, 51.7277, 51.6320, 47.8479] data1 = [1.4826, 1.5395, 1.5863, 1.5898, 1.5343] data2 = [1.1551, 1.1570, 1.1690, 1.1700, 1.1707] ydata = np.zeros(5) def myfunc(D1, D2, D3): polyeff = (np.log(D1) * (D3 - 1)) / (D3 * np.log(D2)) return polyeff for i, value in enumerate(xdata): ydata[i] = myfunc(data1[i], data2[i], constant) plt.plot(xdata, ydata) plt.show()
原始图表
需要平滑边角的折线图:
遇到的问题
我试过Stack Overflow上《Smoothing out a curve》里的大部分方法,但结果和原图表差异极大,求解决办法。
解决方案
要在保留原始数据趋势的前提下平滑边角,推荐用插值生成高密度点的方法,而非直接拟合新曲线。具体步骤如下:
- 导入
scipy.interpolate.make_interp_spline工具 - 对原始x数据排序(插值要求x单调)
- 生成更多的x插值点
- 用样条插值得到对应的y值,再绘图
修改后的代码
import numpy as np from matplotlib import pyplot as plt from scipy.interpolate import make_interp_spline constant = 1.4 xdata = [52.8905, 52.7612, 51.7277, 51.6320, 47.8479] data1 = [1.4826, 1.5395, 1.5863, 1.5898, 1.5343] data2 = [1.1551, 1.1570, 1.1690, 1.1700, 1.1707] ydata = np.zeros(5) def myfunc(D1, D2, D3): polyeff = (np.log(D1) * (D3 - 1)) / (D3 * np.log(D2)) return polyeff for i, value in enumerate(xdata): ydata[i] = myfunc(data1[i], data2[i], constant) # 按x升序排序(样条插值要求x单调) sorted_indices = np.argsort(xdata) x_sorted = np.array(xdata)[sorted_indices] y_sorted = np.array(ydata)[sorted_indices] # 生成100个高密度插值点 x_interp = np.linspace(x_sorted.min(), x_sorted.max(), 100) # 用二次样条插值生成平滑y值,k=2更贴合原始趋势 spl = make_interp_spline(x_sorted, y_sorted, k=2) y_interp = spl(x_interp) # 同时绘制平滑折线和原始数据点,确保趋势一致 plt.plot(x_interp, y_interp, label='平滑折线') plt.scatter(xdata, ydata, color='red', label='原始数据点') plt.legend() plt.show()
关键说明
- 排序是核心:样条插值要求x数据单调,原始x是递减的,必须先排序处理
- 选择
k=2二次样条:比三次样条更不容易出现偏离原始数据的异常波动,完美匹配“仅平滑边角”的需求 - 保留原始点:用散点图标注原始数据,确保平滑后的折线没有偏离原始趋势
内容的提问来源于stack exchange,提问作者Ironstacker727
相关产品推荐
相关产品推荐

