Python GUI 中的实时绘图

Posted

技术标签:

【中文标题】Python GUI 中的实时绘图【英文标题】:Live Plot in Python GUI 【发布时间】:2013-03-22 02:40:12 【问题描述】:

我正在尝试编写 Python GUI,并且需要进行实时绘图。我目前有一个程序从我正在使用的机器接收数据,我希望能够在收到机器输出的值时绘制它们。我一直在研究,从我目前的发现来看,在我看来,tkinter 或任何库都不能在 GUI 中做到这一点。有谁知道 tkinter 是否以及如何做到这一点,或者是否有另一个库能够进行这样的实时绘图?

另外,当我收到数据时,我将如何将收集到的数据写入文件?

提前感谢您的帮助。

【问题讨论】:

wxPython 会更适合这份工作吗? 你的程序目前是如何接收数据的? @SachinWeerasooriya: wxPython more 适合吗?可能不是。也许同样合适。 嗯,这里是实际代码github.com/PowerAndEnergySystemsUIUC/ServoStar_python/blob/… 的链接,但基本上有一个“ServoDrive”类,它有不同的方法来获得我想随时间绘制的速度和扭矩 【参考方案1】:

看起来你是通过轮询来获取数据的,这意味着你不需要线程或多个进程。只需在您喜欢的界面上轮询设备并绘制一个点。

这是一个示例,其中包含一些模拟数据来说明总体思路。它每 100 毫秒更新一次屏幕。

import Tkinter as tk
import random

class ServoDrive(object):
    # simulate values
    def getVelocity(self): return random.randint(0,50)
    def getTorque(self): return random.randint(50,100)

class Example(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        self.servo = ServoDrive()
        self.canvas = tk.Canvas(self, background="black")
        self.canvas.pack(side="top", fill="both", expand=True)

        # create lines for velocity and torque
        self.velocity_line = self.canvas.create_line(0,0,0,0, fill="red")
        self.torque_line = self.canvas.create_line(0,0,0,0, fill="blue")

        # start the update process
        self.update_plot()

    def update_plot(self):
        v = self.servo.getVelocity()
        t = self.servo.getTorque()
        self.add_point(self.velocity_line, v)
        self.add_point(self.torque_line, t)
        self.canvas.xview_moveto(1.0)
        self.after(100, self.update_plot)

    def add_point(self, line, y):
        coords = self.canvas.coords(line)
        x = coords[-2] + 1
        coords.append(x)
        coords.append(y)
        coords = coords[-200:] # keep # of points to a manageable size
        self.canvas.coords(line, *coords)
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

【讨论】:

哇,我认为这非常适合我正在尝试做的事情。非常感谢! 如果您将“Tkinter”更改为“tkinter”,它也适用于 Python 3!【参考方案2】:

据我了解,可以使用 tkinter/Qt/wxpython 等来完成。您只需要使用mutlithreadingmultiprocessing。 使用另一个模块可能有更简单的方法,但我不知道。

我也一直在研究与此问题类似的问题,并且似乎这是该社区中一直存在的问题。

这里有一些讨论这个问题的线程:

How do I refresh a matplotlib plot in a Tkinter window?

How do I update a matplotlib figure while fitting a function?

【讨论】:

感谢您的链接,这些链接很有帮助。但抱歉,我是 python 和 GUI 编程的新手,所以我只是想确保我理解这个问题。人们难以在 GUI 上实时绘图的原因是因为虽然绘制了新点,但图表没有调整大小以显示添加的点? 说你使用多线程有点强。仅当获取数据需要大量时间时才如此。如果获取数据的成本很低,那么单个线程就足够了,因为 GUI 通常大约 99% 的时间都是空闲的。 @SachinWeerasooriya 如果您不需要调整图形大小,那么对 Tkinter GUI 使用 blitting 将通过 GUI 显示数据(点、线等)的更新,因此就足够了.它只是取决于你想要做什么(如果它是为了大量的人或个人使用,或者需要扩展等)。另外,我可能不应该包括整个社区,我相信有些人知道如何轻松做到这一点。我只知道像我这样的非 CS 专业的学生对此有很多问题,因此我认为这是一个更复杂的想法。 好的,谢谢大家!另外,如果我想打印一个不断变化的变量的值,你知道 tkinter 中的哪个小部件最适合我使用,它会自我更新,只显示变量的当前值? A Tkinter label 是我开始使用的,尽管我不确定它是否是 最好的 小部件。此外,由于您似乎开始走上我曾经走的路,我应该提到我从 Tkinter 开始并移至 Qt,因为它对我来说看起来更漂亮。他们也有很好的examples of threaded programs,它似乎被一个大型社区使用。如果您认为我可以为您的特定项目提供帮助,请随时查看我的问题并提出任何您想要的问题。

以上是关于Python GUI 中的实时绘图的主要内容,如果未能解决你的问题,请参考以下文章

在 tkinter 画布中嵌入来自 Arduino 的 Matplotlib 实时绘图数据

Python Qt GUI设计:QPainterQPenQBrush和QPixmap窗口绘图类(基础篇—17)

Python Qt GUI设计:QPainterQPenQBrush和QPixmap窗口绘图类(基础篇—17)

Matplotlib“实时”在python中绘图

用Python串口实时显示数据并绘图pyqtgraph(详细教程)

Python Tkinter 在 GUI 中嵌入 Matplotlib