4

I am trying to write a Python GUI and I need to do a live plot. I currently have a program that receives data from a machine I am using and I want to be able to plot the values the machine outputs as I receive them. I have been researching and from what I have found so far, it doesn't seem to me like tkinter or any library can do this in a GUI. Does anyone know whether and how tkinter can do this or if there is another library that is capable of doing such a live plot?

Also, how would I go about writing the data that I gather to a file as I receive the data?

Thanks in advance for your help.

2 Answers2

8

It looks like you get the data by polling, which means you don't need threads or multiple processes. Simply poll the device at your preferred interface and plot a single point.

Here's an example with some simulated data to illustrate the general idea. It updates the screen every 100ms.

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()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
0

As far as I understand it, it can be done with tkinter/Qt/wxpython etc. You just have to make use of mutlithreading and multiprocessing. There may be a simpler way to do it with another module, but I am unaware of it.

I have been looking into something similar to this problem for a long time as well, and it appears that it is a constant issue among this community.

Here are some threads which talk about the issue:

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

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

Community
  • 1
  • 1
chase
  • 3,592
  • 8
  • 37
  • 58
  • Thanks for the links, those were helpful. But sorry, I am new to python and GUI programming so I just want to make sure i understand the problem. Is the reason people struggle plotting live to a GUI because although the new points are plotted, the graph doesn't resize to show the added points? – Sachin Weerasooriya Apr 01 '13 at 07:02
  • 1
    It's a bit strong to say you _have_ to make use of multithreading. That's only true if fetching the data requires a significant amount of time. If getting the data is cheap, a single thread is more than sufficient, since a GUI is generally idle about 99% of the time. – Bryan Oakley Apr 01 '13 at 11:38
  • @SachinWeerasooriya If you don't need the graph to resize, then using blitting to the Tkinter GUI will show the update of the data (points, lines, etc) through the GUI, so it will suffice. It just depends on what you are trying to do (if it is for a large amount of people or personal use, or needs to be expanded upon, etc.). Also, I probably shouldn't have included the whole community, I'm sure there are people who know how to do this easily. I just know there are a lot of questions about this from non CS majors such as myself, and therefore I assume it's a more complicated idea. – chase Apr 01 '13 at 16:33
  • Ok cool, thanks guys! Also, if I wanted to print the value of a variable that is constantly changing, do you know what widget in tkinter would be best for me to use that would update itself only showing the current value of the variable? – Sachin Weerasooriya Apr 02 '13 at 05:31
  • A [Tkinter label](http://effbot.org/tkinterbook/label.htm) is what I would start out with, although I'm not certain that it's the *best* widget for that. Also, since it appears you are starting on the path which I once took, I should mention that I started out in Tkinter and moved to Qt, because it looks fancier to me. They also have nice [examples of threaded programs](https://code.google.com/p/psymon/downloads/list) and it appears to be used by a large community. Feel free to check out my questions on here and ask any questions you want if you think I can help out on your specific project. – chase Apr 02 '13 at 16:00