Animations

The aim of this module is to quickly and easily create animations. Here, an animation is a kind of interactive-widgets plot, which contains a figure and widgets to control the playback. Animations can be created using either one of the following modules:

  • ipywidgets and ipympl: it only works inside Jupyter Notebook.

  • Holoviz’s panel: works on any Python interpreter, as long as a browser is installed on the system. The interactive plot can be visualized directly in Jupyter Notebook, or in a new browser window where the plot can use the entire screen space.

If only a minimal installation of this plotting module has been performed, then users have to manually install the chosen interactive modules.

By default, this plotting module will attempt to create animations with ipywidgets. To change interactive module, users can either:

  1. specify the following keyword argument to use Holoviz’s Panel: imodule="panel". By default, the modules uses imodule="ipywidgets".

  2. Modify the configuration file to permanently change the interactive module. More information are provided in 4 - Customizing the module.

Note that:

  • To create an animation, users have to provide the params= and animation= keyword arguments to a plotting function. In particular, params= is different from what is used in the Interactive module. More on this in the documentation below.

  • If the user is attempting to execute an interactive widget plot and gets an error similar to the following: TraitError: The ‘children’ trait of a Box instance contains an Instance of a TypedTuple which expected a Widget, not the FigureCanvasAgg at ‘0x…’. It means that the ipywidget module is being used with Matplotlib, but the interactive Matplotlib backend has not been loaded. First, execute the magic command %matplotlib widget, then execute the plot command.

  • Tha aim of this module is to remain as simple as possible, while using the already implemented code that makes interactive-widgets plots possible. If a user needs more customization options, then Manim is a far more powerful alternative.

spb.animation.panel.animation(*series, show=True, **kwargs)[source]

Create an animation containing the plot and a few interactive controls (play/pause/loop buttons).

Parameters:
seriesBaseSeries

Instances of spb.series.BaseSeries, representing the symbolic expression to be plotted.

animationbool or dict
  • False (default value): no animation.

  • True: the animation will use the following default values: fps=30, time=5.

  • dict: the dictionary should contain these optional keys:

    • "fps": frames per second of the animation.

    • "time": total animation time.

It must be noted that these values are exact only if the animation is going to be saved on a file. For interactive applications, these values are just indicative: the animation is going to compute new data at each time step. Hence, the more data needs to be computed, the slower the update.

paramsdict

A dictionary mapping the symbols to a parameter. The parameter can be:

  1. a tuple of the form (min, max, spacing), where:

    • min, maxfloat

      Minimum and maximum values. Must be finite numbers.

    • spacingstr, optional

      Specify the discretization spacing. Default to "linear", can be changed to "log".

    This can be used to simulate a slider.

  2. A dictionary mapping specific animation times to parameter values. This is useful to simulate steps (or values from a dropdown widget, or a spinner widget). For example, let tf be the animation time. Then, this dictionary, {t1: v1, t2: v2}, creates the following steps:

    • 0 for 0 <= t <= t1.

    • v1 for t1 <= t <= t2.

    • v2 for t2 <= t <= tf.

  3. A 1D numpy array, with length given by fps * time, specifying the custom value at each animation frame (or, at each time step) associated to the parameter.

servablebool, optional

Default to False, which will show the interactive application on the output cell of a Jupyter Notebook. If True, the application will be served on a new browser window.

showbool, optional

Default to True. If True, it will return an object that will be rendered on the output cell of a Jupyter Notebook. If False, it returns an instance of Animation, which can later be shown by calling the show() method, or saved to a GIF/MP4 file using the save() method.

titlestr or tuple

The title to be shown on top of the figure. To specify a parametric title, write a tuple of the form:(title_str, param_symbol1, ...), where:

  • title_str must be a formatted string, for example: "test = {:.2f}".

  • param_symbol1, ... must be a symbol or a symbolic expression whose free symbols are contained in the params dictionary.

Notes

  1. Animations are a special kind of interactive applications. In particular, the output of this function can only be shown on a browser.

  2. Animations can be exported to GIF files or MP4 videos by calling the save() method. More on this in the examples.

  3. Saving K3D-Jupyter animations is particularly slow.

Examples

NOTE: the following examples use the ordinary plotting functions because animation is already integrated with them.

Simple animation with two parameters. Note that:

  • the first parameter goes from a maximum value to a minimum value.

  • the second parameter goes from a minimum value to a maximum value.

  • a parametric title has been set.

  • a set of buttons allow to control the playback of the animation.

from sympy import *
from spb import *
a, b, x = symbols("a b x")
max_r = 30
plot_parametric(
    x * cos(x), x * sin(x), prange(x, a, b),
    aspect="equal", use_cm=False,
    animation=True, params={a: (10, 0), b: (20, max_r)},
    title=("a={:.2f}; b={:.2f}", a, b),
    xlim=(-max_r, max_r), ylim=(-max_r, max_r)
)

(Source code, small.png)

../_images/animation-1.small.png

Animation showing how to:

  • set the frames-per-second and total animation time.

  • set custom values to a parameter. Here, b will vary from 0 to 1 and back to 0 following a sinusoidal law.

  • set a parametric title.

