this question has been asked many times but to be honest I don't quite understand why do I get this error "RuntimeError: main thread is not in main loop". I have the following code to read data from Serial and draw some graph with it. My problem is that my program is working if I do not try to draw in real time the data (so if I only keep take_measure() inside the plotter function). But if I add the part for the graph drawing as shown bellow my code is returning this mainloop error. What is happening ? I know I should use the after command but for me after command was a total disaster (a lots of bugs). So do you know what is the cause of my error and how to solve it/how to implement the after method ?
Sorry for my nasty code....
from tkinter import *
from random import randint
import numpy as np
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import time
import threading
import serial
from tkinter.filedialog import asksaveasfile
import csv
from skimage.restoration import (denoise_tv_chambolle, denoise_bilateral, denoise_wavelet, estimate_sigma)
continuePlotting = False
def change_state():
global continuePlotting
global serial_port
global i
global b_start
global mid
global label
if continuePlotting == True:
continuePlotting = False
serial_port.close()
i = 2
label.pack_forget()
else:
continuePlotting = True
label.pack(in_=mid)
t, p1 = [], []
i = 0
def take_measure():
global t
global p1
global t_temp
global p1_temp
global i
global serial_port
if i == 0:
serial_port =serial.Serial('COM5', 2000000)
serial_port.setDTR(False)
time.sleep(0.1)
serial_port.setDTR(True)
serial_port.flushInput()
p1_temp = []
t_temp = []
i = 1
elif i == 2:
serial_port =serial.Serial('COM5', 2000000)
serial_port.setDTR(False)
time.sleep(0.1)
serial_port.setDTR(True)
serial_port.flushInput()
p1_temp = []
t_temp = []
i = 1
try:
temp=serial_port.readline()[:-2].decode()
a = temp.index(";")
t_val = float(temp[:a])
p1_val = (float(temp[a+1:])-2640)*20/3520
t.append(t_val)
p1.append(p1_val)
t_temp.append(t_val)
p1_temp.append(p1_val)
except:
pass
def app():
global t_temp
global p1_temp
global i
global serial_port
global t
global p1
global b_start
global mid
global label
root = Tk()
root.config(background='white')
root.geometry("1000x700")
top = Frame(root)
bottom = Frame(root)
mid = Frame(root)
top.pack(side="top")
mid.pack(side="top")
bottom.pack(side="bottom", fill="both", expand=True)
fig = Figure()
ax = fig.add_subplot(111)
ax.set_xlabel("X axis")
ax.set_ylabel("Y axis")
ax.grid()
graph = FigureCanvasTkAgg(fig, master=root)
graph.get_tk_widget().pack(in_=bottom, side="top",fill='both',expand=True)
graph.draw()
toolbar = NavigationToolbar2Tk(graph, root, pack_toolbar=False)
toolbar.update()
def plotter():
while continuePlotting:
take_measure()
ax.clear()
ax.plot(t_temp, p1_temp)
graph.draw()
def gui_handler():
change_state()
t=threading.Thread(target=plotter, daemon=True)
t.start()
def Save():
files = [('CSV', '*.csv')]
file_name = asksaveasfile(filetypes = files, defaultextension = files)
with open(str(file_name.name),"w", newline='') as file:
Writer=csv.writer(file)
Writer.writerow(["temps en ms", "pression en V"])
for elt in range(len(t)):
Writer.writerow([t[elt], p1[elt]])
file.close()
def Clear():
global t
global p1
serial_port.close()
i = 0
ax.clear()
graph.draw()
t = []
p1 = []
def Draw():
l_t = [t[0]]
l_p1 = [p1[0]]
ax.cla()
ax.grid()
for elt in range(1,len(t)):
if t[elt] == 0:
l_p = denoise_wavelet(np.array(l_p1), method="VisuShrink", mode="hard", wavelet_levels=3, wavelet='haar', rescale_sigma='True')
print("max", max(l_p1))
print("min", min(l_p1))
ax.plot(l_t, l_p)
l_t, l_p1 = [], []
l_t.append(t[elt])
l_p1.append(p1[elt])
l_p = denoise_wavelet(np.array(l_p1), method="VisuShrink", mode="hard", wavelet_levels=3, wavelet='haar', rescale_sigma='True')
ax.plot(l_t, l_p)
graph.draw()
print("max", max(l_p1))
print("min", min(l_p1))
b_start = Button(root, text="Start/Stop", command=gui_handler, bg="red", fg="white")
b_start.pack(in_=top, side = LEFT)
button_quit = Button(master=root, text="Quit", command=root.destroy)
button_save = Button(root,text="Save", command=Save)
button_clear = Button(root,text="Clear graph", command=Clear)
button_draw = Button(root,text="Show graphs", command=Draw)
button_draw.pack(in_=top, side = LEFT)
button_clear.pack(in_=top, side = LEFT)
button_save.pack(in_=top, side = LEFT)
button_quit.pack(in_=top, side=LEFT)
label = Label(root, text = "WAIT")
toolbar.pack(in_=bottom, fill=X)
root.mainloop()
if __name__ == '__main__':
app()
The error is the following:
Exception ignored in: <function Variable.__del__ at 0x000001CCB0F3E3E0>
Traceback (most recent call last):
File "c:\Users\cbroggi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 410, in __del__
if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: main thread is not in main loop
Exception ignored in: <function Image.__del__ at 0x000001CCB1098D60>
Traceback (most recent call last):
File "c:\Users\cbroggi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 4083, in __del__
self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <function Variable.__del__ at 0x000001CCB0F3E3E0>
Traceback (most recent call last):
File "c:\Users\cbroggi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 410, in __del__
if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: main thread is not in main loop
Exception ignored in: <function Variable.__del__ at 0x000001CCB0F3E3E0>
Traceback (most recent call last):
File "c:\Users\cbroggi\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 410, in __del__
if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: main thread is not in main loop