matplotlib 如何防止Tkinter GUI中的动画情节出现卡顿?

fiei3ece  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(142)

下面是代码,它显示了一个动画图和一个GUI来显示值:

import random
import time
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib import animation
import threading

root = tk.Tk()
gui_text = tk.StringVar()
tk.Label(root, textvariable=gui_text).pack()
x = []
y = []

def data_thread():
    while True:
        random_value = random.random()
        x.append(len(x))
        y.append(random_value)
        gui_text.set(f"Random Value: {random_value:.2f}")
        time.sleep(0.09)

def init():
    plot_data.set_data([], [])
    return (plot_data,)

def animate(frame):
    plot_data.set_data(x, y)
    plot_axes.relim()
    plot_axes.autoscale_view(True)
    return (plot_data,)

plot_figure = plt.figure()
plot_axes = plt.axes()
(plot_data,) = plot_axes.plot([], [])

animation = animation.FuncAnimation(plot_figure, animate, init_func=init, interval=1000, blit=False)
plt.show(block=False)

thread = threading.Thread(target=data_thread)
thread.daemon = True
thread.start()

root.mainloop()

正如你所看到的,当情节更新/动画(每秒)时,GUI停止更新值(显示为“随机值:“)有办法防止这种情况吗?

pu3pd22g

pu3pd22g1#

首先,永远不要在Tkinter中使用线程(或者非常小心地使用它),你应该只使用一个循环(mainloop)。这是因为当你使用线程时,tkinter会产生内存泄漏。
其次,animate示例的使用非常复杂。你可以通过清除值并使用新值再次绘制来完成同样的事情(参见下面的代码)。
最后,如果你使用我的代码(它工作正常),但你绘制值非常快,我建议你限制绘制的数字(如果你需要,我可以帮助你)。
在这里,我的代码将每0.01秒获得一个随机值,并直接绘制它。我注解了我的代码,所以它更清晰。
有任何问题都可以问我!祝你有愉快的一天。

import random 
import tkinter as tk 
import matplotlib.pyplot as plt 
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

class Window(tk.Tk):
    def __init__(self,*args):        
        super().__init__() 

        #var
        self.x_list = [] #list of x position | they need to be the same size
        self.y_list = [] #list of y position
        self.nbrOfPoints = 0 

        #widget creation
        self.label1 = tk.Label(self) #label displaying random values

        self.figure = plt.Figure(figsize=(7,3), dpi=100) #figure that will hold your plot
        self.subplot = self.figure.add_subplot(111) #plot holded by figure

        self.GraphCanva = FigureCanvasTkAgg(self.figure, master=self) #canvas from figure
        self.GraphCanva.get_tk_widget().pack() #place your canvas

        #widget placement
        self.label1.pack()

        self.update_values_to_plot() #launch the loop to updates values to plot
        self.update_plot() #lauch loop that will update the plot

    def update_values_to_plot(self) :
        random_value = self.randomValue() #get a random value between 0.0 and 1.0
        self.x_list.append(random_value) #add the random valut to x list
        self.y_list.append(self.nbrOfPoints) #add 0, 1, 2 ... to y list
        self.nbrOfPoints += 1

        #label is a disctionnary so you can update values like this
        self.label1['text'] = "Random value : " + str(random_value) #show random value on label

        self.after(10, self.update_values_to_plot) #call back this function every 0.5 secs

    def randomValue(self) :
        return random.random() #return a random value
    
    def update_plot(self) : #update the plot
        self.subplot.cla() #clear plot
        self.subplot.plot(self.y_list, self.x_list, '-o', label="Random values", color='blue') #place new values 

        self.GraphCanva.draw_idle() #draw what's in your canva (your plot)
        self.after(10, self.update_plot) #call back function every 0.5secs

if __name__ == "__main__":
    second_window = Window()
    second_window.mainloop()

相关问题