python绘制散曲线线宽_python-在Matplotlib中模拟Excel的“平滑曲线散点”样条函数3点...

这篇博客探讨了如何在Python中使用Scipy和Matplotlib库来实现类似Excel的平滑曲线插值。文章介绍了Centripetal Catmull-Rom样条和Scipy的BarycentricInterpolator、Akima1DInterpolator函数,提供了代码示例,展示了如何通过三个或更多点生成平滑曲线,特别适合处理数据点较少的情况。
摘要由CSDN通过智能技术生成

我正在尝试模仿Excel的

使用平滑的线条和标记插入> Scatter> Scatter

Matplotlib中的命令

scipy函数interpolate会产生类似的效果,其中有一些很好的示例,说明了如何在此处简单地实现此功能:

How to draw cubic spline in matplotlib

但是Excel的样条算法也能够仅通过三个点生成平滑曲线(例如x = [0,1,2] y = [4,2,1]);并且无法使用三次样条曲线执行此操作.

是否有一种简单的方法可以修改上述示例,以使用插值库通过三个或更多点获得平滑曲线?

非常感谢

解决方法:

到现在为止,您可能已经找到了Centripetal Catmull-Rom spline的Wikipedia页面,但是如果没有,它包含以下示例代码:

import numpy

import matplotlib.pyplot as plt

def CatmullRomSpline(P0, P1, P2, P3, nPoints=100):

"""

P0, P1, P2, and P3 should be (x,y) point pairs that define the

Catmull-Rom spline.

nPoints is the number of points to include in this curve segment.

"""

# Convert the points to numpy so that we can do array multiplication

P0, P1, P2, P3 = map(numpy.array, [P0, P1, P2, P3])

# Calculate t0 to t4

alpha = 0.5

def tj(ti, Pi, Pj):

xi, yi = Pi

xj, yj = Pj

return ( ( (xj-xi)**2 + (yj-yi)**2 )**0.5 )**alpha + ti

t0 = 0

t1 = tj(t0, P0, P1)

t2 = tj(t1, P1, P2)

t3 = tj(t2, P2, P3)

# Only calculate points between P1 and P2

t = numpy.linspace(t1,t2,nPoints)

# Reshape so that we can multiply by the points P0 to P3

# and get a point for each value of t.

t = t.reshape(len(t),1)

A1 = (t1-t)/(t1-t0)*P0 + (t-t0)/(t1-t0)*P1

A2 = (t2-t)/(t2-t1)*P1 + (t-t1)/(t2-t1)*P2

A3 = (t3-t)/(t3-t2)*P2 + (t-t2)/(t3-t2)*P3

B1 = (t2-t)/(t2-t0)*A1 + (t-t0)/(t2-t0)*A2

B2 = (t3-t)/(t3-t1)*A2 + (t-t1)/(t3-t1)*A3

C = (t2-t)/(t2-t1)*B1 + (t-t1)/(t2-t1)*B2

return C

def CatmullRomChain(P):

"""

Calculate Catmull Rom for a chain of points and return the combined curve.

"""

sz = len(P)

# The curve C will contain an array of (x,y) points.

C = []

for i in range(sz-3):

c = CatmullRomSpline(P[i], P[i+1], P[i+2], P[i+3])

C.extend(c)

return C

很好地计算n = 4点的插值,如下所示:

points = [[0,1.5],[2,2],[3,1],[4,0.5],[5,1],[6,2],[7,3]]

c = CatmullRomChain(points)

px, py = zip(*points)

x, y = zip(*c)

plt.plot(x, y)

plt.plot(px, py, 'or')

产生此matplotlib映像:

更新:

另外,还有一个针对BarycentricInterpolator的scipy.interpolate函数,它似乎可以满足您的需求.它使用起来非常简单,适用于只有3个数据点的情况.

from scipy.interpolate import BarycentricInterpolator

# create some data points

points1 = [[0, 2], [1, 4], [2, -2], [3, 6], [4, 2]]

points2 = [[1, 1], [2, 5], [3, -1]]

# put data into x, y tuples

x1, y1 =zip(*points1)

x2, y2 = zip(*points2)

# create the interpolator

