如何实现Python动画执行后自动关闭并解决TclError报错
解决Matplotlib动画自动关闭后出现TclError的问题
首先,你的问题根源在于在动画的update函数中提前调用plt.close()——当动画还在执行后续帧的绘制回调时,窗口已经被关闭,Tkinter后端找不到对应的应用实例,就会抛出TclError: this isn't a Tk application。
正确的解决方案:利用动画的结束回调关闭窗口
我们可以借助FuncAnimation的finished事件,在动画完全结束后再关闭窗口,而不是在update里强制关闭。修改后的代码如下:
import matplotlib.pyplot as plt import numpy as np from PIL import Image from matplotlib.animation import FuncAnimation plt.style.use('classic') def update(step, arr, axis, max_step): print(step, max_step) for i in range(5): for j in range(5): axis[i, j].xaxis.set_major_locator(plt.NullLocator()) axis[i, j].yaxis.set_major_locator(plt.NullLocator()) if arr[step][i, j] == 10: axis[i, j].imshow(Image.open('A.jpg'), cmap="bone") else: axis[i, j].imshow(Image.open('B.jpg'), cmap="bone") # 移除update内的强制关闭逻辑 return axis def close_figure(event): # 动画完全结束后再关闭窗口 plt.close(event.canvas.figure) if __name__ == '__main__': # 第一个动画流程 a = [] for i in xrange(5): temp = np.zeros((5, 5)) temp[i, i] = 10 a.append(temp) fig, ax = plt.subplots(5, 5, figsize=(5, 5)) fig.subplots_adjust(hspace=0, wspace=0) anim = FuncAnimation(fig, update, frames=5, fargs=(a, ax,4), interval=200, repeat=False) # 绑定动画结束事件到关闭函数 anim.finished.connect(close_figure) plt.show() # 第二个动画流程 a = [] for i in xrange(5): temp = np.zeros((5, 5)) temp[i, i] = 10 a.append(temp) fig, ax = plt.subplots(5, 5, figsize=(5, 5)) fig.subplots_adjust(hspace=0, wspace=0) anim = FuncAnimation(fig, update, frames=5, fargs=(a, ax,4), interval=200, repeat=False) anim.finished.connect(close_figure) plt.show()
为什么这个方案有效?
anim.finished.connect(close_figure)会在动画的所有帧都执行完毕、动画循环完全结束后,才触发关闭窗口的操作,避免了动画回调还在运行时窗口被提前关闭的冲突。- 移除
update里的plt.close(),让动画正常完成所有帧的绘制,再由结束回调处理窗口关闭,从根源上避免了TclError。
额外优化建议
如果你想让代码更简洁,可以把重复的动画创建逻辑封装成函数:
def create_animation(): a = [] for i in xrange(5): temp = np.zeros((5, 5)) temp[i, i] = 10 a.append(temp) fig, ax = plt.subplots(5, 5, figsize=(5, 5)) fig.subplots_adjust(hspace=0, wspace=0) anim = FuncAnimation(fig, update, frames=5, fargs=(a, ax,4), interval=200, repeat=False) anim.finished.connect(close_figure) plt.show() if __name__ == '__main__': create_animation() create_animation()
这样既减少了代码冗余,也能保证两个动画依次自动执行并关闭,不会出现报错。
内容的提问来源于stack exchange,提问作者user491626




