From debd2512980b4211743856afa9b4e2933a631b93 Mon Sep 17 00:00:00 2001 From: ShivamPathak99 <98941325+ShivamPathak99@users.noreply.github.com> Date: Thu, 25 Jan 2024 11:34:45 +0530 Subject: [PATCH 1/2] Moved content of API `FuncAnimation` to `simple animation guide` --- .../users_explain/animations/animations.py | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/galleries/users_explain/animations/animations.py b/galleries/users_explain/animations/animations.py index fb8564f8318e..8a1b6374c569 100644 --- a/galleries/users_explain/animations/animations.py +++ b/galleries/users_explain/animations/animations.py @@ -12,6 +12,10 @@ animation is a sequence of frames where each frame corresponds to a plot on a `~matplotlib.figure.Figure`. This tutorial covers a general guideline on how to create such animations and the different options available. + +.. inheritance-diagram:: matplotlib.animation.FuncAnimation matplotlib.animation.ArtistAnimation + :parts: 1 + """ import matplotlib.pyplot as plt @@ -23,13 +27,27 @@ # Animation classes # ================= # +# ``Animation`` A base class for Animations. # The animation process in Matplotlib can be thought of in 2 different ways: # # - `~matplotlib.animation.FuncAnimation`: Generate data for first # frame and then modify this data for each frame to create an animated plot. +# :doc:`TimedAnimation ` subclass that makes an animation by repeatedly calling a function func. +# # # - `~matplotlib.animation.ArtistAnimation`: Generate a list (iterable) # of artists that will draw in each frame in the animation. +# :doc:`TimedAnimation ` subclass that creates an animation by using a fixed set of Artist objects. +# +# In both cases it is critical to keep a reference to the instance +# object. The animation is advanced by a timer (typically from the host +# GUI framework) which the `Animation` object holds the only reference +# to. If you do not hold a reference to the `Animation` object, it (and +# hence the timers) will be garbage collected which will stop the +# animation. +# To save an animation use `Animation.save`, `Animation.to_html5_video`, +# or `Animation.to_jshtml`. +# # # `~matplotlib.animation.FuncAnimation` is more efficient in terms of # speed and memory as it draws an artist once and then modifies it. On the @@ -63,6 +81,133 @@ # - Use `.animation.Animation.save` or `.pyplot.show` to save or show the # animation. # +# The inner workings of `FuncAnimation` is more-or-less:: +# +for d in frames: + artists = func(d, *fargs) + fig.canvas.draw_idle() + fig.canvas.start_event_loop(interval) +# +# with details to handle 'blitting' (to dramatically improve the live +# performance), to be non-blocking, not repeatedly start/stop the GUI +# event loop, handle repeats, multiple animated axes, and easily save +# the animation to a movie file. +# +# 'Blitting' is a `standard technique +# `__ in computer graphics. The +# general gist is to take an existing bit map (in our case a mostly +# rasterized figure) and then 'blit' one more artist on top. Thus, by +# managing a saved 'clean' bitmap, we can only re-draw the few artists +# that are changing at each frame and possibly save significant amounts of +# time. When we use blitting (by passing ``blit=True``), the core loop of +# `FuncAnimation` gets a bit more complicated:: +ax = fig.gca() + +def update_blit(artists): + fig.canvas.restore_region(bg_cache) + for a in artists: + a.axes.draw_artist(a) + + ax.figure.canvas.blit(ax.bbox) + +artists = init_func() + +for a in artists: + a.set_animated(True) + +fig.canvas.draw() +bg_cache = fig.canvas.copy_from_bbox(ax.bbox) + +for f in frames: + artists = func(f, *fargs) + update_blit(artists) + fig.canvas.start_event_loop(interval) +# +# This is of course leaving out many details (such as updating the +# background when the figure is resized or fully re-drawn). However, +# this hopefully minimalist example gives a sense of how ``init_func`` +# and ``func`` are used inside of `FuncAnimation` 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 on ``func`` and ``init_func`` is very simple to +# keep `FuncAnimation` out of your book keeping and plotting logic, but +# this means that the callable objects you pass in must know what +# artists they should be working on. There are several approaches to +# handling this, of varying complexity and encapsulation. The simplest +# approach, which works quite well in the case of a script, is to define the +# artist at a global scope and let Python sort things out. For example:: +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.animation import FuncAnimation + +fig, ax = plt.subplots() +xdata, ydata = [], [] +ln, = ax.plot([], [], 'ro') + +def init(): + ax.set_xlim(0, 2*np.pi) + ax.set_ylim(-1, 1) + return ln, + +def update(frame): + xdata.append(frame) + ydata.append(np.sin(frame)) + ln.set_data(xdata, ydata) + return ln, + +ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128), + init_func=init, blit=True) +plt.show() +# +# The second method is to use `functools.partial` to pass arguments to the +# function:: +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.animation import FuncAnimation +from functools import partial + +fig, ax = plt.subplots() +line1, = ax.plot([], [], 'ro') + +def init(): + ax.set_xlim(0, 2*np.pi) + ax.set_ylim(-1, 1) + return line1, + +def update(frame, ln, x, y): + x.append(frame) + y.append(np.sin(frame)) + ln.set_data(x, y) + return ln, + +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 required +# artists and functions. A fourth method is to create a class. +# +# Examples +# ^^^^^^^^ +# +# * :doc:`../gallery/animation/animate_decay` +# * :doc:`../gallery/animation/bayes_update` +# * :doc:`../gallery/animation/double_pendulum` +# * :doc:`../gallery/animation/animated_histogram` +# * :doc:`../gallery/animation/rain` +# * :doc:`../gallery/animation/random_walk` +# * :doc:`../gallery/animation/simple_anim` +# * :doc:`../gallery/animation/strip_chart` +# * :doc:`../gallery/animation/unchained` +# # The update function uses the ``set_*`` function for different artists to # modify the data. The following table shows a few plotting methods, the artist # types they return and some methods that can be used to update them. From d3c4d796ad49aba0d0bbbeb5753b993ec14652ae Mon Sep 17 00:00:00 2001 From: ShivamPathak99 <98941325+ShivamPathak99@users.noreply.github.com> Date: Sat, 27 Jan 2024 14:43:48 +0530 Subject: [PATCH 2/2] Linked optional dependencies to its required section --- doc/users/installing/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/users/installing/index.rst b/doc/users/installing/index.rst index fa5187081b2f..ca16260f7e36 100644 --- a/doc/users/installing/index.rst +++ b/doc/users/installing/index.rst @@ -31,7 +31,7 @@ precompiled wheel for your OS and Python. For support of other GUI frameworks, LaTeX rendering, saving animations and a larger selection of file formats, you can - install :ref:`optional dependencies `. + install :ref:`optional dependencies `. Third-party distributions