对于实时数据,Tkinter matplotlib 画布更新太慢

Posted

技术标签:

【中文标题】对于实时数据,Tkinter matplotlib 画布更新太慢【英文标题】:Tkinter matplotlib canvas updates too slowly for real time data 【发布时间】:2020-10-31 11:23:30 【问题描述】:

我正在使用每秒发送 100 个读数的设备,我希望我的 GUI 有一个显示最后 300 个收集点的数据图。但是,我发现:

    将新数据点添加到 y 轴队列

    清除已经存在的情节

    绘制新的数据列表

    重绘画布

每个点之后需要将近 0.2 - 0.4 秒,这非常慢。

这是我目前使用的代码。一个while循环不断检查一个队列,一旦一个新元素被推送到它,它就会以元素作为参数调用update。任何人都可以提出一些改进效率或替代 matplotlib 的建议吗?

class GraphFrame:
    def __init__(self,root,channel,index):
        self.root=root
        self.frame=tk.Frame(self.root)
        self.frame.pack(side=tk.LEFT)
     
        self.y = Queue(maxsize = 300)
        
        self.fig, self.axes = plt.subplots(1,1)
        self.axes.plot(list(self.y.queue))

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, padx=5, pady=5)

    def update(self, new_point):
        if self.y.full():
            self.y.get()
        self.y.put(new_point)
        self.fig.axes[0].clear()
        self.fig.axes[0].plot(list(self.y.queue))
        self.canvas.draw()

编辑:设法解决了这个问题,使用 matplotlib 的 blitting 并将 Tkinter 画布替换为带有图形图像的标签。将尝试在github上上传代码并链接它。

【问题讨论】:

你应该修改线条艺术家,而不是清除图形并从头开始构建。 你能发一份代表数据的清单吗?也许像 15 - 25 个数据点? Queue 是从哪里导入的? @PaulH 数据点只是来自传感器的浮点读数。当没有人在它前面时,值约为 2000,当有人站在它前面时,值约为 20,000。浮点数没什么特别的。 @PaulH from queue import Queue 【参考方案1】:

我不会为每个新点重建你的图形,而是修改你已经拥有的 LineArtist。

class GraphFrame:
    def __init__(self,root,channel,index):
        self.root=root
        self.frame=tk.Frame(self.root)
        self.frame.pack(side=tk.LEFT)
     
        self.y = Queue(maxsize = 300)
        
        self.fig, self.axes = plt.subplots(1,1)

        # capture the artist
        self.line, = self.axes.plot(list(self.y.queue))

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, padx=5, pady=5)

    def update(self, new_point):
        if self.y.full():
            self.y.get()
        self.y.put(new_point)
        
        # update the artist
        self.line.set_xdata(list(range(len(self.y))))
        self.line.set_ydata(list(self.y.queue))

【讨论】:

self.line 是一个列表,它给出“列表对象没有属性 set_xdata” 编辑:没关系,我刚刚得到了该列表的第一个元素 [0] @MohamedMoustafa 您是否在作业中包含逗号?如果是这样,您可能只需要从该列表中提取第一个(也是唯一一个?)元素。 ok,self.y 是一个队列,所以我不能使用 len(),所以我使用了 .qsize()。该图不会在视觉上更新,当我调整 GUI 大小时,它会更新,但仅在 x = 0.00 和 y = 0 - 0.04+ 处显示一条垂直线 @MohamedMoustafa 哦,艺术家更新后可能需要self.fig.draw() self.fig.draw() 给出draw_wrapper() missing 1 required positional argument : 'renderer'。另外,请记住,这是 tkinter FigureCanvasTkAgg 中的图,而不仅仅是常规的 matplotlib 图。

以上是关于对于实时数据,Tkinter matplotlib 画布更新太慢的主要内容,如果未能解决你的问题,请参考以下文章

Tkinter规模小部件不实时更新

将 matplotlib 动画嵌入到 tkinter 帧中

实时3d视图pov-ray和tkinter

使用 matplotlib 在 Tkinter 中绘制数据 - 在列表之间切换

matplotlib 在 tkinter 画布中的缩放功能

无法使用按钮和自定义数据更新 Tkinter matplotlib 图