FuncAnimation запускается только после изменения размера окна - PullRequest
1 голос
/ 04 мая 2019

Я делаю приложение, которое должно визуализировать данные датчика.Поэтому я использую Python с tkinter в качестве графического интерфейса и Matplotlib для визуализации данных.График должен показывать текущее значение датчика, поэтому он должен быть анимированным.Однако, поскольку я не хочу анимировать график, когда датчик не подключен, я добавил кнопку 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 Ответ

1 голос
/ 04 мая 2019

Вам нужно позвонить draw_idle один раз на FigureCanvasTkAgg, чтобы начать дело.

Я поместил root в GUI и удалил вызовы к update и update_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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...