1

I want to plot real-time data as a file is updated. I have my run routine as follows (I read the data in the live plot and then attempt to plot it):

def run(self):
        os.startfile("TPSLogger.exe")
        self.running = True # Now running
        self.new_f = self.find_latest_file()
        plt.figure()
        self.live_plot()

I have abstracted out a lot of the unnecessary code in relation to this question. Then in the live_plot routine:

    def live_plot(self):
        file_size = os.path.getsize(self.new_f) # The new file size
        if self.running:
            if file_size != self.new_pointer:
                channels, self.new_pointer = writeToExcel.conversion(self, self.new_f, self.new_pointer)
                c_count = 1
                for channel in channels:
                    if len(channel) == 0:
                        pass # Empty channel
                    else:
                        plt.plot(channel[0]) # Plot the data
                        
                    c_count += 1
            self.after(self.timing, self.live_plot) # Redo after a certain time
        else:
            # We are now longer running
            plt.show()

First off, do I need to store plt as an attribute of the class which it is in? Secondly when I place plt.show() just outside the for loop it shows the first graph (pulse) and then doesn't show the rest and freezes. Is there a better way to read the file in periods of x seconds without the plot freezing - the GUI works fine during all of this as by the way.

As it is now it plots all the data once the program is finished. Is there a way for me to plot the data as it comes in?

Here is a MCVE:

import matplotlib.pyplot as plt
import tkinter as tk
import random
class tkinterApp(tk.Tk):
     
    # __init__ function for class tkinterApp
    def __init__(self, *args, **kwargs):
         
        tk.Tk.__init__(self, *args, **kwargs)

        # creating a container
        container = tk.Frame(self) 
        container.pack(side = "top", fill = "both", expand = True)
  
        container.grid_rowconfigure(0, weight = 1)
        container.grid_columnconfigure(0, weight = 1)
        self.frames = {} 
        frame = MCVE(container, self)
        self.frames[MCVE] = frame
        frame.grid(row = 0, column = 0, sticky ="nsew")
        self.show_frame(MCVE)
    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

class MCVE(tk.Frame):    
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.channel = [1, 2, 3, 4, 2, 1]
        runButton = tk.Button(self, text="Run", command=self.run)
        runButton.pack()
    def run(self):
        self.live_plot()
    
    def live_plot(self):
        print("iterating.")
        if len(self.channel) == 0:
            pass # Empty channel
        else:
            plt.plot(self.channel)
        plt.show()
        self.channel.append(random.randint(0,10))
        self.after(1000, self.live_plot) # Redo after a certain time


app = tkinterApp()
app.mainloop()
Governor
  • 300
  • 1
  • 10

0 Answers0