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.