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
andipympl
: 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:
specify the following keyword argument to use Holoviz’s Panel:
imodule="panel"
. By default, the modules usesimodule="ipywidgets"
.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=
andanimation=
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:
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.
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.
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 theshow()
method, or saved to a GIF/MP4 file using thesave()
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 theparams
dictionary.
Notes
Animations are a special kind of interactive applications. In particular, the output of this function can only be shown on a browser.
Animations can be exported to GIF files or MP4 videos by calling the
save()
method. More on this in the examples.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) )
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 thegraphics()
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, whereasp1
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 isbitrate=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
.