Python 中的交互式 BSpline 拟合

2023-11-26

使用以下函数,可以在输入点 P 上拟合三次样条:

def plotCurve(P):
  pts = np.vstack([P, P[0]])
  x, y = pts.T
  i = np.arange(len(pts))

  interp_i = np.linspace(0, i.max(), 100000 * i.max())

  xi = interp1d(i, x, kind='cubic')(interp_i)  
  yi = interp1d(i, y, kind='cubic')(interp_i)

  fig, ax = plt.subplots()
  fig,ax=plt.subplots()
  ax.plot(xi, yi)
  ax.plot(x, y, 'ko')
  #plt.show()
  return xi,yi

输入点 P 可以采用以下形式:

P=[(921,1181),(951,1230),(993,1243),(1035,1230),
    (1065,1181),(1045,1130),(993,1130),(945,1130)]

现在,我希望使 P 的这些点可拖动,这样当我们更改任何点的位置时,样条线就会重新安装在新点上。

以此作为参考:https://matplotlib.org/1.4.3/examples/event_handling/poly_editor.html(matplotlib 中的事件处理),我有以下代码:

"""
This is an example to show how to build cross-GUI applications using
matplotlib event handling to interact with objects on the canvas

"""
import numpy as np
from matplotlib.lines import Line2D
from matplotlib.artist import Artist
from matplotlib.mlab import dist_point_to_segment

class PolygonInteractor:
    """
    An polygon editor.
Key-bindings

  't' toggle vertex markers on and off.  When vertex markers are on,
      you can move them, delete them

  'd' delete the vertex under point

  'i' insert a vertex at point.  You must be within epsilon of the
      line connecting two existing vertices

"""
showverts = True
epsilon = 5  # max pixel distance to count as a vertex hit

def __init__(self, ax, poly):
    if poly.figure is None:
        raise RuntimeError('You must first add the polygon to a figure or canvas before defining the interactor')
    self.ax = ax
    canvas = poly.figure.canvas
    self.poly = poly

    x, y = zip(*self.poly.xy)
    self.line = Line2D(x, y, marker='o', markerfacecolor='r', animated=True)
    self.ax.add_line(self.line)
    #self._update_line(poly)

    cid = self.poly.add_callback(self.poly_changed)
    self._ind = None # the active vert

    canvas.mpl_connect('draw_event', self.draw_callback)
    canvas.mpl_connect('button_press_event', self.button_press_callback)
    canvas.mpl_connect('key_press_event', self.key_press_callback)
    canvas.mpl_connect('button_release_event', self.button_release_callback)
    canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
    self.canvas = canvas


def draw_callback(self, event):
    self.background = self.canvas.copy_from_bbox(self.ax.bbox)
    self.ax.draw_artist(self.poly)
    self.ax.draw_artist(self.line)
    self.canvas.blit(self.ax.bbox)

def poly_changed(self, poly):
    'this method is called whenever the polygon object is called'
    # only copy the artist props to the line (except visibility)
    vis = self.line.get_visible()
    Artist.update_from(self.line, poly)
    self.line.set_visible(vis)  # don't use the poly visibility state


def get_ind_under_point(self, event):
    'get the index of the vertex under point if within epsilon tolerance'

    # display coords
    xy = np.asarray(self.poly.xy)
    xyt = self.poly.get_transform().transform(xy)
    xt, yt = xyt[:, 0], xyt[:, 1]
    d = np.sqrt((xt-event.x)**2 + (yt-event.y)**2)
    indseq = np.nonzero(np.equal(d, np.amin(d)))[0]
    ind = indseq[0]

    if d[ind]>=self.epsilon:
        ind = None

    return ind

def button_press_callback(self, event):
    'whenever a mouse button is pressed'
    if not self.showverts: return
    if event.inaxes==None: return
    if event.button != 1: return
    self._ind = self.get_ind_under_point(event)

def button_release_callback(self, event):
    'whenever a mouse button is released'
    if not self.showverts: return
    if event.button != 1: return
    self._ind = None

