I'm currently coding my first tkinter GUI. I'm trying to make an interactive plot, using some scales so that the user can set the values of parameters affecting the plot. when I do this it starts lagging and my solution; working with threading is not working as intended.
In my real code there are multiple plots so the application started lagging as shown here:
from tkinter import *
from tkinter import ttk
import threading
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import time
import numpy as np
def create_window(root):
frame1 = Frame(root)
frame2 = Frame(root)
frame1.grid(row=0,column=0)
frame2.grid(row=0,column=1)
figure1 = plt.Figure(figsize=(5,5))
figure1.set_tight_layout(True)
ax1 = figure1.add_subplot(111)
canvas1 = FigureCanvasTkAgg(figure1, frame1)
canvas1.get_tk_widget().grid(column=1,row=1, padx=10, pady=10)
m.trace_add('write', lambda var=None, index=None, mode=None: update_plot_tracer(ax1, canvas1))
m_scale = ttk.Scale(frame2, orient=VERTICAL, length=200, from_=100.0, to=0.0, variable=m)
m_scale.grid(column=0, row=0)
update_plot(ax1,canvas1)
def update_plot(ax, canvas):
#to make it lag
time.sleep(0.1)
x = np.arange(0,10,1)
y = m.get() * x
ax.clear()
ax.plot(x,y)
ax.set_ylim([0, 100])
canvas.draw()
def update_plot_tracer(ax, canvas, var=None, index=None, mode=None):
update_plot(ax, canvas)
if __name__ == '__main__':
root = Tk()
m = DoubleVar(value = 10.0)
create_window(root)
root.mainloop()
My solution to that was to use threading so that the rest of the user interface is still usable while the plot is plotting. The problem I am running into now is that when the user drags the scale a lot there would be multiple threads called which interfere so I tried to stop the program from updating multiple times at the same time as shown below:
from tkinter import *
from tkinter import ttk
import threading
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import time
import numpy as np
def create_window(root):
frame1 = Frame(root)
frame2 = Frame(root)
frame1.grid(row=0,column=0)
frame2.grid(row=0,column=1)
figure1 = plt.Figure(figsize=(5,5))
figure1.set_tight_layout(True)
ax1 = figure1.add_subplot(111)
canvas1 = FigureCanvasTkAgg(figure1, frame1)
canvas1.get_tk_widget().grid(column=1,row=1, padx=10, pady=10)
m.trace_add('write', lambda var=None, index=None, mode=None: update_plot_tracer(ax1, canvas1))
m_scale = ttk.Scale(frame2, orient=VERTICAL, length=200, from_=100.0, to=0.0, variable=m)
m_scale.grid(column=0, row=0)
update_plot(ax1,canvas1)
m_entry = ttk.Entry(frame2, textvariable = m)
m_entry.grid(column=0, row=1)
def update_plot(ax, canvas):
x = np.arange(0,10,1)
y = m.get() * x
print('last used value of m', m.get())
ax.clear()
ax.plot(x,y)
ax.set_ylim([0, 100])
canvas.draw()
#to make it lag
time.sleep(0.2)
def update_plot_tracer(ax, canvas, var=None, index=None, mode=None):
global thread1#just to make this example work, in my real code i have it as a class variable...
if thread1 is None or not thread1.is_alive():
thread1 = threading.Thread(target= lambda: update_plot(ax, canvas))
thread1.start()
if __name__ == '__main__':
thread1 = None
root = Tk()
m = DoubleVar(value = 10.0)
create_window(root)
root.mainloop()
Now I have the next problem: when the thread is started but the user keeps moving the mouse, the value he/she sees is not the one used in the plot, so I would like to do something like adding the threads to a queue, but then I will run into the problem that this queue could get very long and it would take some time to update to the newest state, even though all the threads between the currently running and the newest added are useless, but as far as I have understood it, once I have added a thread to the queue (from the queue bib) it cant be removed. I have never worked with most of this so any help is appreciated.
Also, I want to keep it as interactive as possible, so to only update once the user lets go of the scale is not my preferred way of doing this.
EDIT: The question is how do I create a queue of threads from which I can remove entries?