This notebook demonstrates the tools in the clawpack.visclaw.animation_tools
module (new in Version 5.4.0), which facilitates creating a list of figures or images and viewing them as an animation.
This notebook can be found in $CLAW/apps/notebooks/visclaw
, see http://www.clawpack.org/apps.html for instructions for cloning the Clawpack apps
repository.
Several approaches are supported:
Using the ipywidgets.interact
allows generating an interactive widget for sweeping through the frames. This may be easiest to work with when running a notebook interactively, including when using http://mybinder.org.
Using the JSAnimation
package from https://github.com/jakevdp/JSAnimation creates animations with controls that allow viewing as a movie more easily. You can also create a stand-alone html file of an animation to post on the web. Moreover movies created with JSAnimation and saved with the notebook will operate properly when viewed via nbviewer
or when viewing a notebook on GitHub. However, do not try to run such a movie on a binder instance, or the JavaScript will go into an infinite loop.
The JSAnimation
version can also be embedded in another webpage or in Sphinx documentation, using the animation_tools.make_html
and animation_tools.make_rst
functions.
An mp4
file can also be created using the animation_tools.make_mp4
function.
_plots
directory to animations:¶The script make_anim.py illustrates how to turn the png files in a Clawpack _plots
directory into stand-alone .html
, .mp4
, or .rst
files.
%pylab inline
Populating the interactive namespace from numpy and matplotlib
from __future__ import print_function
from ipywidgets import interact, interact_manual
import ipywidgets
import os
import io
import base64
from IPython.display import display, FileLink, FileLinks, HTML
from clawpack.visclaw import animation_tools
You can make figures however you want. As they are created, append to a list called figs
:
figs = []
x = linspace(0,1,1000)
for k in range(11):
fig = figure(figsize=(5,3))
plot(x, sin(2*pi*k*x), 'b')
ylim(-1.1,1.1)
title('$\sin(2\pi kx)$ for k = %s' % k)
figs.append(fig)
close(fig)
The tool animation_tools.interact_animate_figs
can be used to create an interact that loops over all the frames contained in a list of figures.
animation_tools.interact_animate_figs(figs)
Passing in the argument manual=True
will use the widget interact_manual
instead of interact
. This refrains from updating the image as you move the slider bar. Instead you move the slider as desired and then click on the Run
button to re-display the image. This is useful if there are many frames and you want to be able to jump to around without all the intermediate frames being displayed, which can slow down the response significantly.
animation_tools.interact_animate_figs(figs, manual=True)
The argument TextInput=True
can be specified to produce a text input cell rather than a slider bar:
animation_tools.interact_animate_figs(figs, manual=True, TextInput=True)
Valid frameno values: from 0 to 10
The tool animation_tools.interact_animate_images
can be used to create an interact that loops over all the frames contained in a list of images rather than figures. The images can be generated from a list of figures, as illustrated in the next cell. Or they can be read in from a directory of png files, for example, as illustrated later.
This function also takes the arguments manual
and TextInput
as described above, with default values False
.
images = animation_tools.make_images(figs)
animation_tools.interact_animate_images(images, figsize=(6,3))
A list of images can also be turned into a JSAnimation inline plot:
animation_tools.JSAnimate_images(images, figsize=(6,3))
Alternatively, a separate stand-alone html page can be created with the JSAnimation. This can be posted on the web for others to view, for example.
anim = animation_tools.JSAnimate_images(images, figsize=(5,4));
# display(anim) # to display it in the notebook
file_name = 'SineFunctions.html'
animation_tools.make_html(anim, file_name=file_name, title="Sine Functions",
raw_html="Illustration of html file created by <tt>make_html</tt>")
FileLink(file_name)
Created SineFunctions.html
You can also produce a .rst
file containing the animation, which can be incorporated into Sphinx documentation:
file_name = 'SineFunctions.rst'
animation_tools.make_rst(anim, file_name=file_name)
FileLink(file_name)
Created SineFunctions.rst Imbed this in another rst file using: .. include:: SineFunctions.rst
Note that ffmpeg must be installed in order to create an mp4
file.
Give it a try:
file_name = 'SineFunctions.mp4'
animation_tools.make_mp4(anim, file_name=file_name)
Created SineFunctions.mp4
if os.path.isfile(file_name):
video = io.open(file_name, 'r+b').read()
encoded = base64.b64encode(video)
data = '''<video alt="test" controls>
<source src="data:video/mp4;base64,{0}" type="video/mp4" />
</video>'''.format(encoded.decode('ascii'))
print("If the mp4 file doesn't display here your browser (e.g. Chrome) might not support it")
else:
data = "File not found: %s" % file_name
HTML(data=data)
If the mp4 file doesn't display here your browser (e.g. Chrome) might not support it
Sometimes it is useful to create a directory containing png files for each figure, or you might have such a directory generated by other means (e.g. from VisClaw).
Here we create a directory named _plots
to store png files for each frame:
plotdir = '_plots'
animation_tools.make_plotdir(plotdir, clobber=True)
Figure files for each frame will be stored in _plots
You can create frames any way you wish and then use animation_tools.save_frame
to save each one. You can also explicitly call savefig
, but then you should construct file names such that glob.glob
can be used to return a list of filenames in the directory that are in the correct order for plotting as frames in an animation. The animation_tools.save_frame
creates names such as frame00000.png
etc. as shown below. The optional argument fname_base
can be used to change frame
to something else.
x = linspace(0,1,1000)
for k in range(5):
fig = figure(figsize=(6,3))
plot(x, cos(2*pi*k*x), 'b')
ylim(-1.1,1.1)
title('$\cos(2\pi kx)$ for k = %s' % k)
animation_tools.save_frame(k, verbose=True)
close(fig)
Saved _plots/frame00000.png Saved _plots/frame00001.png Saved _plots/frame00002.png Saved _plots/frame00003.png Saved _plots/frame00004.png
FileLinks(plotdir)
Given such a directory of png files, we can read them in using animation_tools.read_images
to produce a list of images:
cosine_images = animation_tools.read_images(plotdir='_plots', fname_pattern='frame*.png')
print("Found %i images" % len(cosine_images))
Found 5 images
The resulting list of images new_images
can now be animated using any of the tools illustrated earlier, e.g.
animation_tools.interact_animate_images(cosine_images)
If you already have a list of figures or images and wish to create a directory containing them, the utilities animation_tools.save_figs
or animation_tools.save_images
can be used. For example:
animation_tools.save_images(cosine_images, plotdir='cosine_images', fname_base='wavenumber',
format='png', verbose=True, kwargs={'dpi':150})
FileLinks('cosine_images')
Figure files for each frame will be stored in cosine_images Saved cosine_images/wavenumber00000.png Saved cosine_images/wavenumber00001.png Saved cosine_images/wavenumber00002.png Saved cosine_images/wavenumber00003.png Saved cosine_images/wavenumber00004.png
reload_images = animation_tools.read_images(plotdir='cosine_images', fname_pattern='wavenumber*.png')
animation_tools.interact_animate_images(reload_images)