def key_press_callback(self, event):
    'whenever a key is pressed'
    if not event.inaxes: return
    if event.key=='t':
        self.showverts = not self.showverts
        self.line.set_visible(self.showverts)
        if not self.showverts: self._ind = None
    elif event.key=='d':
        ind = self.get_ind_under_point(event)
        if ind is not None:
            self.poly.xy = [tup for i,tup in enumerate(self.poly.xy) if i!=ind]
            self.line.set_data(zip(*self.poly.xy))
    elif event.key=='i':
        xys = self.poly.get_transform().transform(self.poly.xy)
        p = event.x, event.y # display coords
        for i in range(len(xys)-1):
            s0 = xys[i]
            s1 = xys[i+1]
            d = dist_point_to_segment(p, s0, s1)
            if d<=self.epsilon:
                self.poly.xy = np.array(
                    list(self.poly.xy[:i]) +
                    [(event.xdata, event.ydata)] +
                    list(self.poly.xy[i:]))
                self.line.set_data(zip(*self.poly.xy))
                break


    self.canvas.draw()

def motion_notify_callback(self, event):
    'on mouse movement'
    if not self.showverts: return
    if self._ind is None: return
    if event.inaxes is None: return
    if event.button != 1: return
    x,y = event.xdata, event.ydata

    self.poly.xy[self._ind] = x,y
    self.line.set_data(zip(*self.poly.xy))

    self.canvas.restore_region(self.background)
    self.ax.draw_artist(self.poly)
    self.ax.draw_artist(self.line)
    self.canvas.blit(self.ax.bbox)


if __name__ == '__main__':
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon

#theta = np.arange(0, 2*np.pi, 0.1)
#r = 1.5

#xs = r*np.cos(theta)
#ys = r*np.sin(theta)
xs = (921, 951, 993, 1035, 1065, 1045, 993, 945)
ys = (1181, 1230, 1243, 1230, 1181, 1130, 1130, 1130)

poly = Polygon(list(zip(xs, ys)), animated=True)

fig, ax = plt.subplots()
ax.add_patch(poly)
p = PolygonInteractor(ax, poly)

#ax.add_line(p.line)
ax.set_title('Click and drag a point to move it')
#ax.set_xlim((-2,2))
#ax.set_ylim((-2,2))

ax.set_xlim((800, 1300))
ax.set_ylim((1000, 1300))

plt.show()

现在,我想做的是用样条拟合函数替换多边形拟合。由于我对此很陌生,我不知道该怎么做。 有没有什么方法可以保持所有相同的功能,但仅通过给定点拟合样条曲线而不是多边形,使其具有交互性并根据点移动重新拟合样条曲线?

我的样条线看起来有点像这样:

enter image description here

我应该怎样去做呢?

或者,如果有其他合适的方法可以实现相同的目的,请推荐。

也欢迎使用 MATLAB 提出建议。


当然,您需要将您的功能添加到PolygonInteractor。但不要让它自己画任何东西。 然后向类中添加一个新行,self.line2这将是要更新的行。

最后,让全班同学也画出你的新路线。并用插值函数的结果更新它。

为了方便起见,您可以转动多边形(self.poly)不可见,也从self.line并且只显示要点可能才有意义。

enter image description here

import numpy as np
from  scipy.interpolate import interp1d
from matplotlib.lines import Line2D
from matplotlib.artist import Artist
from matplotlib.mlab import dist_point_to_segment


