#!/usr/bin/env python # coding: utf-8 # # Demonstrate animation_tools module # # 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 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 . # # - 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. # # #### Converting frames in a Clawpack `_plots` directory to animations: # # The script [make_anim.py](make_anim.py) illustrates how to turn the png files in a Clawpack `_plots` directory into stand-alone `.html`, `.mp4`, or `.rst` files. # In[1]: get_ipython().run_line_magic('pylab', 'inline') # In[2]: 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 # In[4]: from clawpack.visclaw import animation_tools # ## Generate a set of figures to use for demos # # You can make figures however you want. As they are created, append to a list called `figs`: # In[5]: 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) # ## Animating a list of figures # # 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. # In[6]: 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. # In[7]: 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: # In[8]: animation_tools.interact_animate_figs(figs, manual=True, TextInput=True) # ## Animating a list of images # # 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`. # In[9]: images = animation_tools.make_images(figs) animation_tools.interact_animate_images(images, figsize=(6,3)) # ## JSAnimation # # A list of images can also be turned into a JSAnimation inline plot: # In[10]: animation_tools.JSAnimate_images(images, figsize=(6,3)) # ### Stand-alone html file # # 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. # In[11]: anim = animation_tools.JSAnimate_images(images, figsize=(5,4)); # display(anim) # to display it in the notebook # In[12]: file_name = 'SineFunctions.html' animation_tools.make_html(anim, file_name=file_name, title="Sine Functions", raw_html="Illustration of html file created by make_html") FileLink(file_name) # ### reStructured text file # # You can also produce a `.rst` file containing the animation, which can be incorporated into Sphinx documentation: # In[13]: file_name = 'SineFunctions.rst' animation_tools.make_rst(anim, file_name=file_name) FileLink(file_name) # ### Create an mp4 file # Note that [ffmpeg](https://ffmpeg.org) must be installed in order to create an `mp4` file. # # Give it a try: # In[14]: file_name = 'SineFunctions.mp4' animation_tools.make_mp4(anim, file_name=file_name) # In[15]: if os.path.isfile(file_name): video = io.open(file_name, 'r+b').read() encoded = base64.b64encode(video) data = ''''''.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) # ## Create a directory of png files # # 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: # In[16]: plotdir = '_plots' animation_tools.make_plotdir(plotdir, clobber=True) # 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. # In[17]: 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) # In[18]: 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: # In[19]: cosine_images = animation_tools.read_images(plotdir='_plots', fname_pattern='frame*.png') print("Found %i images" % len(cosine_images)) # The resulting list of images `new_images` can now be animated using any of the tools illustrated earlier, e.g. # In[20]: animation_tools.interact_animate_images(cosine_images) # ## Saving a list of figures or 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: # In[21]: animation_tools.save_images(cosine_images, plotdir='cosine_images', fname_base='wavenumber', format='png', verbose=True, kwargs={'dpi':150}) FileLinks('cosine_images') # In[22]: reload_images = animation_tools.read_images(plotdir='cosine_images', fname_pattern='wavenumber*.png') animation_tools.interact_animate_images(reload_images) # In[ ]: