【问题标题】:Matplotlib FuncAnimation Created twice - duplicate when embbeded in tkinterMatplotlib FuncAnimation 创建两次 - 嵌入 tkinter 时重复
【发布时间】:2021-11-18 22:55:41
【问题描述】:

我有一个令人烦恼的错误,我无法理解它的起源。尝试了几天,仍然没有成功。

我正在尝试使用FuncAnimation 创建与播放的音频相对应的行光标,并且由于某种原因,动画仅在从RectangleSelector 触发激活函数的回调 (line_select_callback) 时创建两次用鼠标绘制后的小部件。当我使用标准的TK 按钮激活SAME 功能(line_select_callback)时,它运行良好。

存在一些带有相关打印的调试代码。

我创建了最小的工作示例。 我的猜测是它与未附加到tk窗口的图形有关,并且除了嵌入的图形之外还被静默激活,我不太确定。

任何帮助将不胜感激,谢谢! :)

import os
import threading
import tkinter as tk


from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg)
from matplotlib.widgets import RectangleSelector
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

from matplotlib import animation

class LineAnimation:
    def __init__(self,  fig, ax):
        print(' enter LineAnimation ctor')

        # Parameters
        self.ax = ax
        self.fig = fig
        self.xdata, self.ydata = [], []
        self.ln, = plt.plot([], [], 'ro')

        # Print figures list
        figures = [manager.canvas.figure
                   for manager in matplotlib._pylab_helpers.Gcf.get_all_fig_managers()]
        print('figures BEFORE animation: ', figures)

        self.animation = animation.FuncAnimation(fig=self.fig,
                                                 func=self.update,
                                                 init_func=self.init,
                                                 frames=np.linspace(0, 2 * np.pi, 128),
                                                 interval=25,
                                                 blit=True, repeat=False,
                                                 cache_frame_data=False)

        self.fig.canvas.draw()
        # Print figures list
        figures = [manager.canvas.figure
                   for manager in matplotlib._pylab_helpers.Gcf.get_all_fig_managers()]
        print('figures AFTER animation: ', figures, '\n')

    def init(self):
        # Prints for debugging
        print('\nenter init animate')
        print('Thread id: ', threading.get_ident())
        print('Process id: ', os.getpid(), '\n')


        # Init
        self.ax.set_xlim(0, 2*np.pi)
        self.ax.set_ylim(-1, 1)
        return self.ln,

    def update(self, frame):
        self.xdata.append(frame)
        self.ydata.append(np.sin(frame))
        self.ln.set_data(self.xdata, self.ydata)
        return self.ln,

class Example:

    def __init__(self):

        # init window
        self.root = tk.Tk(className=' Species segmentation')
        self.fig, self.ax = plt.subplots()

        # init sine audio file
        self.fs = 44100
        self.dur = 2
        self.freq = 440
        self.x = np.sin(2*np.pi*np.arange(self.fs*self.dur)*self.freq/self.fs)
        # plt.ion()

        # Embedd in tk
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.root)  # A tk.DrawingArea.
        self.canvas.draw()
        self.canvas.get_tk_widget().grid()

        # Plot something
        self.N = 100000
        self.xp = np.linspace(0, 10, self.N)
        self.ax.plot(self.xp, np.sin(2*np.pi*self.xp))
        self.ax.set_title(
            "Plot for demonstration purpuse")

        # init Rectangle Selector
        self.RS = RectangleSelector(self.ax, self.line_select_callback,
                                   drawtype='box', useblit=True,
                                   button=[1, 3],  # avoid using middle button
                                   minspanx=5, minspany=5,
                                   spancoords='pixels', interactive=True,
                                   rectprops={'facecolor': 'yellow', 'edgecolor': 'black', 'alpha': 0.15, 'fill': True})

        self.canvas.draw()
        # plt.show()


        tk.mainloop()

    def line_select_callback(self, eclick, erelease):
        print('enter line_select_callback')

        self.anim = LineAnimation(
            self.fig,
            self.ax)

        self.fig.canvas.draw()

        # plt.show()

Example()

【问题讨论】:

    标签: python matplotlib tkinter animation


    【解决方案1】:

    我设法找出了导致此问题的原因: 矩形选择器(使用 blitting)和在同一轴上使用动画(也使用 blitting)。 我已经设法正确地创建了动画,但只有当我禁用了矩形选择器时

        self.RS.set_active(False)
        self.RS.update()
        self.canvas.flush_events()
    

    并删除他的艺术家(我需要在我的代码中手动执行此操作):

        for a in self.RS.artists:
            a.set_visible(False)
    

    之后,动画就正常工作了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-02
      • 2011-05-03
      • 2014-10-06
      相关资源
      最近更新 更多