Matplotlib 中的动态图形更新

195 阅读2分钟

在使用 Matplotlib 进行数据可视化时,经常需要更新图形上的数据,例如曲线、点或文本。然而,如果每次更新都需要重新绘制整个图形,则效率非常低,尤其是在数据量较大的情况下。

  1. 解决方案

    为了提高图形更新的效率,Matplotlib 提供了多种方法来更新图形上的数据,而无需重新绘制整个图形。一种常见的解决方案是使用 set_data() 方法直接更新数据。set_data() 方法可以更新线上的数据点,也可以更新散点图中的点。

    例如,以下代码演示了如何使用 set_data() 方法更新线上的数据点:

    import matplotlib.pyplot as plt
    
    # 创建一个线图
    x = np.linspace(0, 10, 100)
    y = np.sin(x)
    line, = plt.plot(x, y)
    
    # 更新线上的数据点
    y = np.cos(x)
    line.set_data(x, y)
    
    # 重新绘制图形
    plt.draw()
    

    运行这段代码,可以看到线上的数据点已经更新。

    另一种常见的解决方案是使用 cla()clf() 方法来清除图形。cla() 方法可以清除当前的轴,clf() 方法可以清除整个图形。例如,以下代码演示了如何使用 cla() 方法清除当前的轴:

    import matplotlib.pyplot as plt
    
    # 创建一个线图
    x = np.linspace(0, 10, 100)
    y = np.sin(x)
    line, = plt.plot(x, y)
    
    # 清除当前的轴
    plt.cla()
    
    # 重新创建线图
    line, = plt.plot(x, y)
    
    # 重新绘制图形
    plt.draw()
    

    运行这段代码,可以看到线图已被重新创建。

代码例子

import matplotlib.pyplot as plt

class ECC(object):
    def __init__(self, a, b, px, qx, qy):
        # 初始化输入变量
        self.a = a
        self.b = b
        self.pxlam = px
        self.qxlam = qx
        self.invertQy = qy
        self.fig = plt.figure(1)
        self.ax = SubplotZero(self.fig, 111)
        self.xr = 0
        self.yr = 0
        self._tracker = []  # 跟踪器,用于存储所有需要更新的元素

    def onclick(self, event):
        x = event.xdata

        if event.button == 1:
            self.pxlam = x

        if event.button == 3:
            self.qxlam = x

        pylam = self.ecclambda(self.pxlam, self.a, self.b)  # 计算 P
        qylam = self.ecclambda(self.qxlam, self.a, self.b)  # 计算 Q

        if self.invertQy == 1:  qylam = -qylam  # 可选,将 qy 反转为负

        # 清除所有需要更新的元素
        for element in self._tracker:
            element.remove()

        self._tracker = []  # 重置跟踪器

        # 创建新的元素
        self.p, = plt.plot([self.pxlam], [pylam], "mo")[0]
        self.q, = plt.plot([self.qxlam], [qylam], "mo")[0]
        self.pt = plt.text(self.pxlam-0.25, pylam+0.5, '$P$')
        self.qt = plt.text(self.qxlam-0.25, qylam+0.5, '$Q$')

        self.xr, self.yr = self.dataToPlotR(pylam, qylam)
        self.r, = plt.plot([self.pxlam, self.xr], [qylam, self.yr], color="c", linewidth=1)
        plt.plot([self.xr], [self.yr], "mo")
        plt.plot([self.xr], [-1*(self.yr)], "co")
        plt.text(self.xr+0.25, self.yr, '$-R$'); plt.text(self.xr+0.25,-1*(self.yr), '$R$')
        plt.text(-9, 6, 'P: (%s ,%s) \n Q: (%s ,%s) \n R: (%s ,%s) \n a: %s \n b: %s '
                % (self.pxlam, pylam, self.qxlam, qylam, self.xr, -1*(self.yr), self.a, self.b),
                fontsize=10, color='blue', bbox=dict(facecolor='tan', alpha=0.5))

        # 添加新的元素到跟踪器
        self._tracker.extend([self.p, self.q, self.pt, self.qt, self.r])

        # 重新绘制图形
        plt.draw()

    def update(self):
        pylam = self.ecclambda(self.pxlam, self.a, self.b)
        qylam = self.ecclambda(self.qxlam, self.a, self.b)

        self.p.set_data([self.pxlam], [pylam])
        self.q.set_data([self.qxlam], [qylam])
        self.pt.set_x(self.pxlam-0.25)
        self.pt.set_y(pylam+0.5)
        self.qt.set_x(self.qxlam-0.25)
        self.qt.set_y(qylam+0.5)

        self.xr, self.yr = self.dataToPlotR(pylam, qylam)