class PolygonInteractor(object):

    """
    A polygon editor.
    https://matplotlib.org/gallery/event_handling/poly_editor.html

    Key-bindings

      't' toggle vertex markers on and off.  When vertex markers are on,
          you can move them, delete them

      'd' delete the vertex under point

      'i' insert a vertex at point.  You must be within epsilon of the
          line connecting two existing vertices

    """

    showverts = True
    epsilon = 5  # max pixel distance to count as a vertex hit

    def __init__(self, ax, poly, visible=False):
        if poly.figure is None:
            raise RuntimeError('You must first add the polygon to a figure '
                               'or canvas before defining the interactor')
        self.ax = ax
        canvas = poly.figure.canvas
        self.poly = poly
        self.poly.set_visible(visible)

        x, y = zip(*self.poly.xy)
        self.line = Line2D(x, y, ls="",
                           marker='o', markerfacecolor='r',
                           animated=True)
        self.ax.add_line(self.line)

        self.cid = self.poly.add_callback(self.poly_changed)
        self._ind = None  # the active vert

        canvas.mpl_connect('draw_event', self.draw_callback)
        canvas.mpl_connect('button_press_event', self.button_press_callback)
        canvas.mpl_connect('key_press_event', self.key_press_callback)
        canvas.mpl_connect('button_release_event', self.button_release_callback)
        canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
        self.canvas = canvas

        x,y = self.interpolate()
        self.line2 = Line2D(x, y, animated=True)
        self.ax.add_line(self.line2)

    def interpolate(self):
        x, y = self.poly.xy[:].T
        i = np.arange(len(x))

        interp_i = np.linspace(0, i.max(), 100 * i.max())

        xi = interp1d(i, x, kind='cubic')(interp_i)  
        yi = interp1d(i, y, kind='cubic')(interp_i)

        return xi,yi

    def draw_callback(self, event):
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)
        self.ax.draw_artist(self.poly)
        self.ax.draw_artist(self.line)
        self.ax.draw_artist(self.line2)
        # do not need to blit here, this will fire before the screen is
        # updated

    def poly_changed(self, poly):
        'this method is called whenever the polygon object is called'
        # only copy the artist props to the line (except visibility)
        vis = self.line.get_visible()
        Artist.update_from(self.line, poly)
        self.line.set_visible(vis)  # don't use the poly visibility state


    def get_ind_under_point(self, event):
        'get the index of the vertex under point if within epsilon tolerance'

        # display coords
        xy = np.asarray(self.poly.xy)
        xyt = self.poly.get_transform().transform(xy)
        xt, yt = xyt[:, 0], xyt[:, 1]
        d = np.hypot(xt - event.x, yt - event.y)
        indseq, = np.nonzero(d == d.min())
        ind = indseq[0]

        if d[ind] >= self.epsilon:
            ind = None

        return ind

    def button_press_callback(self, event):
        'whenever a mouse button is pressed'
        if not self.showverts:
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return
        self._ind = self.get_ind_under_point(event)

    def button_release_callback(self, event):
        'whenever a mouse button is released'
        if not self.showverts:
            return
        if event.button != 1:
            return
        self._ind = None

    def key_press_callback(self, event):
        'whenever a key is pressed'
        if not event.inaxes:
            return
        if event.key == 't':
            self.showverts = not self.showverts
            self.line.set_visible(self.showverts)
            if not self.showverts:
                self._ind = None
        elif event.key == 'd':
            ind = self.get_ind_under_point(event)
            if ind is not None:
                self.poly.xy = np.delete(self.poly.xy,
                                         ind, axis=0)
                self.line.set_data(zip(*self.poly.xy))
        elif event.key == 'i':
            xys = self.poly.get_transform().transform(self.poly.xy)
            p = event.x, event.y  # display coords
            for i in range(len(xys) - 1):
                s0 = xys[i]
                s1 = xys[i + 1]
                d = dist_point_to_segment(p, s0, s1)
                if d <= self.epsilon:
                    self.poly.xy = np.insert(
                        self.poly.xy, i+1,
                        [event.xdata, event.ydata],
                        axis=0)
                    self.line.set_data(zip(*self.poly.xy))
                    break
        if self.line.stale:
            self.canvas.draw_idle()

    def motion_notify_callback(self, event):
        'on mouse movement'
        if not self.showverts:
            return
        if self._ind is None:
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return
        x, y = event.xdata, event.ydata

        self.poly.xy[self._ind] = x, y
        if self._ind == 0:
            self.poly.xy[-1] = x, y
        elif self._ind == len(self.poly.xy) - 1:
            self.poly.xy[0] = x, y
        self.line.set_data(zip(*self.poly.xy))

        x,y = self.interpolate()
        self.line2.set_data(x,y)

        self.canvas.restore_region(self.background)
        self.ax.draw_artist(self.poly)
        self.ax.draw_artist(self.line)
        self.ax.draw_artist(self.line2)
        self.canvas.blit(self.ax.bbox)


