matplotlib.animation
#
Animation#
The easiest way to make a live animation in Matplotlib is to use one of theAnimation
classes.
See also
A base class for Animations. | |
| |
|
In both cases it is critical to keep a reference to the instanceobject. The animation is advanced by a timer (typically from the hostGUI framework) which theAnimation
object holds the only referenceto. If you do not hold a reference to theAnimation
object, it (andhence the timers) will be garbage collected which will stop theanimation.
To save an animation useAnimation.save
,Animation.to_html5_video
,orAnimation.to_jshtml
.
SeeHelper Classes below for details about what movie formats aresupported.
FuncAnimation
#
The inner workings ofFuncAnimation
is more-or-less:
fordinframes:artists=func(d,*fargs)fig.canvas.draw_idle()fig.canvas.start_event_loop(interval)
with details to handle 'blitting' (to dramatically improve the liveperformance), to be non-blocking, not repeatedly start/stop the GUIevent loop, handle repeats, multiple animated axes, and easily savethe animation to a movie file.
'Blitting' is astandard technique in computer graphics. Thegeneral gist is to take an existing bit map (in our case a mostlyrasterized figure) and then 'blit' one more artist on top. Thus, bymanaging a saved 'clean' bitmap, we can only re-draw the few artiststhat are changing at each frame and possibly save significant amounts oftime. When we use blitting (by passingblit=True
), the core loop ofFuncAnimation
gets a bit more complicated:
ax=fig.gca()defupdate_blit(artists):fig.canvas.restore_region(bg_cache)forainartists:a.axes.draw_artist(a)ax.figure.canvas.blit(ax.bbox)artists=init_func()forainartists:a.set_animated(True)fig.canvas.draw()bg_cache=fig.canvas.copy_from_bbox(ax.bbox)forfinframes:artists=func(f,*fargs)update_blit(artists)fig.canvas.start_event_loop(interval)
This is of course leaving out many details (such as updating thebackground when the figure is resized or fully re-drawn). However,this hopefully minimalist example gives a sense of howinit_func
andfunc
are used inside ofFuncAnimation
and the theory of how'blitting' works.
Note
The zorder of artists is not taken into account when 'blitting'because the 'blitted' artists are always drawn on top.
The expected signature onfunc
andinit_func
is very simple tokeepFuncAnimation
out of your book keeping and plotting logic, butthis means that the callable objects you pass in must know whatartists they should be working on. There are several approaches tohandling this, of varying complexity and encapsulation. The simplestapproach, which works quite well in the case of a script, is to define theartist at a global scope and let Python sort things out. For example:
importnumpyasnpimportmatplotlib.pyplotaspltfrommatplotlib.animationimportFuncAnimationfig,ax=plt.subplots()xdata,ydata=[],[]ln,=ax.plot([],[],'ro')definit():ax.set_xlim(0,2*np.pi)ax.set_ylim(-1,1)returnln,defupdate(frame):xdata.append(frame)ydata.append(np.sin(frame))ln.set_data(xdata,ydata)returnln,ani=FuncAnimation(fig,update,frames=np.linspace(0,2*np.pi,128),init_func=init,blit=True)plt.show()
The second method is to usefunctools.partial
to pass arguments to thefunction:
importnumpyasnpimportmatplotlib.pyplotaspltfrommatplotlib.animationimportFuncAnimationfromfunctoolsimportpartialfig,ax=plt.subplots()line1,=ax.plot([],[],'ro')definit():ax.set_xlim(0,2*np.pi)ax.set_ylim(-1,1)returnline1,defupdate(frame,ln,x,y):x.append(frame)y.append(np.sin(frame))ln.set_data(x,y)returnln,ani=FuncAnimation(fig,partial(update,ln=line1,x=[],y=[]),frames=np.linspace(0,2*np.pi,128),init_func=init,blit=True)plt.show()
A third method is to use closures to build up the requiredartists and functions. A fourth method is to create a class.
Examples#
ArtistAnimation
#
Examples#
Writer Classes#
The provided writers fall into a few broad categories.
The Pillow writer relies on the Pillow library to write the animation, keepingall data in memory.
The HTML writer generates JavaScript-based animations.
Writer for JavaScript-based HTML movies. |
The pipe-based writers stream the captured frames over a pipe to an externalprocess. The pipe-based variants tend to be more performant, but may not workon all systems.
Pipe-based ffmpeg writer. | |
Pipe-based animated gif writer. |
The file-based writers save temporary files for each frame which are stitchedinto a single file at the end. Although slower, these writers can be easier todebug.
File-based ffmpeg writer. | |
File-based animated gif writer. |
The writer classes provide a way to grab sequential frames from the sameunderlyingFigure
. They all provide three methods thatmust be called in sequence:
setup
prepares the writer (e.g. opening a pipe).Pipe-based and file-based writers take different arguments tosetup()
.grab_frame
can then be called as often asneeded to capture a single frame at a timefinish
finalizes the movie and writes the outputfile to disk.
Example:
moviewriter=MovieWriter(...)moviewriter.setup(fig,'my_movie.ext',dpi=100)forjinrange(n):update_figure(j)moviewriter.grab_frame()moviewriter.finish()
If using the writer classes directly (not throughAnimation.save
), it isstrongly encouraged to use thesaving
context manager:
withmoviewriter.saving(fig,'myfile.mp4',dpi=100):forjinrange(n):update_figure(j)moviewriter.grab_frame()
to ensure that setup and cleanup are performed as necessary.
Examples#
Helper Classes#
Animation Base Classes#
A base class for Animations. | |
|
Writer Registry#
A module-level registry is provided to map between the name of thewriter and the class to allow a string to be passed toAnimation.save
instead of a writer instance.
Registry of available writer classes by human readable name. |
Writer Base Classes#
To reduce code duplication base classes
Abstract base class for writing movies, providing a way to grab frames by calling | |
Base class for writing movies. | |
|
and mixins
Mixin class for FFMpeg output. | |
Mixin class for ImageMagick output. |
are provided.
See the source code for how to easily implement newMovieWriter
classes.