from sympy import *
from spb import *
import numpy as np
a, b, x = symbols("a b x")
fps = 20
time = 6
frames = np.linspace(0, 2*np.pi, fps * time)
b_values = (np.sin(frames - np.pi/2) + 1) / 2
plot(
    cos(a * x) * exp(-abs(x) * b), (x, -pi, pi),
    params={
        a: (0.5, 3),
        b: b_values
    },
    animation={"fps": fps, "time": time},
    title=("a={:.2f}, b={:.2f}", a, b),
    ylim=(-1.25, 1.25)
)

Animation of a 3D surface using K3D-Jupyter. Here we create an Animation object, which can later be used to save the animation to a file.

from sympy import *
from spb import *
import numpy as np
r, theta, t, a = symbols("r, theta, t, a")
expr = cos(r**2 - a) * exp(-r / 3)
p = plot3d_revolution(
    expr, (r, 0, 5), (theta, 0, t),
    params={t: (1e-03, 2*pi), a: (0, 2*pi)},
    use_cm=True, color_func=lambda x, y, z: np.sqrt(x**2 + y**2),
    is_polar=True,
    wireframe=True, wf_n1=30, wf_n2=30,
    wf_rendering_kw={"width": 0.005},
    animation=True,
    title=(r"theta={:.4f}; \, a={:.4f}", t, a),
    backend=KB, grid=False, show=False
)
p.show()
# Use the mouse to properly orient the view and then save the animation
p.save("3d-animation.mp4")

Evolution of a complex function using the graphics module and Plotly. Note that animation=True has been set in the graphics() function call.

from sympy import *
from spb import *
t, tf = symbols("t t_f", real=True)
gamma, omega = Rational(1, 2), 7
f = exp(-gamma * t**2) * exp(I * omega * t)
params = {tf: (-5, 5)}
graphics(
    line_parametric_3d(
        t, re(f), im(f), range=(t, -5, tf), label="f(t)",
        params=params, use_cm=False
    ),
    line_parametric_3d(
        t, re(f), -2, range=(t, -5, tf), label="re(f(t))",
        params=params, use_cm=False
    ),
    line_parametric_3d(
        t, 2, im(f), range=(t, -5, tf), label="im(f(t))",
        params=params, use_cm=False
    ),
    line_parametric_3d(
        5, re(f), im(f), range=(t, -5, tf), label="abs(f(t))",
        params=params, use_cm=False
    ),
    backend=PB, aspect=dict(x=3, y=1, z=1), ylim=(-2, 2), zlim=(-2, 2),
    xlabel="t", ylabel="re(f)", zlabel="im(f)",
    title="$f(t)=%s$" % latex(f), animation=True, size=(704, 512)
)

Plotgrid animation. Note that:

  • Each plot is an interactive animation (they can also be ordinary plots).

  • p2, p3 use defaults fps/time, whereas p1 uses custom values.

  • the overall plotgrid parses the different animations, collecting times and fps. It then choses the highest numbers, and recreates all the parameters. Hence, in the following animation p1 runs for the entire animation.

from sympy import *
from spb import *
from matplotlib.gridspec import GridSpec
a, b, c, d, x, y, z = symbols("a:d x:z")
p1 = plot(
    sin(a*x), cos(a*x),
    animation={"fps": 10, "time": 2}, params={a: (1, 5)}, show=False)
max_r = 30
p2 = plot_parametric(
    x * cos(x), x * sin(x), prange(x, b, c),
    aspect="equal", use_cm=False,
    animation=True, params={b: (10, 0), c: (20, max_r)},
    title=("b={:.2f}; c={:.2f}", b, c),
    show=False, xlim=(-max_r, max_r), ylim=(-max_r, max_r))
p3 = plot_complex(gamma(d*z), (z, -3-3*I, 3+3*I), title=r"$\gamma(d \, z)$",
    animation=True, params={d: (-1, 1)}, coloring="b", grid=False, show=False)
gs = GridSpec(3, 4)
mapping = {
    gs[2, :]: p1,
    gs[0:2, 0:2]: p2,
    gs[0:2, 2:]: p3,
}
plotgrid(gs=mapping)
class spb.animation.BaseAnimation[source]

Implements the base functionalities to create animations.

spb.animation.BaseAnimation.get_FuncAnimation(self)

Return a Matplotlib’s FuncAnimation object. It only works if this animation is showing a Matplotlib’s figure.

spb.animation.BaseAnimation.save(self, path, save_frames=False, **kwargs)

Save the animation to a file.

Parameters:
pathstr

Where to save the animation on the disk. Supported formats are .gif or .mp4.

save_framesbool, optional

Default to False. If True, save individual frames into png files.

**kwargs

Keyword arguments to customize the gif/video creation process. Both gif/video animations are created using imageio.mimwrite. In particular:

  • GIFs are created with imageio.plugins.pillowmulti.GIFFormat

  • MP4s are created with imageio.plugins.ffmpeg.FfmpegFormat. If a video seems to be low-quality, try to increase the bitrate. Its default value is bitrate=3000000.

Notes

  • When saving an animation from Jupyter Notebook/Lab, a progress bar will be visibile, indicating how many frames have been generated.

  • Saving K3D-Jupyter animations is particularly slow.

spb.animation.BaseAnimation.update_animation(self, frame_idx)

Update the figure in order to obtain the visualization at a specified frame of the animation.

Parameters:
frame_idxint

Must be 0 <= frame_idx < fps*time.