When creating an animation using matplotlib.animation and saving it, an error appears when trying to close the figure window via plt.close:
Python version:
Python 2.7.12 |Anaconda custom (64-bit)| (default, Jul 2 2016, 17:42:40)
IPython 4.1.2 -- An enhanced Interactive Python
Currently I switched to using PyCharm 2017.1 Community Edition. The error message can be reproduced both directly in IPython and within PyCharm when running from %cpaste or %paste in IPython or running in PyCharm's interactive console using Shift+Alt+E. The movie encoder used is mencoder as integrated in mplayer, since this is the default one installed at my work place.
Note:
in IPython use plt.ion() first to turn on interactive mode (already switched on in PyCharm by default)
code exits without error in IPython when pasted using the middle mouse button directly into the IPython screen
code exits without error in IPython or PyCharm when typing all commands separately and also when pasting (%cpaste, %paste) all commands except for plt.close() and then typing plt.close() manually
code exits without error when replacing plt.close() with plt.clf(), but I need plt.close(), e.g. for creating animations in a loop with different parameters where the graph needs to be recreated from scratch
code exits without error when running the code in a script from start to end (non-interactive mode)
code exits without error when closing the figure window clicking with the mouse on the window button
code exits with error when inserting time.sleep(1) before plt.close(), so the problem likely does not relate to time conflicts in the code
A minimal, complete and (hopefully) verifiable example is given below:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# animation function for random image data
def animate_random_data(i):
new_data = np.random.rand(10, 10)
# update the data
im.set_data(new_data)
# initialize the graph
first_data = np.random.rand(10,10)
im = plt.imshow(first_data,interpolation='none')
myfig = plt.gcf()
# create the animation and save it
ani = animation.FuncAnimation(myfig, animate_random_data, range(10),
interval=100)
ani.save('animation_random_data.mpg', writer='mencoder')
plt.close()
Error traceback (from PyCharm):
Traceback (most recent call last):
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/backends/backend_qt5agg.py", line 176, in __draw_idle_agg
FigureCanvasAgg.draw(self)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 474, in draw
self.figure.draw(self.renderer)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/artist.py", line 61, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/figure.py", line 1165, in draw
self.canvas.draw_event(renderer)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/backend_bases.py", line 1809, in draw_event
self.callbacks.process(s, event)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/cbook.py", line 563, in process
proxy(*args, **kwargs)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/cbook.py", line 430, in __call__
return mtd(*args, **kwargs)
File "/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/matplotlib/animation.py", line 652, in _start
self.event_source.add_callback(self._step)
AttributeError: 'NoneType' object has no attribute 'add_callback'
Although the program continues without error when closing the windows manually as written in the list above, it is an annoying bug (think of multiple animations in a loop). The error appears also for e.g. 1D line plots. Thanks for any help (and clarification on what this error message exactly means)!
解决方案
The error comes from the animation still running while closing the figure. While in most cases it is automatically taken care of to stop the animation when closing the figure, it seems not to be the case in interactive mode.
A solution can be to explicitely stop the animation and delete it before closing the figure.
ani = animation.FuncAnimation(...)
ani.save(...)
ani.event_source.stop()
del ani
plt.close()