如何隐藏画布中的动画子图

时间:2015-09-03 09:14:07

标签: python canvas matplotlib tkinter subplot

我正在python中用tkinter写一个gui来显示一些情节。这些图必须是动画的,因为数据集每隔几秒就会更新一次。 目前我在一个框架中有4个地块。

我想要一个菜单​​或按钮或那里的东西,可以隐藏其中一个图,并扩展行/列中的另一个图。但即使隐藏一个子情节也无法正常工作。这是我的代码:

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将扩展以填充整行。 或者我需要使用多个画布'或类似的东西?

提前致谢!

1 个答案:

答案 0 :(得分:0)

我自己找到了解决方案。问题是这个数字的紧张。我把电话改为:

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()

所以其他情节将填满这一行。以防万一将来也需要这个。

再见。