如何在 canvas 中隐藏动画子图

How to hide animated subplots in a canvas

我正在 python 中用 tkinter 编写一个图形用户界面来显示一些图表。这些图必须是动画的,因为数据集每隔几秒更新一次。 目前我在一个框架中有 4 个图。

我想要一个菜单​​或按钮或其他东西,可以隐藏其中一个图,并展开 row/column 中的另一个图。但即使隐藏一个子图也不起作用。这是我的代码:

class Window(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.frame = tk.Frame(self)
        self.frame.pack()

        self.menu = tk.Menu(self)
        self.config(menu=self.menu)

        self.filemenu = tk.Menu(self.menu)
        self.menu.add_cascade(label = 'View', menu = self.filemenu)
        self.filemenu.add_command(label = 'Turn on graph 1', command=self.dummy0)
        self.filemenu.add_command(label = 'Turn off graph 1', command=self.dummy1)

        fpath = '../files/somefile.txt'

        self.fig = Figure(figsize = (12, 8), tight_layout = True)
        gs = gridspec.GridSpec(2, 2)
        self.ax0 = self.fig.add_subplot(gs[0, 0])
        self.ax1 = self.fig.add_subplot(gs[0, 1])
        self.ax2 = self.fig.add_subplot(gs[1, 0])
        self.ax3 = self.fig.add_subplot(gs[1, 1])

        self.canvas = FigureCanvasTkAgg(self.fig, self.frame)
        ani0 = animation.FuncAnimation(self.fig, self.animate, interval = 1000, fargs = (self.ax0, fpath, 'TankDruck O2', 60))
        ani1 = animation.FuncAnimation(self.fig, self.animate, interval = 1000, fargs = (self.ax1, fpath, 'TankDruck N2', 60))
        ani2 = animation.FuncAnimation(self.fig, self.animate, interval = 1000, fargs = (self.ax2, fpath, 'TankStand O2', 60))
        ani3 = animation.FuncAnimation(self.fig, self.animate, interval = 1000, fargs = (self.ax3, fpath, 'TankStand N2', 60))
        self.canvas.show()
        #self.canvas.get_tk_widget().grid(row = 0, column = 0)
        self.canvas.get_tk_widget().pack(side=tk.LEFT, fill = tk.BOTH, expand = True)

    def dummy0(self):
        self.ax0.set_visible(True)

    def dummy1(self):
        self.ax0.set_visible(False)
        self.canvas.draw()

    def animate(self, i, ax, path, var, tstep):
        reader = Reader(path)
        reader.read(var, tstep)
        xdata, ydata, var, unit = reader.get_data()
        ax.clear()
        ax.set_ylabel(var + ' in ' + unit)
        ax.set_xlabel('Seconds since 01.01.2000')
        ax.plot(xdata, ydata)

当我执行它时,它工作得很好。就在我想隐藏子图时,程序抛出错误,但继续 运行:

Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib64/python2.7/lib-tk/Tkinter.py", line 1470, in __call__
  return self.func(*args)
File "/usr/lib64/python2.7/lib-tk/Tkinter.py", line 531, in callit
  func(*args)
File "/usr/lib64/python2.7/site-packages/matplotlib/backends/backend_tkagg.py", line 363, in idle_draw
  self.draw()
File "/usr/lib64/python2.7/site-packages/matplotlib/backends/backend_tkagg.py", line 348, in draw
  FigureCanvasAgg.draw(self)
File "/usr/lib64/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 451, in draw
  self.figure.draw(self.renderer)
File "/usr/lib64/python2.7/site-packages/matplotlib/artist.py", line 54, in draw_wrapper
  draw(artist, renderer, *args, **kwargs)
File "/usr/lib64/python2.7/site-packages/matplotlib/figure.py", line 966, in draw
  self.tight_layout(renderer, **self._tight_parameters)
File "/usr/lib64/python2.7/site-packages/matplotlib/figure.py", line 1605, in tight_layout
rect=rect)
File "/usr/lib64/python2.7/site-packages/matplotlib/tight_layout.py", line 352, in get_tight_layout_figure
  pad=pad, h_pad=h_pad, w_pad=w_pad)
File "/usr/lib64/python2.7/site-packages/matplotlib/tight_layout.py", line 131, in auto_adjust_subplotpars
  fig.transFigure.inverted())
File "/usr/lib64/python2.7/site-packages/matplotlib/transforms.py", line 1049, in __init__
  assert bbox.is_bbox
AttributeError: 'NoneType' object has no attribute 'is_bbox'

有谁知道我该如何处理这个问题?在最好的情况下,绘图 ax0 会消失,而 ax1 会扩展以填满整行。 还是我需要使用多个 canvas' 或类似的东西?

提前致谢!

刚刚自己找到了解决方案。问题是图中的 tight_layout 。我将调用更改为:

self.fig = Figure(figsize = (12, 8))

现在可以正常使用了。

我还更改了 dummy0 和 dummy1:

def dummy0(self):
    self.ax0.set_visible(True)
    self.ax1.change_geometry(2,2,2) 
    self.canvas.draw()

def dummy1(self):
    self.ax0.set_visible(False)
    self.ax1.change_geometry(2,1,1)
    self.canvas.draw()

所以另一个图将填充该行。以防将来有人也需要这个。

再见。