if __name__ == '__main__':
    import matplotlib.pyplot as plt
    from matplotlib.patches import Polygon

    #theta = np.arange(0, 2*np.pi, 0.1)
    #r = 1.5

    #xs = r*np.cos(theta)
    #ys = r*np.sin(theta)
    xs = (921, 951, 993, 1035, 1065, 1045, 993, 945)
    ys = (1181, 1230, 1243, 1230, 1181, 1130, 1130, 1130)

    poly = Polygon(list(zip(xs, ys)), animated=True)

    fig, ax = plt.subplots()
    ax.add_patch(poly)
    p = PolygonInteractor(ax, poly, visible=False)

    ax.set_title('Click and drag a point to move it')

    ax.set_xlim((800, 1300))
    ax.set_ylim((1000, 1300))

    plt.show()

请注意,此处创建的曲线并不是真正的循环曲线。它有一个曲线并不真正平滑的起点。这可以通过使用一组真正循环的贝塞尔曲线来避免,如下所示使用 matplotlib 创建随机形状/轮廓.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 中的交互式 BSpline 拟合 的相关文章

  • 如何传递架构以从现有数据帧创建新数据帧?

    要将 schema 传递到 json 文件 我们这样做 from pyspark sql types import StructField StringType StructType IntegerType data schema Stru
  • Python - 比较同一字典中的值

    我有一本字典 d Trump MAGA FollowTheMoney Clinton dems Clinton Stein FollowTheMoney Atlanta 我想删除字符串列表中的重复字符串 该字符串是键的值 对于这个例子 期望
  • 如何在 __init__ 中使用await设置类属性

    我如何定义一个类await在构造函数或类体中 例如我想要的 import asyncio some code class Foo object async def init self settings self settings setti
  • VSCode Settings.json 丢失

    我正在遵循教程 并尝试将 vscode 指向我为 Scrapy 设置的虚拟工作区 但是当我在 VSCode 中打开设置时 工作区设置 选项卡不在 用户设置 选项卡旁边 我还尝试通过以下方式手动转到文件 APPDATA Code User s
  • 我应该使用 Python 双端队列还是列表作为堆栈? [复制]

    这个问题在这里已经有答案了 我想要一个可以用作堆栈的 Python 对象 使用双端队列还是列表更好 元素数量较少还是数量较多有什么区别 您的情况可能会根据您的应用程序和具体用例而有所不同 但在一般情况下 列表非常适合堆栈 append is
  • 嵌套列表的重叠会产生不必要的间隙

    我有一个包含三个列表的嵌套 这些列表由 for 循环填充 并且填充由 if 条件控制 第一次迭代后 它可能类似于以下示例 a 1 2 0 0 0 0 0 0 4 5 0 0 0 0 0 0 6 7 根据条件 它们不重叠 在第二次迭代之后 新
  • PyQt 使用 ctrl+Enter 触发按钮

    我正在尝试在我的应用程序中触发 确定 按钮 我当前尝试的代码是这样的 self okPushButton setShortcut ctrl Enter 然而 它不起作用 这是有道理的 我尝试查找一些按键序列here http ftp ics
  • MongoEngine 查询具有以列表中指定的前缀开头的属性的对象的列表

    我需要在 Mongo 数据库中查询具有以列表中任何前缀开头的特定属性的元素 现在我有一段这样的代码 query mymodel terms term in query terms 并且这会匹配在列表 term 上有一个项目的对象 该列表中的
  • Python 内置的 super() 是否违反了 DRY?

    显然这是有原因的 但我没有足够的经验来认识到这一点 这是Python中给出的例子docs http docs python org 2 library functions html super class C B def method se
  • Python 3:将字符串转换为变量[重复]

    这个问题在这里已经有答案了 我正在从 txt 文件读取文本 并且需要使用我读取的数据之一作为类实例的变量 class Sports def init self players 0 location name self players pla
  • 通过Python连接到Bigquery:ProjectId和DatasetId必须非空

    我编写了以下脚本来通过 SDK 将 Big Query 连接到 Python 如下所示 from google cloud import bigquery client bigquery Client project My First Pr
  • 尽管我已在 python ctypes 中设置了信号处理程序,但并未调用它

    我尝试过使用 sigaction 和 ctypes 设置信号处理程序 我知道它可以与python中的信号模块一起使用 但我想尝试学习 当我向该进程发送 SIGTERM 时 但它没有调用我设置的处理程序 只打印 终止 为什么它不调用处理程序
  • 如何使用 Python 3 检查目录是否包含文件

    我到处寻找这个答案但找不到 我正在尝试编写一个脚本来搜索特定的子文件夹 然后检查它是否包含任何文件 如果包含 则写出该文件夹的路径 我已经弄清楚了子文件夹搜索部分 但检查文件却难倒了我 我发现了有关如何检查文件夹是否为空的多个建议 并且我尝
  • Spider 必须返回 Request、BaseItem、dict 或 None,已“设置”

    我正在尝试从以下位置下载所有产品的图像 我的蜘蛛看起来像 from shopclues items import ImgData import scrapy class multipleImages scrapy Spider name m
  • Python:Goslate 翻译请求返回“503:服务不可用”[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我们不允许提出寻求书籍 工具 软件库等推荐的问题 您可以编辑问题 以便用事实和引文来回答 这个问题似乎不是关于主要由程序员使用的特定编程问
  • 重新分配唯一值 - pandas DataFrame

    我在尝试着assign unique值在pandas df给特定的个人 For the df below Area and Place 会一起弥补unique不同的价值观jobs 这些值将分配给个人 总体目标是使用尽可能少的个人 诀窍在于这
  • 如何将 Django 中的权限添加到模型并使用 shell 进行测试

    我在模型中添加了 Meta 类并同步了数据库 然后在 shell 中创建了一个对象 它返回 false 所以我真的无法理解错误在哪里或者缺少什么是否在其他文件中可能存在某种配置 class Employer User Employer in
  • 等待子进程使用 os.system

    我用了很多os system在 for 循环内调用创建后台进程 如何等待所有后台进程结束 os wait告诉我没有子进程 ps 我使用的是Solaris 这是我的代码 usr bin python import subprocess imp
  • 在virtualenv中下载sqlite3

    我正在尝试使用命令创建应用程序python3 manage py startapp webapp但我收到一条错误消息 django core exceptions ImproperlyConfigured 加载时出错 pysqlite2 或
  • pytest找不到模块[重复]

    这个问题在这里已经有答案了 我正在关注pytest 良好实践 https docs pytest org en latest explanation goodpractices html test discovery或者至少我认为我是 但是

随机推荐

  • 为什么向 MySQL 查询添加“*”会导致语法错误?

    在 MySQL 中 这段代码运行良好 select f blegg from blegg limit 1 f f g h 17 17 2 17 1 row in set 0 00 sec 那么为什么这段代码会导致语法错误呢 select f
  • 如何指定使用 if let 时无法推断的类型?

    我想写以下内容if let but Ok config 没有提供类型toml from str let result Result
  • 如何找到一个小部件的唯一且恒定的 ID?

    请注意 对于小部件 这不包括画布项 不是小部件 我的目标是构建两个类 一个类生成画布小部件的项目 另一个类生成小部件本身 这是为了确保我可以在窗口中移动东西并在重新打开时将其保留在那里 我已经为画布项目完成了此操作 您会看到 画布小部件实际
  • Android:在绘制视图之前获取视图的高度

    对于动画 我需要知道视图的高度 问题是 除非绘制视图 否则 getHeight 方法总是返回 0 那么有没有办法不用画图就能得到高度呢 在本例中 View 是 LinearLayout 编辑 我尝试改编扩展动画https github co
  • 如何防止我的 Shiny 应用程序在开源闪亮服务器中断开连接?

    我正在使用 Ubuntu 和 NGINX 在开源闪亮服务器上运行 R闪亮应用程序 但是 由于某种原因 我的应用程序不断收到 与服务器断开连接 的消息 而且我似乎无法让它工作 这个闪亮的应用程序在我的本地运行得非常好 我已经通过以下建议尝试了
  • 在 python 中设置自定义异常的退出代码

    我使用自定义异常来将我的异常与 Python 的默认异常区分开来 当我引发异常时 有没有办法定义自定义退出代码 class MyException Exception pass def do something bad raise MyEx
  • 将 OneSignal 与 Angular 集成

    我正在尝试将 OneSignal 集成到我的 Angular 2 应用程序中以接收推送通知 首先 我使用普通的旧 HTML 制作了一个 HelloWorld 应用程序 它运行得非常漂亮 因此 我尝试将其包含到我的 Angular 应用程序中
  • 如何在不使用 R 读取整个文件的情况下确定远程下载的文件大小

    是否有一种相当简单的方法来确定远程文件的文件大小 而无需下载整个文件 Stack Overflow 回答了如何执行此操作使用 PHP 和curl 所以我想这在 R 中也是可能的 如果可能的话 我认为最好避免使用 RCurl 因为这需要对非
  • 使用 C# 和 IIS 7 保护大型下载

    这是设置 1 个运行 C 应用程序的 Web 服务器 我的用户 存储在所述服务器上的 MySQL 数据库中 对其进行身份验证 1 个运行软件的文件服务器待定 过去 我使用 lighttpd 和 mod secdownload 来保护文件服务
  • 使用 Maven 构建时,运行时缺少 jaxb.properties

    我有一个项目 我想使用 JAXB 从 XSD 生成的一组类 通过这些类 我想从 XML 和 JSON 进行编组 解组 我发现我需要 Moxy Eclipselink 来做我需要的事情 我将我的类和流程作为 Ant 项目进行了测试 然后我决定
  • StringEscapeUtils.escapeXml 正在转换不应转换的 utf8 字符

    escapeXml函数正在转换 to amp 1133 amp 1134 我想不应该 我读到的是它仅支持五个基本 XML 实体 gt lt quot amp apos 有没有一个函数只转换这五个基本的xml实体 public String
  • 使用 MSVC 强制导出符号

    我有一个应用程序和几个 DLL 文件中的插件 这些插件使用的符号来自 通过导出库应用程序 该应用程序链接到几个静态库 这是大多数符号的来源 只要应用程序使用符号 这就可以正常工作 如果此处未使用该符号 则在编译 DLL 时会出现链接器错误
  • float指针和int指针地址有什么区别?

    我尝试运行这段代码 int p float q q 6 6 p q 虽然这将是一个警告 但我认为 q and p大小相同 所以p可以有一个地址q 但是当我打印时 q and p我得到不同的输出 这是我的输出 p 6 600000 q 0 0
  • FireMonkey 控件的动画效果不流畅

    背景 我使用一些 FireMonkey 控件创建了一个 GUI 有些控件是动画的 它们的外观会自动更新 某些控件仅响应用户交互 滑块等 而更新 Problem 与用户控件的交互会阻止对动画控件的更新 从而导致动画不连续 有问题的动画视频 上
  • 找到可用(未加载)的 PHP 扩展

    我需要一种方法来查找所有可用的 PHP 扩展是否已加载 我在看如何查看 PHP 加载的扩展 但它只解释了如何找到加载的扩展 我也想要一种找到卸载的扩展的方法 从 php ini 知道了 extension dir 我做了一个ls exten
  • 如何使用jquery旋转插件旋转图像?

    如何使用旋转图像jQuery 旋转 plugin 我已经尝试过以下方法 但似乎不起作用
  • 使用Python请求“桥接”文件而不加载到内存中?

    我想使用Python 请求库从 URL 获取文件并将其用作发布请求中的多部分编码文件 问题是该文件可能非常大 50MB 2GB 我不想将其加载到内存中 语境here 以下文档中的示例 多部分 流下来 and 流起来 我做了这样的东西 wit
  • JavaScript 函数 parseInt() 无法正确解析以 0 开头的数字

    我在正整数之前有一些零 我想删除零 这样只保留正整数 就像 001 只会是 1 我认为最简单的方法是使用 parseInt 001 但我发现它不适用于数字 8 和 9 示例 parseInt 008 将产生 0 而不是 8 以下是完整的 h
  • Swift 动态类型检查结构?

    我对 Swift 中的动态类型检查感到困惑 具体来说 我有一个奇怪的情况 本质上我想编写 或查找 一个函数 func isInstanceOf obj Any type Any Type gt Bool 在 Objective C 中 这是
  • Python 中的交互式 BSpline 拟合

    使用以下函数 可以在输入点 P 上拟合三次样条 def plotCurve P pts np vstack P P 0 x y pts T i np arange len pts interp i np linspace 0 i max 1