FuncAnimation仅在调整窗口大小后开始

时间:2019-05-04 14:58:25

标签: python matplotlib tkinter

我正在制作一个应该可视化传感器数据的应用程序。因此,我将tkinter作为gui框架和matplotlib使用python来可视化数据。该图应显示当前传感器值,因此应设置动画。 但是,由于我不希望在未连接传感器时对图形进行动画处理,因此添加了一个connect按钮,该按钮需要启动动画。 所有这一切都按预期工作,但是,动画仅在我调整tkinter窗口大小后才开始。 我认为这会触发所有组件的重绘,但是我不知道如何从代码中触发它。

我已经尝试调用函数root.update()root.update_idletasks(),但这无济于事。

这是代码的最小示例:

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

from matplotlib import style


root = tk.Tk()
style.use('fivethirtyeight')

ys = [i for i in range(100)]

def animate(i, ax1, line):
    global ys
    ys = ys[1:] + [ys[0]]
    line.set_ydata(ys)

    # Draw x and y lists
    ax1.relim()
    ax1.autoscale_view(True,True,True)

    return line

class Gui():
    def __init__(self):
        global ys
        self._fig = plt.figure()
        self._ax1 = self._fig.add_subplot(1,1,1)

        self._line, = self._ax1.plot(ys)
        plt.xticks(ha='right')
        plt.subplots_adjust(bottom=0.30)
        plt.title('Air pressure measured')
        plt.ylabel('Sensor value')

        top_frame = tk.Frame(root, bg='cyan', width = 450, height=50)
        top_frame.pack(side=tk.LEFT, anchor=tk.N, pady=10)
        self.connectButton = tk.Button(top_frame, 
                                        text="connect",
                                        command=self.toggleAnimate)
        self.connectButton.pack()

        self._canvas = FigureCanvasTkAgg(self._fig, master=root)
        self._canvas.draw()
        self._canvas.get_tk_widget().pack()

    def start(self):
        root.mainloop()

    def toggleAnimate(self):
        self._animate = animation.FuncAnimation(self._fig, animate, fargs=(self._ax1, self._line), interval=100, blit=False)
        root.update_idletasks()
        root.update()

if __name__ == "__main__":
    g = Gui()
    g.start()

1 个答案:

答案 0 :(得分:1)

您需要在draw_idle上致电FigureCanvasTkAgg一次,以使事情进展顺利。

我将root放在GUI内,并删除了对updateupdate_idletasks的不必要的调用,这些调用可能会干扰mainloop
我也将您的canvas包装在frame内,但是您可以根据需要将其重新定位到root

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

from matplotlib import style


style.use('fivethirtyeight')

ys = [i for i in range(100)]

def animate(i, ax1, line):
    global ys
    ys = ys[1:] + [ys[0]]
    line.set_ydata(ys)

    # Draw x and y lists
    ax1.relim()
    ax1.autoscale_view(True,True,True)

    return line

class Gui():
    def __init__(self):
        self.root = tk.Tk()
        self._fig = plt.figure()
        self._ax1 = self._fig.add_subplot(1,1,1)

        self._line, = self._ax1.plot(ys)
        plt.xticks(ha='right')
        plt.subplots_adjust(bottom=0.30)
        plt.title('Air pressure measured')
        plt.ylabel('Sensor value')

        top_frame = tk.Frame(self.root, bg='cyan', width = 450, height=50)
        top_frame.pack(side=tk.LEFT, anchor=tk.N, pady=10)
        self.connectButton = tk.Button(top_frame, 
                                        text="connect",
                                        command=self.toggleAnimate)
        self.connectButton.pack()

        self._canvas = FigureCanvasTkAgg(self._fig, master=top_frame) #master=self.root)
        self._canvas.get_tk_widget().pack(expand=True, side=tk.LEFT, anchor=tk.N, pady=10, padx=10)
        self._canvas.draw()        
        self._animate = None

    def start(self):
        self.root.mainloop()

    def toggleAnimate(self):
        if self._animate is None:
            self._canvas.draw_idle()
            self._animate = animation.FuncAnimation(self._fig, animate, fargs=(self._ax1, self._line), interval=100) #, blit=False)


if __name__ == "__main__":
    g = Gui()
    g.start()