bci1 = BarycentricInterpolator(x1, y1)

bci2 = BarycentricInterpolator(x2, y2)

# define dense x-axis for interpolating over

x1_new = np.linspace(min(x1), max(x1), 1000)

x2_new = np.linspace(min(x2), max(x2), 1000)

# plot it all

plt.plot(x1, y1, 'o')

plt.plot(x2, y2, 'o')

plt.plot(x1_new, bci1(x1_new))

plt.plot(x2_new, bci2(x2_new))

plt.xlim(-1, 5)

更新2

scipy中的另一个选项是通过Akima1DInterpolator进行akima插值.它与Barycentric一样容易实现,但是具有避免在数据集边缘发生大振荡的优点.这是一些测试案例,这些案例展示了您到目前为止所要求的所有条件.

from scipy.interpolate import Akima1DInterpolator

x1, y1 = np.arange(13), np.random.randint(-10, 10, 13)

x2, y2 = [0,2,3,6,12], [100,50,30,18,14]

x3, y3 = [4, 6, 8], [60, 80, 40]

akima1 = Akima1DInterpolator(x1, y1)

akima2 = Akima1DInterpolator(x2, y2)

akima3 = Akima1DInterpolator(x3, y3)

x1_new = np.linspace(min(x1), max(x1), 1000)

x2_new = np.linspace(min(x2), max(x2), 1000)

x3_new = np.linspace(min(x3), max(x3), 1000)

plt.plot(x1, y1, 'bo')

plt.plot(x2, y2, 'go')

plt.plot(x3, y3, 'ro')

plt.plot(x1_new, akima1(x1_new), 'b', label='random points')

plt.plot(x2_new, akima2(x2_new), 'g', label='exponential')

plt.plot(x3_new, akima3(x3_new), 'r', label='3 points')

plt.xlim(-1, 15)

plt.ylim(-10, 110)

plt.legend(loc='best')

标签:splines,scipy,matplotlib,python,excel

让用户可以随时查找曲线上任意的坐标(函数值) 附件的 .mht文件,是一个简单介绍贝塞尔三次插值的文档,可以用IE打开,更多贝塞尔插值的算法,可以用搜索引擎找 附件的 .xls文件,打开以后,会看见三个工作表,分别演示了 找一个数值在曲线上的一组对应 找一个数值在曲线上的所有对应 和贝塞尔曲线是怎样在通过每两个节的(每一对输入的X-Y数值代表平面坐标系的一个,称为节,Excel平滑曲线通过每一个节) 要在其他Excel文档使用 BezireInt() 函数,需要按Alt+F11,双击模块一 复制所有文字 然后打开其他Excel文档按Alt+F11,插入---模块,然后粘贴所有文字 自定义函数的使用方法是: 在空白单元格输入 =BezierInt(X坐标的范围,Y坐标的范围,待查的数值) 函数就会返回一个包含六个元素的数组,分别是三个的X,Y坐标 如: 你根据 a1:a4的数值作为X值,b2:b4的数值作为Y值,画了一个平滑线散点图 想查找c1的数值是不是在这条曲线上 就可以输入 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,1) 得到曲线上第一个 X值=C1数值的的X坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,2) 得到曲线上第一个 X值=C1数值的的Y坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,3) 得到第2个 X值=C1数值的的X坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,4) 得到第2个 X值=C1数值的的Y坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,5) 得到第3个 X值=C1数值的的X坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,6) 得到第3个 X值=C1数值的的Y坐标 如果有多段曲线上的包含C1的数值,那么可以增加输入参数,指定从哪个节开始查找 =Index( BezierInt(a1:a4,b1:b4,c1,3),1,1) 得到从第三组X-Y数据开始查找, 返回第一个符合C1数值的的X坐标 =Index( BezierInt(a1:a4,b1:b4,c1,3),1,2) 得到从第三组X-Y数据开始查找,返回第一个符合C1数值的的Y坐标 函数默认输入数值是X值,要根据Y值找的话,还可以增加输入参数, 指定输入的是Y值 =Index( BezierInt(a1:a4,b1:b4,c1,1,"Y"),1,1) 得到返回曲线上第一个 Y值=C1数值的的X坐标如此类推......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值