Threading multiple animated plots in GUI with python3 Threading multiple animated plots in GUI with python3 tkinter tkinter

Threading multiple animated plots in GUI with python3


I finally figured out how to make all the plots work and update live. Turns out I needed a figure for each plot that was on a different page of the GUI. And I removed the threading for the figures because it caused performance problems in the real application. Turns out it was faster and more responsive without the threading. A fully working version of the code is at the bottom:

f = Figure(figsize=(9,6), dpi=100)aPlot = f.add_subplot(211)aPlot2 = f.add_subplot(212)f2 = Figure(figsize=(9,6), dpi=100)bPlot = f2.add_subplot(211)bPlot2 = f2.add_subplot(212)f0 = Figure(figsize=(9,6), dpi=100)cPlot = f0.add_subplot(211)cPlot2 = f0.add_subplot(212)f4 = Figure(figsize=(9,6), dpi=100)dPlot = f4.add_subplot(211)dPlot2 = f4.add_subplot(212)

Then I needed a different function to animate each figure. So it was a lot of redundant code. There must be a better way to accomplish this.

def animate(i):    pullData = open("sampleData.txt", "r").read()    dataList = pullData.split('\n')    remote_file = dataList    curFrame = []    recFrame = []    #global mode    #mode = []    #bytesRead = []    #missingFrames = []    plossRate = []    counter = []    counter2 = []    counter2.append(0)    #print("i is: " + str(i))    value = 0    for eachLine in remote_file:        if len(eachLine)>1:            value=value+1            #a, b, c, d, e = eachLine.split(',')            #curFrame.append(int(a))            #recFrame.append(int(b))            mode.append(random.randint(1,3))            #bytesRead.append(int(d))            #missingFrames.append(int(e))            plossRate.append(random.randint(0,90))            counter.append(int(value))            counter2.append(int(value))            #print("mode = " + str(c) + " lastFrame =  " + str(b) + "  conter = " + str(value))    aPlot.clear()    aPlot2.clear()    aPlot.plot(counter, plossRate)    aPlot.set_title('Packet Loss Rate')    aPlot.set_ylabel('Percentage')    aPlot2.plot(counter, mode[-counter[-1]:], 'bo')    #aPlot2.axis(0,counter[-1],0,3)    aPlot2.set_title('Current Audio Mode')    aPlot2.set_ylabel('mode')    #finally:    #pullData.close()def make_plot(i):    pullData = open("sampleData.txt", "r").read()    dataList = pullData.split('\n')    remote_file = dataList    curFrame = []    recFrame = []    #global mode    #mode = []    #bytesRead = []    #missingFrames = []    #plossRate = []    counter = []    counter2 = []    counter2.append(0)    value = 0    for eachLine in remote_file:        if len(eachLine)>1:            value=value+1            #a, b, c, d, e = eachLine.split(',')            #curFrame.append(int(a))            #recFrame.append(int(b))            mode.append(random.randint(1,3))            #bytesRead.append(int(d))            #missingFrames.append(int(e))            plossRate.append(random.randint(0,90))            counter.append(int(value))            counter2.append(int(value))            #print("mode = " + str(c) + " lastFrame =  " + str(b) + "  conter = " + str(value))    bPlot.clear()    bPlot2.clear()    bPlot.plot(counter, plossRate[-counter[-1]:])    bPlot.set_title('Packet Loss Rate')    bPlot.set_ylabel('Percentage')    bPlot2.plot(counter, mode[-counter[-1]:], 'bo')    #aPlot2.axis(0,counter[-1],0,3)    bPlot2.set_title('Current Audio Mode')    bPlot2.set_ylabel('mode')def base_plot(i):    pullData = open("sampleData.txt", "r").read()    dataList = pullData.split('\n')    remote_file = dataList    curFrame = []    recFrame = []    #global mode    #mode = []    #bytesRead = []    #missingFrames = []    #plossRate = []    counter = []    counter2 = []    counter2.append(0)    value = 0    for eachLine in remote_file:        if len(eachLine)>1:            value=value+1            #a, b, c, d, e = eachLine.split(',')            #curFrame.append(int(a))            #recFrame.append(int(b))            mode.append(random.randint(1,3))            #bytesRead.append(int(d))            #missingFrames.append(int(e))            plossRate.append(random.randint(0,90))            counter.append(int(value))            counter2.append(int(value))            #print("mode = " + str(c) + " lastFrame =  " + str(b) + "  conter = " + str(value))    cPlot.clear()    cPlot2.clear()    cPlot.plot(counter, plossRate[-counter[-1]:])    cPlot.set_title('Packet Loss Rate')    cPlot.set_ylabel('Percentage')    cPlot2.plot(counter, mode[-counter[-1]:], 'bo')    #aPlot2.axis(0,counter[-1],0,3)    cPlot2.set_title('Current Audio Mode')    cPlot2.set_ylabel('mode')def livePlot(i):    pullData = open("sampleData.txt", "r").read()    dataList = pullData.split('\n')    remote_file = dataList    curFrame = []    recFrame = []    #global mode    #mode = []    #bytesRead = []    #missingFrames = []    #plossRate = []    counter = []    counter2 = []    counter2.append(0)    value = 0    for eachLine in remote_file:        if len(eachLine)>1:            value=value+1            #a, b, c, d, e = eachLine.split(',')            #curFrame.append(int(a))            #recFrame.append(int(b))            mode.append(random.randint(1,3))            plossRate.append(random.randint(0,90))            counter.append(int(value))            counter2.append(int(value))            #print("mode = " + str(c) + " lastFrame =  " + str(b) + "  conter = " + str(value))    dPlot.clear()    dPlot2.clear()    dPlot.plot(counter, plossRate[-counter[-1]:])    dPlot.set_title('Packet Loss Rate')    dPlot.set_ylabel('Percentage')    dPlot2.plot(counter, mode[-counter[-1]:], 'bo')    dPlot2.set_title('Current Audio Mode')    dPlot2.set_ylabel('mode')

