如何使用BSpline平滑Matplotlib中存在波动的红色折线?
用BSpline平滑折线的解决方案
我来帮你搞定这个问题!确实scipy里旧的spline函数已经被弃用了,官方推荐用BSpline或者更方便的make_interp_spline来实现平滑曲线。下面是具体的步骤和修改后的代码:
关键思路
你的红色折线是基于y和j数组绘制的,但原始的y数组并不是单调有序的,这会导致直接拟合时曲线出现异常波动甚至交叉。所以我们需要先对数据排序,再用三阶BSpline生成平滑曲线。
修改后的完整代码
import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import make_interp_spline # 原始数据 y = np.array([476,310,254,190,184,182,161,154,148,133,127,119,117,103,102,96,95,95,91,84,82,71,65,64,64,64,62,61,49, 42,38,37,33,30,29,22,22,18,16,16,16,14,12,12,11,10,9,9,9,8,8,6,6,5,4,4,4,4,3,2,1,1]) x = np.array([19,40,35,43,19,18,35,15,31,12,22,19,33,19,43,55,17,6,21,26,20,21,14,53,30,13,42,43,51,43,24,30,36,13,41,41,41,50,56,50, 44,64,58,42,18,30,78,22,11,25,25,50,50,60,100,25,25,0,67,100,100,0]) j = np.array([29,32,34,36,37,37,38,38,39,40,40,41,41,43,43,43,43,43,44,45,45,47,48,48,48,48, 49,49,52,55,56,57,59,60,61,66,66,71,73,73,73,77,81,81,83,86,89,89,89,92,92,102, 102,109,118,118,118,118,132,154,201,201]) plt.figure(figsize=(15,8)) plt.ylim(0, 100) plt.scatter(y,x) # --- 平滑红色折线的核心代码 --- # 1. 按y值排序,确保x轴单调(避免曲线交叉) sorted_indices = np.argsort(y) y_sorted = y[sorted_indices] j_sorted = j[sorted_indices] # 2. 创建三阶BSpline插值器(k=3是常用的平滑阶数) spl = make_interp_spline(y_sorted, j_sorted, k=3) # 3. 生成更密集的x值,让曲线更平滑 y_new = np.linspace(y_sorted.min(), y_sorted.max(), 1000) j_smooth = spl(y_new) # 4. 绘制平滑后的红色曲线 plt.plot(y_new, j_smooth, 'red', linewidth=1) # --- 核心代码结束 --- plt.show()
细节说明
- 排序的必要性:原始的
y数组是无序的(从476降到1再到0),直接拟合会导致曲线在y值波动的地方出现奇怪的折返,排序后x轴单调,拟合出的曲线才会连续自然。 - 阶数k的选择:
k=3对应三阶样条,是最常用的平滑选项;如果想要更贴近原始点的曲线,可以尝试k=2(二阶样条);k=1就是线性插值,和平原折线效果一致。 make_interp_spline的优势:它会自动计算BSpline的节点和系数,比手动创建BSpline对象更简单,完全替代了旧的spline函数的功能。
这样修改后,你就能得到一条平滑的红色曲线,解决x轴150附近的波动问题啦!
内容的提问来源于stack exchange,提问作者Nicholas
相关产品推荐
相关产品推荐

