May-06-2019, 08:03 AM
Hi everyone,
My code is about a graph based on two values which are input through a serial port and a linear graph is the output. But the issue I'm facing is that there are 2 GUI interface one shows the values being sent and the other shows the graph output. So when the program runs the data window is running fine but the graph window becomes unresponsive although the values are being generated.
The code is distributed among two files: SMSRRTT2.0.py and e8.py Here's the code for the respective file.
SMSRRTT2.0.py
Thank you!
My code is about a graph based on two values which are input through a serial port and a linear graph is the output. But the issue I'm facing is that there are 2 GUI interface one shows the values being sent and the other shows the graph output. So when the program runs the data window is running fine but the graph window becomes unresponsive although the values are being generated.
The code is distributed among two files: SMSRRTT2.0.py and e8.py Here's the code for the respective file.
SMSRRTT2.0.py
"""This is a simple application written in Python and TKinter. The application's main purpose is not to serve a specific one. This is a generic application for sending and receiving data from the computer to UART host controller (Arduino). The major functions are self update and get data which are threaded to make sure the GUI does not freeze. The GUI runs in the main thread, the worker threads are the two separate ones. A simple Arduino Test Sketch is also made to test the purpose of this app which sends data in a specific format. Format: String outgoing_data = {"1,2,3,4,5"}; The array size has been limited to 5 since the UNO has 5 analogue Sources and the progress bars represent the 5 bars. """ import time import threading import tkinter from tkinter import ttk from tkinter import * import serial import csv import os import datetime import matplotlib serial_data = '' filter_data = '' update_period = 5 serial_object = None gui = Tk() gui.title("UART Interface") data4 = '' data5 = '' def connect(): """The function initiates the Connection to the UART device with the Port and Buad fed through the Entry boxes in the application. The radio button selects the platform, as the serial object has different key phrases for Linux and Windows. Some Exceptions have been made to prevent the app from crashing, such as blank entry fields and value errors, this is due to the state-less-ness of the UART device, the device sends data at regular intervals irrespective of the master's state. The other Parts are self explanatory. """ version_ = button_var.get() print(version_) global serial_object port = port_entry.get() baud = baud_entry.get() try: if version_ == 2: try: serial_object = serial.Serial('/dev/tty' + str(port), baud) except: print ("Cant Open Specified Port") elif version_ == 1: serial_object = serial.Serial('COM' + str(port), baud) except ValueError: print ("Enter Baud and Port") return t1 = threading.Thread(target = get_data) t1.daemon = True t1.start() def get_data(): """This function serves the purpose of collecting data from the serial object and storing the filtered data into a global variable. The function has been put into a thread since the serial event is a blocking function. """ global serial_object global filter_data while(1): try: serial_data = str(serial_object.readline().decode("ascii")) filter_data = serial_data.split(',') graph_data = filter_data[0] gd = int(graph_data) graph_data1 = filter_data[1] gd1 = int(graph_data1) gd2 = filter_data[2] with open("file.txt", 'a') as f: f.write('%d'%gd + ',' + '%d'%gd1 + ',' + gd2 +'\n') print(filter_data) print(type(filter_data)) except TypeError: pass def update_gui(): """" This function is an update function which is also threaded. The function assimilates the data and applies it to it corresponding progress bar. The text box is also updated every couple of seconds. A simple auto refresh function .after() could have been used, this has been avoid purposely due to various performance issues. """ global filter_data global update_period text.place(x = 15, y = 10) progress_1.place(x = 60, y = 100) progress_2.place(x = 60, y = 130) progress_3.place(x = 60, y = 160) progress_4.place(x = 60, y = 190) progress_5.place(x = 60, y = 220) new = time.time() while(1): if filter_data: text.insert(END, filter_data) try: progress_1["value"] = filter_data[0] progress_2["value"] = filter_data[1] progress_3["value"] = filter_data[2] progress_4["value"] = filter_data[3] progress_5["value"] = filter_data[4] except : pass if time.time() - new >= update_period: text.delete("1.0", END) progress_1["value"] = 0 progress_2["value"] = 0 progress_3["value"] = 0 progress_4["value"] = 0 progress_5["value"] = 0 new = time.time() def grh(): os.system("e8.py") def send(): """This function is for sending data from the computer to the host controller. The value entered in the the entry box is pushed to the UART. The data can be of any format, since the data is always converted into ASCII, the receiving device has to convert the data into the required f format. """ send_data = data_entry.get() if not send_data: print("Sent Nothing") serial_object.write(send_data.encode()) def disconnect(): """ This function is for disconnecting and quitting the application. Sometimes the application throws a couple of errors while it is being shut down, the fix isn't out yet but will be pushed to the repo once done. simple GUI.quit() calls. """ try: serial_object.close() except AttributeError: print("Closed without Using it -_-") gui.quit() if __name__ == "__main__": """ The main loop consists of all the GUI objects and its placement. The Main loop handles all the widget placements. """ #frames frame_1 = Frame(height = 285, width = 480, bd = 3, relief = 'groove').place(x = 7, y = 5) frame_2 = Frame(height = 150, width = 480, bd = 3, relief = 'groove').place(x = 7, y = 300) text = Text(width = 55, height = 5) #threads t2 = threading.Thread(target = update_gui) t2.daemon = True t2.start() #Labels data1_ = Label(text = "Data1:").place(x = 15, y= 100) data2_ = Label(text = "Data2:").place(x = 15, y= 130) data3_ = Label(text = "Data3:").place(x = 15, y= 160) data4_ = Label(text = "Data4:").place(x = 15, y= 190) data5_ = Label(text = "Data5:").place(x = 15, y= 220) baud = Label(text = "Baud").place(x = 100, y = 348) port = Label(text = "Port").place(x = 200, y = 348) contact = Label(text = "SAFE MINETECH").place(x = 250, y = 437) #progress_bars progress_1 = ttk.Progressbar(orient = HORIZONTAL, mode = 'determinate', length = 200, max = 255) progress_2 = ttk.Progressbar(orient = HORIZONTAL, mode = 'determinate', length = 200, max = 255) progress_3 = ttk.Progressbar(orient = HORIZONTAL, mode = 'determinate', length = 200, max = 255) progress_4 = ttk.Progressbar(orient = HORIZONTAL, mode = 'determinate', length = 200, max = 255) progress_5 = ttk.Progressbar(orient = HORIZONTAL, mode = 'determinate', length = 200, max = 255) #Entry data_entry = Entry() data_entry.place(x = 100, y = 255) baud_entry = Entry(width = 7) baud_entry.place(x = 100, y = 365) port_entry = Entry(width = 7) port_entry.place(x = 200, y = 365) #radio button button_var = IntVar() radio_1 = Radiobutton(text = "Windows", variable = button_var, value = 1).place(x = 10, y = 315) radio_2 = Radiobutton(text = "Linux", variable = button_var, value = 2).place(x = 110, y = 315) #button button1 = Button(text = "Send", command = send, width = 6).place(x = 15, y = 250) connect = Button(text = "Connect", command = connect).place(x = 15, y = 360) disconnect = Button(text = "Disconnect", command = disconnect).place(x =300, y = 360) save = Button(text = "Save", command = disconnect).place(x =415, y = 250) graph = Button(text = "Graph", command = grh).place(x =415, y = 100) #mainloop gui.geometry('500x500') #ani = animation.FuncAnimation(f, animate, fargs=(xs, ys, ys1), interval=800) gui.mainloop()e8.py
import matplotlib matplotlib.use("TkAgg") from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk from matplotlib.figure import Figure import matplotlib.animation as animation from matplotlib import style import datetime as dt import tkinter as tk from tkinter import ttk import matplotlib.pyplot as plt from tkinter import * import pandas as pd from tkinter import Frame, Tk, BOTH, Text, Menu, END from tkinter import filedialog from matplotlib import pyplot as plt import os NORM_FONT= ("Verdana", 10) LARGE_FONT= ("Verdana", 12) style.use("fast") f = plt.Figure(figsize=(5,5), dpi=100) ax = f.add_subplot(231) ax1 = f.add_subplot(232) ax2 = f.add_subplot(233) ax3 = f.add_subplot(234) ax4 = f.add_subplot(235) ax5 = f.add_subplot(236) xs = [] ys = [] ys1 = [] ys2 = [] ys3 = [] ys4 = [] ys5 = [] def animate(i,xs,ys,ys1): graph_data = open('file.txt','r').read() lines = graph_data.split('\n') for line in lines: if len(line) > 1: x, x1, x2 = line.split(',') #tm = dt.datetime.now().strftime('%S') # Add x and y to lists xs.append(float(x)) ys.append(x2) ys1.append(float(x1)) #ys1.append(float(x1)) #ys2.append(float(x2)) #ys3.append(float(x3)) #ys4.append(float(x4)) #ys5.append(float(x5)) # Limit x and y lists to 20 items xs = xs[-10:] ys = ys[-10:] ys1 = ys1[-10:] #ys1 = ys1[-20:] #ys2 = ys2[-20:] #ys3 = ys3[-20:] #ys4 = ys4[-20:] #ys5 = ys5[-20:] # Draw x and y lists ax.clear() ax1.clear() ax2.clear() ax3.clear() ax4.clear() ax5.clear() ax.set_xlabel('Time') ax.set_ylabel('sensor1') ax1.set_xlabel('Time') ax1.set_ylabel('sensor2') ax2.set_xlabel('Time') ax2.set_ylabel('sensor3') ax3.set_xlabel('Time') ax3.set_ylabel('sensor4') ax4.set_xlabel('Time') ax4.set_ylabel('sensor5') ax5.set_xlabel('Time') ax5.set_ylabel('sensor6') ax.plot(xs,ys) ax1.plot(ys1,ys) #ax2.plot(xs,ys2) #ax3.plot(xs,ys3) #ax4.plot(xs,ys4) #ax5.plot(xs,ys5) # Format plot #ax.plot_date(str(rs), "#00A3E0", label="value") #a.plot_date(sellDates, sells["price"], "#183A54", label="sells") #handles, labels = ax.get_legend_handles_labels(str(rs)) #ax.legend(bbox_to_anchor=(0, 1.02, 1, .102), loc=3,ncol=2, borderaxespad=0,) class SeaofBTCapp(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) #tk.Tk.iconbitmap(self, default="clienticon.ico") #tk.Tk.wm_title(self, "Sea of BTC client") 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): frame = F(container, self) self.frames[F] = frame frame.grid(row=0, column=0, sticky="nsew") self.show_frame(PageOne) 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 = tk.Label(self, text=("""do you want to start IRI meter."""), font=LARGE_FONT) label.pack(pady=10,padx=10) button1 = ttk.Button(self, text="Agree", command=lambda: controller.show_frame(PageOne)) button1.pack() class PageOne(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self, parent) label = tk.Label(self, text="Page One!!!", font=LARGE_FONT) label.pack(pady=10,padx=10) canvas = FigureCanvasTkAgg(f, self) canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) toolbar = NavigationToolbar2Tk(canvas, self) canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True) #canvas.move(50,50) toolbar.update() app = SeaofBTCapp() app.geometry("600x400") ani = animation.FuncAnimation(f, animate, fargs=(xs, ys, ys1), interval=100) app.mainloop()Any help would be highly appreciated as the solution which I know is through threading but that's not working and I've read tkinter and threading are not the best companions. So what all could I do to make this program run smoothly.
Thank you!