I am working with matplotlib and tkinter in Raspberry pi 4B. I have three different sensor readings shown in real-time. My goal is to pick a sensor from the menubar, which would open the corresponding page. In the page, I would just have a blank graph. From the start/stop menu, I will start reading, which would start displaying the readings right away. I will also stop the animation from the menu.
Issue:
- I noticed that the animations are running in background. I am not sure how to stop that.
- I don't know how to program the start and stop option in the menubar to control the current graph.
- I am not sure how to modify my function
animate_graphthat reads the frame that called it. This seems more of a simple issue, but I don't know what parameter I should pass to this function.
Here is my code:
import tkinter as tk from tkinter import *from tkinter import ttkimport matplotlib matplotlib.use("TkAgg") #backend of matplotlib??from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tkfrom matplotlib.figure import Figure #figure we call to format the gaphimport matplotlib.pyplot as plt #to plot the graphimport matplotlib.animation as animation #to create the real-time graphfrom matplotlib import style #to change the way the graph will lookstyle.use("dark_background") import numpy as npimport datetime as dt#-----------------------------END OF IMPORT -----------------------------------------------#LARGE_FONT = ("Times New Roman", 12)NORM_FONT = ("Times New Roman", 9)#----------------------------------FUNCTION------------------------------------------------#def popupmsg(title, msg): popup = tk.Tk() popup.wm_title(title) label = ttk.Label(popup,text = msg, font = NORM_FONT) label.pack(side = "top",fill = "x",pady = 10) b1 = ttk.Button(popup,label = "Okay", command=popup.destroy) b1.pack() popup.mainloop()fig_s1,ax1_s1 = plt.subplots() ax2_s1 = ax1_s1.twinx()x_s1 = []y1_s1 = []y2_s1 = []def animate_graph(i,x,y1,y2,ax1,ax2): #add frame here reading1,reading2 = (5-3) * np.random.random() + 3,(5-3) * np.random.random() + 3 #append xs and ys with time and temp respectively x.append(dt.datetime.now().strftime('%H:%M:%S')) y1.append(reading1) y2.append(reading2) #limit xs and ys to the last 10 seconds x = x[-10:] y1 = y1[-10:] y2 = y2[-10:] #Draw x and y lists #y-axis for temperature color = 'tab:red' ax1.clear() ln1= ax1.plot(x,y1,color = color, linestyle = 'dashed', label = 'Read1') ax1.tick_params(axis = 'y', labelcolor = color) #y-axis for relative humidity color = 'tab:blue' ax2.clear() ln2 = ax2.plot(x,y2,color = color,label = 'Read2') ax2.tick_params(axis = 'y', labelcolor = color) #get different axes labels together lns = ln1+ln2 labs = [l.get_label() for l in lns] ax1.legend(lns,labs,bbox_to_anchor = (0,1.02,1,0.102),loc = 3,ncol = 3,borderaxespad = 0) #x-axis label rotated to 45 degrees to avoid overlapping ax1.tick_params(axis = 'x', labelrotation = 45) # #show the graph # canvas = FigureCanvasTkAgg(fig_s1,frame) # canvas.draw() # canvas.get_tk_widget().pack(side = tk.TOP, fill = tk.BOTH, expand = True) # #add navigation bar # toolbar = NavigationToolbar2Tk(canvas,frame) # toolbar.update() # canvas._tkcanvas.pack(side = tk.TOP,fill = tk.BOTH, expand = True)#------------------------------------PAGES-----------------------------------#class main(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self,*args,**kwargs) tk.Tk.wm_title(self, "GUI") container = tk.Frame(self) container.pack(side = "top" , fill = "both" , expand = True) container.grid_rowconfigure(0, weight = 1) container.grid_columnconfigure(0,weight = 1) menubar = tk.Menu(container) filemenu = tk.Menu(menubar,tearoff = 0) filemenu.add_command(label = "Made By", command = lambda: popupmsg("Made By","Not supported yet")) filemenu.add_separator() filemenu.add_command(label = "Exit", command = quit) #add filemenu TO THE menubar menubar.add_cascade(label = "File", menu= filemenu) #sensor menu snsrmenu = tk.Menu(menubar,tearoff = 0) snsrmenu.add_command(label = "Sensor 1", command = lambda: self.show_frame(GraphS1)) snsrmenu.add_command(label = "Sensor 2", command = lambda: self.show_frame(GraphS2)) snsrmenu.add_command(label = "Sensor 3", command = lambda: self.show_frame(GraphS3)) snsrmenu.add_separator() snsrmenu.add_command(label = "Exit", command = quit) #add filemenu TO THE menubar menubar.add_cascade(label = "Sensors", menu= snsrmenu) #start stop menubar for the graphs startstopmenu = tk.Menu(menubar,tearoff=0) startstopmenu.add_command(label = "Start reading", command = lambda: popupmsg("!","Not supported yet")) startstopmenu.add_command(label = "Stop reading", command = lambda: popupmsg("!","Not supported yet")) #add filemenu TO THE menubar menubar.add_cascade(label = "Start/Stop Graph", menu= startstopmenu) tk.Tk.config(self,menu=menubar) self.frames = {} for f in (StartPage,GraphS1,GraphS2,GraphS3): 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,control): tk.Frame.__init__(self,parent) label = tk.Label(self,text = "StartPage", font = LARGE_FONT) label.pack(pady = 10, padx = 10) b1 = ttk.Button(self,text = "Open page to run sensor 1", command = lambda: control.show_frame(GraphS1)) b1.pack() b2 = ttk.Button(self,text = "Exit", command = quit) b2.pack()class GraphS1(tk.Frame): def __init__(self,parent,control): tk.Frame.__init__(self,parent) label = tk.Label(self,text = "Real-time Graph ",font = LARGE_FONT) label.pack() b1 = ttk.Button(self,text = "Go back to StartPage", command = lambda: control.show_frame(StartPage)) b1.pack() b2 = ttk.Button(self,text = "Pause", command = lambda: anim.event_source.stop()) b2.pack() b3 = ttk.Button(self,text = "Play", command = lambda: anim.event_source.start()) b3.pack() b4 = ttk.Button(self,text = "Exit", command = quit) b4.pack()class GraphS2(tk.Frame): def __init__(self,parent,control): tk.Frame.__init__(self,parent) label = tk.Label(self,text = "Real-time Graph S2",font = LARGE_FONT) label.pack() b1 = ttk.Button(self,text = "Go back to StartPage", command = lambda: control.show_frame(StartPage)) b1.pack() b4 = ttk.Button(self,text = "Exit", command = quit) b4.pack()class GraphS3(tk.Frame): def __init__(self,parent,control): tk.Frame.__init__(self,parent) label = tk.Label(self,text = "Real-time Graph S3",font = LARGE_FONT) label.pack() b1 = ttk.Button(self,text = "Go back to StartPage", command = lambda: control.show_frame(StartPage)) b1.pack() b4 = ttk.Button(self,text = "Exit", command = quit) b4.pack()#--------------------CALL MAIN CLASS-------------------------------------------------------##call main classgui = main() # gui.geometry("1280x720")gui.state('zoomed') #maximise window#call animation classanim = animation.FuncAnimation(fig_s1,animate_graph, fargs = (x_s1,y1_s1,y2_s1,ax1_s1,ax2_s1),interval = 1000)#run in loopgui.mainloop()I have only programmed the sensor 1 page, but not the other two. I am assuming it will be the same approach for the other two.
Thanks in advance.
EDIT1: Made huge changes to the project to something I can work with. Won't need this anymore. Just leaving this here incase anyone has a solution to it. might help someone else