You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用BLIT实现实时绘图时无法清除旧线条的问题

解决Matplotlib实时绘图Blit模式下重复线条问题

问题根源分析

  1. 背景保存时机错误:每个Plot实例初始化时就保存背景,但后续创建的子图会修改整个画布,导致保存的bg不是最终的干净画布状态。
  2. 重复绘制静态元素:每次update都重新调用ax.legend()和ax.set_title(),这些静态元素未被包含在blit缓存中,会被重复绘制。
  3. 自动缩放破坏缓存:ax.relim()和ax.autoscale_view()会触发坐标轴重绘,导致之前保存的背景失效,旧线条残留。

修改后的代码实现

修正后的Plot类

class Plot():
    def __init__(self, fig, ax, grain, name, color) -> None:
        self.fig = fig
        self.ax = ax
        
        self.xData = range(grain)
        self.yData = [0] * grain 
        
        self.name = name
        self.color = color
        
        # 初始化曲线,设置动画属性
        self.ln, = self.ax.plot(self.xData, self.yData, animated=True, label=self.name, color=f"C{color}")
        
        # 初始化静态元素并标记为animated
        self.title = self.ax.set_title(self.name)
        self.legend = self.ax.legend()
        self.title.set_animated(True)
        self.legend.set_animated(True)
        
        # 暂不保存背景,统一在LiveGraph初始化完成后保存
        self.bg = None

    def update(self, y):
        # 恢复背景
        self.fig.canvas.restore_region(self.bg)
        
        # 更新数据
        self.yData.append(y)
        self.yData.pop(0)
        self.ln.set_ydata(self.yData)
        
        # 如果需要自动缩放,需重新计算背景(可选)
        # self.ax.relim()
        # self.ax.autoscale_view()
        # self.bg = self.fig.canvas.copy_from_bbox(self.ax.bbox)
        
        # 重绘动态元素
        self.ax.draw_artist(self.ln)
        self.ax.draw_artist(self.title)
        self.ax.draw_artist(self.legend)
        
        # 更新指定区域
        self.fig.canvas.blit(self.ax.bbox)
        self.fig.canvas.flush_events()

修正后的LiveGraph类

import matplotlib.pyplot as plt
import math

class LiveGraph():
    def __init__(self, plotNum, names) -> None:
        self.fig = plt.figure()
        self.plots = []
        
        # 创建所有子图
        for i in range(plotNum):
            ax = self.fig.add_subplot(plotNum, 1, i+1)
            plot = Plot(self.fig, ax, 100, names[i], i)
            self.plots.append(plot)
        
        # 所有元素初始化完成后,统一保存每个子图的背景
        self.fig.canvas.draw()
        for plot in self.plots:
            plot.bg = self.fig.canvas.copy_from_bbox(plot.ax.bbox)
        
        self.tick = 0
        plt.show(block=False)
        plt.pause(0.1)  

    def update(self):
        self.tick += 1
        y_val = math.sin(self.tick/10)
        for plot in self.plots:
            plot.update(y_val)

if __name__ == "__main__":
    LG = LiveGraph(2, ["test1", "test2"])
    while True:
        LG.update()

关键修改说明

  1. 延迟背景保存:在LiveGraph中所有子图和静态元素创建完成后,先调用self.fig.canvas.draw()绘制整个画布,再保存每个子图的背景,确保bg是干净的初始状态。
  2. 静态元素标记动画:将标题、图例等静态元素设置为animated=True,让blit机制将它们包含在缓存中,避免重复绘制。
  3. 移除重复静态元素绘制:不在update中重复创建标题和图例,只在初始化时创建一次。
  4. 可选自动缩放处理:如果需要自动缩放,每次缩放后要重新保存背景,否则会导致线条残留(不需要自动缩放可直接注释相关代码)。

内容的提问来源于stack exchange,提问作者Paul Weder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 22:52:43