Then in the app main loop I had to call all of these:

ani1 = animation.FuncAnimation(f, animate, interval=1000)ani2 = animation.FuncAnimation(f2, make_plot, interval=1000)ani3 = animation.FuncAnimation(f0, base_plot, interval=1000)ani4 = animation.FuncAnimation(f4, livePlot, interval=1000)

Here is a working version of the python code:

gui3.py

#!/usr/bin/env python3import paramiko, threadingimport time, os, subprocessfrom subprocess import Popenimport sys# if not sys.warnoptions:#   import warnings#   warnings.simplefilter("ignore")import matplotlibmatplotlib.use("TkAgg")from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tkfrom matplotlib.figure import Figureimport matplotlib.animation as animationfrom matplotlib import styleimport tkinter as tkfrom tkinter import ttk# Just being used to debug plotsimport randomfrom matplotlib import pyplot as pltLARGE_FONT=("Verdana", 12)style.use("ggplot")f = Figure()aPlot = f.add_subplot(211)aPlot2 = f.add_subplot(212)f2 = Figure(figsize=(9,6), dpi=100)bPlot = f2.add_subplot(211)bPlot2 = f2.add_subplot(212)f0 = Figure(figsize=(9,6), dpi=100)cPlot = f0.add_subplot(211)cPlot2 = f0.add_subplot(212)f4 = Figure(figsize=(9,6), dpi=100)dPlot = f4.add_subplot(211)dPlot2 = f4.add_subplot(212)###==========================================================================================### BEGIN FUNCS 4 FUN ###++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# Function to execute the C++ code over ssh (Adaptive mode is default):def start_ssh():    print("SSH started")# Function to update live labelsdef label_reader(label):    def reader():        label.config(text="Mode: "+ str(mode[-1]))        label.after(100, reader)    reader()def loss_label_reader(label):    def reader():        label.config(text="Loss: "+ str(plossRate[-1]))        label.after(100, reader)    reader()# Function to kill the processes running the C++ networking code:def clear():    print("processes closed")# Function to execute the C++ code over ssh using only Mode 1:def start_ssh_singleMode():        print("SSH single mode started")# Function to setup interference and/or set it back to 0%:def interference_setup():        print("Interference setup")# Function to add a hard-coded amount of interference:def add_interference():        print("Interference added")global modemode = ["0"]global plossRateplossRate = ["0"]global counter, counter2# Plot to animatedef animate(i):    pullData = open("sampleData.txt", "r").read()    dataList = pullData.split('\n')    remote_file = dataList    curFrame = []    recFrame = []    #global mode    #mode = []    #bytesRead = []    #missingFrames = []    plossRate = []    counter = []    counter2 = []    counter2.append(0)    #print("i is: " + str(i))    value = 0    for eachLine in remote_file:        if len(eachLine)>1:            value=value+1            #a, b, c, d, e = eachLine.split(',')            #curFrame.append(int(a))            #recFrame.append(int(b))            mode.append(random.randint(1,3))            #bytesRead.append(int(d))            #missingFrames.append(int(e))            plossRate.append(random.randint(0,90))            counter.append(int(value))            counter2.append(int(value))            #print("mode = " + str(c) + " lastFrame =  " + str(b) + "  conter = " + str(value))    aPlot.clear()    aPlot2.clear()    aPlot.plot(counter, plossRate)    aPlot.set_title('Packet Loss Rate')    aPlot.set_ylabel('Percentage')    aPlot2.plot(counter, mode[-counter[-1]:], 'bo')    #aPlot2.axis(0,counter[-1],0,3)    aPlot2.set_title('Current Audio Mode')    aPlot2.set_ylabel('mode')def make_plot(i):    pullData = open("sampleData.txt", "r").read()    dataList = pullData.split('\n')    remote_file = dataList    curFrame = []    recFrame = []    #global mode    #mode = []    #bytesRead = []    #missingFrames = []    #plossRate = []    counter = []    counter2 = []    counter2.append(0)    value = 0    for eachLine in remote_file:        if len(eachLine)>1:            value=value+1            #a, b, c, d, e = eachLine.split(',')            #curFrame.append(int(a))            #recFrame.append(int(b))            mode.append(random.randint(1,3))            #bytesRead.append(int(d))            #missingFrames.append(int(e))            plossRate.append(random.randint(0,90))            counter.append(int(value))            counter2.append(int(value))            #print("mode = " + str(c) + " lastFrame =  " + str(b) + "  conter = " + str(value))    bPlot.clear()    bPlot2.clear()    bPlot.plot(counter, plossRate[-counter[-1]:])    bPlot.set_title('Packet Loss Rate')    bPlot.set_ylabel('Percentage')    bPlot2.plot(counter, mode[-counter[-1]:], 'bo')    #aPlot2.axis(0,counter[-1],0,3)    bPlot2.set_title('Current Audio Mode')    bPlot2.set_ylabel('mode')def base_plot(i):    pullData = open("sampleData.txt", "r").read()    dataList = pullData.split('\n')    remote_file = dataList    curFrame = []    recFrame = []    #global mode    #mode = []    #bytesRead = []    #missingFrames = []    #plossRate = []    counter = []    counter2 = []    counter2.append(0)    value = 0    for eachLine in remote_file:        if len(eachLine)>1:            value=value+1            #a, b, c, d, e = eachLine.split(',')            #curFrame.append(int(a))            #recFrame.append(int(b))            mode.append(random.randint(1,3))            #bytesRead.append(int(d))            #missingFrames.append(int(e))            plossRate.append(random.randint(0,90))            counter.append(int(value))            counter2.append(int(value))            #print("mode = " + str(c) + " lastFrame =  " + str(b) + "  conter = " + str(value))    cPlot.clear()    cPlot2.clear()    cPlot.plot(counter, plossRate[-counter[-1]:])    cPlot.set_title('Packet Loss Rate')    cPlot.set_ylabel('Percentage')    cPlot2.plot(counter, mode[-counter[-1]:], 'bo')    #aPlot2.axis(0,counter[-1],0,3)    cPlot2.set_title('Current Audio Mode')    cPlot2.set_ylabel('mode')def livePlot(i):    pullData = open("sampleData.txt", "r").read()    dataList = pullData.split('\n')    remote_file = dataList    curFrame = []    recFrame = []    #global mode    #mode = []    #bytesRead = []    #missingFrames = []    #plossRate = []    counter = []    counter2 = []    counter2.append(0)    value = 0    for eachLine in remote_file:        if len(eachLine)>1:            value=value+1            #a, b, c, d, e = eachLine.split(',')            #curFrame.append(int(a))            #recFrame.append(int(b))            mode.append(random.randint(1,3))            #bytesRead.append(int(d))            #missingFrames.append(int(e))            plossRate.append(random.randint(0,90))            counter.append(int(value))            counter2.append(int(value))            #print("mode = " + str(c) + " lastFrame =  " + str(b) + "  conter = " + str(value))    dPlot.clear()    dPlot2.clear()    dPlot.plot(counter, plossRate[-counter[-1]:])    dPlot.set_title('Packet Loss Rate')    dPlot.set_ylabel('Percentage')    dPlot2.plot(counter, mode[-counter[-1]:], 'bo')    #aPlot2.axis(0,counter[-1],0,3)    dPlot2.set_title('Current Audio Mode')    dPlot2.set_ylabel('mode')### END FUNCS 4 FUN ###++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++###==========================================================================================###==========================================================================================### BEGIN MAIN CLASS FOR NETWORKUP APP ###+++++++++++++++++++++++++++++++++++++++++++++++++++class MyApp(tk.Tk):    def __init__(self, *args, **kwargs):        tk.Tk.__init__(self, *args, **kwargs)        #tk.Tk.iconbitmap(self, default="logo-no-halo-sm.png")        tk.Tk.wm_title(self, "Network Up")        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 = {}        for F in (StartPage, PageOne, PageTwo, PageThree, PageFour):            frame = F(container, self)            self.frames[F] = frame            frame.grid(row=0, column=0, sticky="nsew")        self.show_frame(StartPage)    def show_frame(self, cont):        frame = self.frames[cont]        frame.tkraise()class StartPage(tk.Frame):    def __init__(self, parent, controller):        tk.Frame.__init__(self, parent)        label = ttk.Label(self, text="Home Page", font=LARGE_FONT)        label.pack(pady=10, padx=10)        button1 = ttk.Button(self, text="PageOne", command=lambda: controller.show_frame(PageOne))        button1.pack()        button2 = ttk.Button(self, text="PageTwo", command=lambda: controller.show_frame(PageTwo))        button2.pack()        button3 = ttk.Button(self, text="PageThree", command=lambda: controller.show_frame(PageThree))        button3.pack()        button4 = ttk.Button(self, text="PageFour", command=lambda: controller.show_frame(PageFour))        button4.pack(pady=5, padx=5)        canvas0 = FigureCanvasTkAgg(f, self)        self.canvas = canvas0class PageOne(tk.Frame):    def __init__(self, parent, controller):        tk.Frame.__init__(self, parent)        label = ttk.Label(self, text="Audio (No Interference)", font=LARGE_FONT)        label.pack(pady=10, padx=10)        button1 = ttk.Button(self, text="Back to Home", command=lambda:[controller.show_frame(StartPage), clear()])        button1.pack()        button_start = ttk.Button(self, text="Play", command=lambda: start_ssh)        button_start.pack()        loss_label = ttk.Label(self, text="Loss 0")        loss_label.pack()        loss_label_reader(loss_label)        mode_label = ttk.Label(self, text="Mode 1")        mode_label.pack()        label_reader(mode_label)        canvas1 = FigureCanvasTkAgg(f0, self)        canvas1.draw()        canvas1.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)        self.canvas = canvas1class PageTwo(tk.Frame):    def __init__(self, parent, controller):        tk.Frame.__init__(self, parent)        label = ttk.Label(self, text="Audio (Interference)", font=LARGE_FONT)        label.pack(pady=10, padx=10)        button1 = ttk.Button(self, text="Back to Home", command=lambda: [controller.show_frame(StartPage), clear(), interference_setup()])        button1.pack()        button_start_mode1 = ttk.Button(self, text="Play", command=lambda: [start_ssh_singleMode(), add_interference()])        button_start_mode1.pack()        loss_label = ttk.Label(self, text="Loss 0")        loss_label.pack()        loss_label_reader(loss_label)        mode_label = ttk.Label(self, text="Mode 1")        mode_label.pack()        label_reader(mode_label)        canvas2 = FigureCanvasTkAgg(f2, self)        canvas2.draw()        canvas2.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)        self.canvas = canvas2class PageThree(tk.Frame):    def __init__(self, parent, controller):        tk.Frame.__init__(self, parent)        label = ttk.Label(self, text="Audio (Interference and Adaptive Codec)", font=LARGE_FONT)        label.pack(pady=10, padx=10)        button1 = ttk.Button(self, text="Back to Home", command=lambda: [interference_setup(), clear(), controller.show_frame(StartPage)])        button1.pack()        button_start2 = ttk.Button(self, text="Play", command=lambda: [start_ssh(), add_interference()])        button_start2.pack()        loss_label = ttk.Label(self, text="Loss 0")        loss_label.pack()        loss_label_reader(loss_label)        mode_label = ttk.Label(self, text="Mode 1")        mode_label.pack()        label_reader(mode_label)        canvas3 = FigureCanvasTkAgg(f, self)        canvas3.draw()        canvas3.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)        self.canvas = canvas3class PageFour(tk.Frame):    def __init__(self, parent, controller):        tk.Frame.__init__(self, parent)        label = ttk.Label(self, text="Audio (Interference and Adaptive Codec)", font=LARGE_FONT)        label.pack(pady=10, padx=10)        button1 = ttk.Button(self, text="Back to Home", command=lambda: [interference_setup(), clear(), controller.show_frame(StartPage)])        button1.pack()        button_start2 = ttk.Button(self, text="Play", command=lambda: [start_ssh(), add_interference()])        button_start2.pack()        w2 = tk.Scale(self, from_=0, to=90, orient='horizontal')        w2.pack()        loss_label = ttk.Label(self, text="Loss 0")        loss_label.pack()        loss_label_reader(loss_label)        mode_label = ttk.Label(self, text="Mode 1")        mode_label.pack()        label_reader(mode_label)        canvas4 = FigureCanvasTkAgg(f4, self)        canvas4.draw()        canvas4.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)        self.canvas = canvas4app = MyApp()app.geometry("1280x720")ani1 = animation.FuncAnimation(f, animate, interval=1000)ani2 = animation.FuncAnimation(f2, make_plot, interval=1000)ani3 = animation.FuncAnimation(f0, base_plot, interval=1000)ani4 = animation.FuncAnimation(f4, livePlot, interval=1000)app.mainloop()

And based on the logic you still need to add sampleData.txt which can be found in the posts question above.