Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 模拟Excel';s";“平滑曲线散布”;Matplotlib中3点的样条函数_Python_Excel_Matplotlib_Scipy_Splines - Fatal编程技术网

Python 模拟Excel';s";“平滑曲线散布”;Matplotlib中3点的样条函数

Python 模拟Excel';s";“平滑曲线散布”;Matplotlib中3点的样条函数,python,excel,matplotlib,scipy,splines,Python,Excel,Matplotlib,Scipy,Splines,我试图模仿Excel的 插入>散布>带有平滑线和标记的散布 Matplotlib中的命令 scipy函数插值创建了类似的效果,这里有一些很好的示例说明如何简单地实现这一点: 然而,Excel的样条算法也能够通过三个点生成平滑曲线(例如,x=[0,1,2]y=[4,2,1]);用三次样条曲线是不可能做到的 我看到一些讨论表明Excel算法使用Catmull Rom样条曲线;但我并不真正理解这些,也不知道它们如何适应Matplotlib: 是否有一种简单的方法可以修改上述示例,使用插值库通过三个

我试图模仿Excel的

插入>散布>带有平滑线和标记的散布

Matplotlib中的命令

scipy函数插值创建了类似的效果,这里有一些很好的示例说明如何简单地实现这一点:

然而,Excel的样条算法也能够通过三个点生成平滑曲线(例如,x=[0,1,2]y=[4,2,1]);用三次样条曲线是不可能做到的

我看到一些讨论表明Excel算法使用Catmull Rom样条曲线;但我并不真正理解这些,也不知道它们如何适应Matplotlib:

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


非常感谢

到目前为止,您可能已经找到了的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
图像:

更新: 或者,还有一个
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中的另一个选项是通过akima插值。它与重心法一样易于实现,但其优点是避免了数据集边缘的大振荡。这里有几个测试用例,展示了到目前为止您所要求的所有标准

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')

@Lanery:Re:update2:最好的只是变得更好

必须将列表x2、y2、x3、y3重新定义为numpy数组,才能让您的示例在我的系统上运行(Spyder/Python 2.7):


但现在就像做梦一样!非常感谢您的专业知识和清晰的解释。

感谢您的及时回复和示例。但这并没有回答我原来的问题:1)样条曲线不经过第一个点和最后一个点2)它不适用于n=3。此外,这是否意味着无法使用插值库模拟Excel的样条函数?如果有任何进一步的建议,我将不胜感激。回到维基百科页面,Catmull Rom“是一种由四个控制点定义的插值样条线,
p0
p1
p2
p3
,曲线只从
p1
p2
,”因此样条曲线永远不会经过第一个点和最后一个点。我的猜测是Excel在进行样条拟合时进行了某种合理的外推,使得样条曲线通常看起来很拟合。为了回答您的第二个问题,我在
scipy.interpolate
中找不到任何类似于使用Catmull-Rom的方法。也就是说,还有另一种样条曲线方法,看起来它可以做你想做的事。请给我一分钟更新我的答案。另请参见:重心插值器使用拉格朗日插值将单个(高次)多项式拟合到点的每个坐标。这是已知的病态的许多(说超过8)点。相比之下,其他方案使用的样条曲线是分段低阶多项式。对于一般情况,我当然不推荐使用重心内极器。
x2 = np.array([0,2,3,6,12])
y2 = np.array([100,50,30,18,14])
x3 = np.array([4, 6, 8])
y3 = np.array([60, 80, 40])