diff --git a/doc/api/animation_api.rst b/doc/api/animation_api.rst index c8f4e72126e7..85e289b0096f 100644 --- a/doc/api/animation_api.rst +++ b/doc/api/animation_api.rst @@ -1,6 +1,6 @@ -====================== - ``animation`` module -====================== +********* +animation +********* .. automodule:: matplotlib.animation :no-members: @@ -11,7 +11,6 @@ :local: :backlinks: entry - Animation ========= @@ -37,7 +36,6 @@ To save an animation to disk use `Animation.save` or `Animation.to_html5_video` See :ref:`ani_writer_classes` below for details about what movie formats are supported. - ``FuncAnimation`` ----------------- @@ -48,7 +46,6 @@ The inner workings of `FuncAnimation` is more-or-less:: 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 @@ -122,14 +119,10 @@ artist at a global scope and let Python sort things out. For example :: init_func=init, blit=True) plt.show() - The second method is to us `functools.partial` to 'bind' artists to function. A third method is to use closures to build up the required artists and functions. A fourth method is to create a class. - - - Examples ~~~~~~~~ @@ -137,39 +130,29 @@ Examples :maxdepth: 1 ../gallery/animation/animate_decay - ../gallery/animation/bayes_update_sgskip - ../gallery/animation/double_pendulum_animated_sgskip - ../gallery/animation/dynamic_image + ../gallery/animation/bayes_update + ../gallery/animation/double_pendulum_sgskip ../gallery/animation/histogram ../gallery/animation/rain - ../gallery/animation/random_data - ../gallery/animation/simple_3danim + ../gallery/animation/random_walk ../gallery/animation/simple_anim - ../gallery/animation/strip_chart_demo + ../gallery/animation/strip_chart ../gallery/animation/unchained ``ArtistAnimation`` ------------------- - Examples ~~~~~~~~ .. toctree:: :maxdepth: 1 - ../gallery/animation/basic_example - ../gallery/animation/basic_example_writer_sgskip - ../gallery/animation/dynamic_image2 - - - + ../gallery/animation/dynamic_image Writer Classes ============== - - The provided writers fall into two broad categories: pipe-based and file-based. The pipe-based writers stream the captured frames over a pipe to an external process. The pipe-based variants tend to be more @@ -179,7 +162,6 @@ performant, but may not work on all systems. :toctree: _as_gen :nosignatures: - FFMpegWriter ImageMagickFileWriter AVConvWriter @@ -196,7 +178,6 @@ slower, these writers can be easier to debug. ImageMagickWriter AVConvFileWriter - Fundamentally, a `MovieWriter` provides a way to grab sequential frames from the same underlying `~matplotlib.figure.Figure` object. The base class `MovieWriter` implements 3 methods and a context manager. The @@ -215,32 +196,32 @@ file to disk. For example :: moviewriter.grab_frame() moviewriter.finish() - -If using the writer classes directly (not through `Animation.save`), it is strongly encouraged -to use the `~MovieWriter.saving` context manager :: +If using the writer classes directly (not through `Animation.save`), it is +strongly encouraged to use the `~MovieWriter.saving` context manager :: with moviewriter.saving(fig, 'myfile.mp4', dpi=100): for j in range(n): update_figure(n) moviewriter.grab_frame() - to ensures that setup and cleanup are performed as necessary. +Examples +-------- -:ref:`sphx_glr_gallery_animation_moviewriter_sgskip.py` +.. toctree:: + :maxdepth: 1 + ../gallery/animation/frame_grabbing_sgskip .. _ani_writer_classes: Helper Classes ============== - Animation Base Classes ---------------------- - .. autosummary:: :toctree: _as_gen :nosignatures: @@ -248,12 +229,6 @@ Animation Base Classes Animation TimedAnimation - -Custom Animation classes ------------------------- - -:ref:`sphx_glr_gallery_animation_subplots.py` - Writer Registry --------------- @@ -280,7 +255,7 @@ To reduce code duplication base classes MovieWriter FileMovieWriter -and mixins are provided +and mixins .. autosummary:: :toctree: _as_gen @@ -290,9 +265,9 @@ and mixins are provided FFMpegBase ImageMagickBase -See the source code for how to easily implement new `MovieWriter` -classes. +are provided. +See the source code for how to easily implement new `MovieWriter` classes. Inheritance Diagrams ==================== diff --git a/doc/users/prev_whats_new/whats_new_1.1.rst b/doc/users/prev_whats_new/whats_new_1.1.rst index 489b8b6ab60a..80c0aaea240b 100644 --- a/doc/users/prev_whats_new/whats_new_1.1.rst +++ b/doc/users/prev_whats_new/whats_new_1.1.rst @@ -35,8 +35,8 @@ Ryan May has written a backend-independent framework for creating animated figures. The :mod:`~matplotlib.animation` module is intended to replace the backend-specific examples formerly in the :ref:`examples-index` listings. Examples using the new framework are -in :ref:`animation-examples-index`; see the entrancing :ref:`double -pendulum ` which uses +in :ref:`animation-examples-index`; see the entrancing :file:`double +pendulum ` which uses :meth:`matplotlib.animation.Animation.save` to create the movie below. .. raw:: html diff --git a/examples/animation/animate_decay.py b/examples/animation/animate_decay.py index d0fce20b86b2..b4b2aa091a15 100644 --- a/examples/animation/animate_decay.py +++ b/examples/animation/animate_decay.py @@ -3,10 +3,11 @@ Decay ===== -A sinusoidal decay animation. +This example showcases: +- using a generator to drive an animation, +- changing axes limits during an animation. """ - import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation diff --git a/examples/animation/basic_example.py b/examples/animation/basic_example.py deleted file mode 100644 index 9e7f4ae103eb..000000000000 --- a/examples/animation/basic_example.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -========================= -Simple animation examples -========================= - -Two animations where the first is a random walk plot and -the second is an image animation. -""" - -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.animation as animation - - -def update_line(num, data, line): - line.set_data(data[..., :num]) - return line, - -############################################################################### - -fig1 = plt.figure() - -# Fixing random state for reproducibility -np.random.seed(19680801) - -data = np.random.rand(2, 25) -l, = plt.plot([], [], 'r-') -plt.xlim(0, 1) -plt.ylim(0, 1) -plt.xlabel('x') -plt.title('test') -line_ani = animation.FuncAnimation(fig1, update_line, 25, fargs=(data, l), - interval=50, blit=True) - -# To save the animation, use the command: line_ani.save('lines.mp4') - -############################################################################### - -fig2 = plt.figure() - -x = np.arange(-9, 10) -y = np.arange(-9, 10).reshape(-1, 1) -base = np.hypot(x, y) -ims = [] -for add in np.arange(15): - ims.append((plt.pcolor(x, y, base + add, norm=plt.Normalize(0, 30)),)) - -im_ani = animation.ArtistAnimation(fig2, ims, interval=50, repeat_delay=3000, - blit=True) -# To save this second animation with some metadata, use the following command: -# im_ani.save('im.mp4', metadata={'artist':'Guido'}) - -plt.show() diff --git a/examples/animation/basic_example_writer_sgskip.py b/examples/animation/basic_example_writer_sgskip.py deleted file mode 100644 index d223471d100f..000000000000 --- a/examples/animation/basic_example_writer_sgskip.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -=================== -Saving an animation -=================== - -This example showcases the same animations as `basic_example.py`, but instead -of displaying the animation to the user, it writes to files using a -MovieWriter instance. -""" - -import numpy as np -import matplotlib -matplotlib.use("Agg") -import matplotlib.pyplot as plt -import matplotlib.animation as animation - - -def update_line(num, data, line): - line.set_data(data[..., :num]) - return line, - -# Fixing random state for reproducibility -np.random.seed(19680801) - - -# Set up formatting for the movie files -Writer = animation.writers['ffmpeg'] -writer = Writer(fps=15, metadata=dict(artist='Me'), bitrate=1800) - - -fig1 = plt.figure() - -data = np.random.rand(2, 25) -l, = plt.plot([], [], 'r-') -plt.xlim(0, 1) -plt.ylim(0, 1) -plt.xlabel('x') -plt.title('test') -line_ani = animation.FuncAnimation(fig1, update_line, 25, fargs=(data, l), - interval=50, blit=True) -line_ani.save('lines.mp4', writer=writer) - -fig2 = plt.figure() - -x = np.arange(-9, 10) -y = np.arange(-9, 10).reshape(-1, 1) -base = np.hypot(x, y) -ims = [] -for add in np.arange(15): - ims.append((plt.pcolor(x, y, base + add, norm=plt.Normalize(0, 30)),)) - -im_ani = animation.ArtistAnimation(fig2, ims, interval=50, repeat_delay=3000, - blit=True) -im_ani.save('im.mp4', writer=writer) diff --git a/examples/animation/bayes_update_sgskip.py b/examples/animation/bayes_update.py similarity index 88% rename from examples/animation/bayes_update_sgskip.py rename to examples/animation/bayes_update.py index e819682ac089..242d19ebb3df 100644 --- a/examples/animation/bayes_update_sgskip.py +++ b/examples/animation/bayes_update.py @@ -9,13 +9,18 @@ distribution should converge. """ -# update a distribution based on new data. +import math + import numpy as np import matplotlib.pyplot as plt -import scipy.stats as ss from matplotlib.animation import FuncAnimation +def beta_pdf(x, a, b): + return (x**(a-1) * (1-x)**(b-1) * math.gamma(a + b) + / (math.gamma(a) * math.gamma(b))) + + class UpdateDist(object): def __init__(self, ax, prob=0.5): self.success = 0 @@ -47,7 +52,7 @@ def __call__(self, i): # Choose success based on exceed a threshold with a uniform pick if np.random.rand(1,) < self.prob: self.success += 1 - y = ss.beta.pdf(self.x, self.success + 1, (i - self.success) + 1) + y = beta_pdf(self.x, self.success + 1, (i - self.success) + 1) self.line.set_data(self.x, y) return self.line, diff --git a/examples/animation/double_pendulum_animated_sgskip.py b/examples/animation/double_pendulum_sgskip.py similarity index 98% rename from examples/animation/double_pendulum_animated_sgskip.py rename to examples/animation/double_pendulum_sgskip.py index 9e419f324c12..3d4bf0c618ca 100644 --- a/examples/animation/double_pendulum_animated_sgskip.py +++ b/examples/animation/double_pendulum_sgskip.py @@ -94,5 +94,4 @@ def animate(i): ani = animation.FuncAnimation(fig, animate, np.arange(1, len(y)), interval=25, blit=True, init_func=init) -# ani.save('double_pendulum.mp4', fps=15) plt.show() diff --git a/examples/animation/dynamic_image.py b/examples/animation/dynamic_image.py index 28db4bae5e0d..d82e62f62af6 100644 --- a/examples/animation/dynamic_image.py +++ b/examples/animation/dynamic_image.py @@ -1,10 +1,10 @@ """ -================= -An animated image -================= +================================================= +Animated image using a precomputed list of images +================================================= -Animation of an image. """ + import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation @@ -17,16 +17,27 @@ def f(x, y): x = np.linspace(0, 2 * np.pi, 120) y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1) - -im = plt.imshow(f(x, y), animated=True) - - -def updatefig(*args): - global x, y +# ims is a list of lists, each row is a list of artists to draw in the +# current frame; here we are just animating one artist, the image, in +# each frame +ims = [] +for i in range(60): x += np.pi / 15. y += np.pi / 20. - im.set_array(f(x, y)) - return im, + im = plt.imshow(f(x, y), animated=True) + ims.append([im]) + +ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True, + repeat_delay=1000) + +# To save the animation, use e.g. +# +# ani.save("movie.mp4") +# +# or +# +# from matplotlib.animation import FFMpegWriter +# writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) +# ani.save("movie.mp4", writer=writer) -ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True) plt.show() diff --git a/examples/animation/dynamic_image2.py b/examples/animation/dynamic_image2.py deleted file mode 100644 index 7616e834d922..000000000000 --- a/examples/animation/dynamic_image2.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -======================================== -An animated image using a list of images -======================================== - -Animate an image from a list of images (or Artists). -""" -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.animation as animation - -fig = plt.figure() - - -def f(x, y): - return np.sin(x) + np.cos(y) - -x = np.linspace(0, 2 * np.pi, 120) -y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1) -# ims is a list of lists, each row is a list of artists to draw in the -# current frame; here we are just animating one artist, the image, in -# each frame -ims = [] -for i in range(60): - x += np.pi / 15. - y += np.pi / 20. - im = plt.imshow(f(x, y), animated=True) - ims.append([im]) - -ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True, - repeat_delay=1000) - -# ani.save('dynamic_images.mp4') - -plt.show() diff --git a/examples/animation/moviewriter_sgskip.py b/examples/animation/frame_grabbing_sgskip.py similarity index 63% rename from examples/animation/moviewriter_sgskip.py rename to examples/animation/frame_grabbing_sgskip.py index 0d2122247f7a..e74576249aa0 100644 --- a/examples/animation/moviewriter_sgskip.py +++ b/examples/animation/frame_grabbing_sgskip.py @@ -1,26 +1,23 @@ """ -=========== -MovieWriter -=========== - -Use a MovieWriter directly to grab individual frames and write -them to a file. This avoids any event loop integration, but has the advantage -of working with even the Agg backend. This is not recommended for use in an -interactive setting. +============== +Frame grabbing +============== +Use a MovieWriter directly to grab individual frames and write them to a +file. This avoids any event loop integration, and thus works even with the Agg +backend. This is not recommended for use in an interactive setting. """ import numpy as np import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt -import matplotlib.animation as manimation +from matplotlib.animation import FFMpegWriter # Fixing random state for reproducibility np.random.seed(19680801) -FFMpegWriter = manimation.writers['ffmpeg'] metadata = dict(title='Movie Test', artist='Matplotlib', comment='Movie support!') writer = FFMpegWriter(fps=15, metadata=metadata) diff --git a/examples/animation/histogram.py b/examples/animation/histogram.py index 365157172ab2..2556708dd7e7 100644 --- a/examples/animation/histogram.py +++ b/examples/animation/histogram.py @@ -4,8 +4,8 @@ ================== Use a path patch to draw a bunch of rectangles for an animated histogram. - """ + import numpy as np import matplotlib.pyplot as plt diff --git a/examples/animation/rain.py b/examples/animation/rain.py index 3e96be613b6f..6fe60ff0520d 100644 --- a/examples/animation/rain.py +++ b/examples/animation/rain.py @@ -8,6 +8,7 @@ Author: Nicolas P. Rougier """ + import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation @@ -65,7 +66,6 @@ def update(frame_number): scat.set_offsets(rain_drops['position']) -# Construct the animation, using the update function as the animation -# director. +# Construct the animation, using the update function as the animation director. animation = FuncAnimation(fig, update, interval=10) plt.show() diff --git a/examples/animation/random_data.py b/examples/animation/random_data.py deleted file mode 100644 index 3c1d6f933087..000000000000 --- a/examples/animation/random_data.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -=========== -Random data -=========== - -An animation of random data. - -""" - -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.animation as animation - -# Fixing random state for reproducibility -np.random.seed(19680801) - - -fig, ax = plt.subplots() -line, = ax.plot(np.random.rand(10)) -ax.set_ylim(0, 1) - - -def update(data): - line.set_ydata(data) - return line, - - -def data_gen(): - while True: - yield np.random.rand(10) - -ani = animation.FuncAnimation(fig, update, data_gen, interval=100) -plt.show() diff --git a/examples/animation/simple_3danim.py b/examples/animation/random_walk.py similarity index 96% rename from examples/animation/simple_3danim.py rename to examples/animation/random_walk.py index d248d61b4748..ae60ce7c09ec 100644 --- a/examples/animation/simple_3danim.py +++ b/examples/animation/random_walk.py @@ -1,10 +1,10 @@ """ -============ -3D animation -============ +======================= +Animated 3D random walk +======================= -An animated plot in 3D. """ + import numpy as np import matplotlib.pyplot as plt import mpl_toolkits.mplot3d.axes3d as p3 diff --git a/examples/animation/simple_anim.py b/examples/animation/simple_anim.py index 457bfba12fed..2b0f02849f0f 100644 --- a/examples/animation/simple_anim.py +++ b/examples/animation/simple_anim.py @@ -1,10 +1,10 @@ """ -=========== -Simple Anim -=========== +================== +Animated line plot +================== -A simple example of an animated plot """ + import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation @@ -15,16 +15,27 @@ line, = ax.plot(x, np.sin(x)) -def animate(i): - line.set_ydata(np.sin(x + i / 100)) # update the data +def init(): # only required for blitting to give a clean slate. + line.set_ydata([np.nan] * len(x)) return line, -# Init only required for blitting to give a clean slate. -def init(): - line.set_ydata(np.ma.array(x, mask=True)) +def animate(i): + line.set_ydata(np.sin(x + i / 100)) # update the data. return line, + ani = animation.FuncAnimation( fig, animate, init_func=init, interval=2, blit=True) + +# To save the animation, use e.g. +# +# ani.save("movie.mp4") +# +# or +# +# from matplotlib.animation import FFMpegWriter +# writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) +# ani.save("movie.mp4", writer=writer) + plt.show() diff --git a/examples/animation/strip_chart_demo.py b/examples/animation/strip_chart.py similarity index 100% rename from examples/animation/strip_chart_demo.py rename to examples/animation/strip_chart.py index 60a5db6b13b4..8e9bf2dad659 100644 --- a/examples/animation/strip_chart_demo.py +++ b/examples/animation/strip_chart.py @@ -5,6 +5,7 @@ Emulates an oscilloscope. """ + import numpy as np from matplotlib.lines import Line2D import matplotlib.pyplot as plt @@ -58,5 +59,4 @@ def emitter(p=0.03): ani = animation.FuncAnimation(fig, scope.update, emitter, interval=10, blit=True) - plt.show() diff --git a/examples/animation/subplots.py b/examples/animation/subplots.py deleted file mode 100644 index 9af8296471a1..000000000000 --- a/examples/animation/subplots.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -================= -Animated subplots -================= - -This example uses subclassing, but there is no reason that the proper function -couldn't be set up and then use FuncAnimation. The code is long, but not -really complex. The length is due solely to the fact that there are a total of -9 lines that need to be changed for the animation as well as 3 subplots that -need initial set up. - -""" - -import numpy as np -import matplotlib.pyplot as plt -from matplotlib.lines import Line2D -import matplotlib.animation as animation - - -class SubplotAnimation(animation.TimedAnimation): - def __init__(self): - fig = plt.figure() - ax1 = fig.add_subplot(1, 2, 1) - ax2 = fig.add_subplot(2, 2, 2) - ax3 = fig.add_subplot(2, 2, 4) - - self.t = np.linspace(0, 80, 400) - self.x = np.cos(2 * np.pi * self.t / 10.) - self.y = np.sin(2 * np.pi * self.t / 10.) - self.z = 10 * self.t - - ax1.set_xlabel('x') - ax1.set_ylabel('y') - self.line1 = Line2D([], [], color='black') - self.line1a = Line2D([], [], color='red', linewidth=2) - self.line1e = Line2D( - [], [], color='red', marker='o', markeredgecolor='r') - ax1.add_line(self.line1) - ax1.add_line(self.line1a) - ax1.add_line(self.line1e) - ax1.set_xlim(-1, 1) - ax1.set_ylim(-2, 2) - ax1.set_aspect('equal', 'datalim') - - ax2.set_xlabel('y') - ax2.set_ylabel('z') - self.line2 = Line2D([], [], color='black') - self.line2a = Line2D([], [], color='red', linewidth=2) - self.line2e = Line2D( - [], [], color='red', marker='o', markeredgecolor='r') - ax2.add_line(self.line2) - ax2.add_line(self.line2a) - ax2.add_line(self.line2e) - ax2.set_xlim(-1, 1) - ax2.set_ylim(0, 800) - - ax3.set_xlabel('x') - ax3.set_ylabel('z') - self.line3 = Line2D([], [], color='black') - self.line3a = Line2D([], [], color='red', linewidth=2) - self.line3e = Line2D( - [], [], color='red', marker='o', markeredgecolor='r') - ax3.add_line(self.line3) - ax3.add_line(self.line3a) - ax3.add_line(self.line3e) - ax3.set_xlim(-1, 1) - ax3.set_ylim(0, 800) - - animation.TimedAnimation.__init__(self, fig, interval=50, blit=True) - - def _draw_frame(self, framedata): - i = framedata - head = i - 1 - head_slice = (self.t > self.t[i] - 1.0) & (self.t < self.t[i]) - - self.line1.set_data(self.x[:i], self.y[:i]) - self.line1a.set_data(self.x[head_slice], self.y[head_slice]) - self.line1e.set_data(self.x[head], self.y[head]) - - self.line2.set_data(self.y[:i], self.z[:i]) - self.line2a.set_data(self.y[head_slice], self.z[head_slice]) - self.line2e.set_data(self.y[head], self.z[head]) - - self.line3.set_data(self.x[:i], self.z[:i]) - self.line3a.set_data(self.x[head_slice], self.z[head_slice]) - self.line3e.set_data(self.x[head], self.z[head]) - - self._drawn_artists = [self.line1, self.line1a, self.line1e, - self.line2, self.line2a, self.line2e, - self.line3, self.line3a, self.line3e] - - def new_frame_seq(self): - return iter(range(self.t.size)) - - def _init_draw(self): - lines = [self.line1, self.line1a, self.line1e, - self.line2, self.line2a, self.line2e, - self.line3, self.line3a, self.line3e] - for l in lines: - l.set_data([], []) - -ani = SubplotAnimation() -# ani.save('test_sub.mp4') -plt.show() diff --git a/examples/animation/unchained.py b/examples/animation/unchained.py index faa2cf0a29c1..fbcce8337ee9 100644 --- a/examples/animation/unchained.py +++ b/examples/animation/unchained.py @@ -3,11 +3,12 @@ MATPLOTLIB **UNCHAINED** ======================== -Comparative path demonstration of frequency from a fake signal of a pulsar. -(mostly known because of the cover for Joy Division's Unknown Pleasures) +Comparative path demonstration of frequency from a fake signal of a pulsar +(mostly known because of the cover for Joy Division's Unknown Pleasures). Author: Nicolas P. Rougier """ + import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation @@ -67,7 +68,6 @@ def update(*args): # Return modified artists return lines -# Construct the animation, using the update function as the animation -# director. +# Construct the animation, using the update function as the animation director. anim = animation.FuncAnimation(fig, update, interval=10) plt.show()