A quick introduction to motionpicture

motionpicture is a Python library that takes care of all the infrastructure needed to render frames and animate them into a video. When you install kuibit, motionpicture will be automatically installed. With this page, you will learn how the basics of how use motionpicture.

Overall considerations

The key ingredient in motionpicture are movie files. These are Python files that specify how to render one frame and what constitute a frame (e.g., one iteration = one frame). kuibit comes with a series of movie files for common videos (e.g., 2D plots of a given grid function) which are ready to be used. Later in this document, we will discuss how to write movie files.

The second important element in motionpicture is mopi. mopi is a command-line executable that takes as argument a movie file and renders the frames and the videos. mopi has a lot of options that can be explored with the --help flag.

motionpicture requires ffmpeg, which has to be installed separately.

Animating frames

At level zero, motionpicture is a tool to glue together frames. Suppose you have a folder frames full of files 0000.png, 0001.png, …, and you want to make a video out of them. You can use mopi for that.

$ mopi --only-render-movie --frame-name-format '%04d.png' --outdir frames --movie-name my_video

This will create a file my_video.mp4 with the specified frames. The advantage of using mopi for this task is that it comes with a lot of options that can be easily explored in the --help. For example,

$ mopi --only-render-movie --frame-name-format '%04d.png' --outdir frames --movie-name my_video \
       --fps 60 --extension webm --title "My video" --comment "This is my first video with mopi" \
       --author "Me"

Making and animating frames

Suppose you want to make frames, and then animate them. This is the core functionality of motionpicture, and the main benefits of using the tool is that you have to worry only about making one single frame, and everything else is taken care of (including parallelization)

mopi can take as input a Python file which defines a class MOPIMovie which contains methods to identify what is a frame and how to draw it. Such files can be specified with the flag -m, or they can be read from a folder defined by the environment variable MOPI_MOVIES_DIR. mopi will load the chosen movie and will expose all the command-line options that are defined there. For instance, if you defined the environment variable MOPI_MOVIES_DIR and grid_var is in that folder, then mopi grid_var --help will look like this:

usage: mopi [-m MOVIE_FILE] [-c CONFIG] [--movies-dir MOVIES_DIR] [-o OUTDIR] [--snapshot SNAPSHOT] [--disable-progress-bar] [--parallel]
            [--num-workers NUM_WORKERS] [--only-render-movie] [--frame-name-format FRAME_NAME_FORMAT] [-v] [-h] [--min-frame MIN_FRAME]
            [--max-frame MAX_FRAME] [--frames-every FRAMES_EVERY] [--movie-name MOVIE_NAME] [--extension EXTENSION] [--fps FPS]
            [--author AUTHOR] [--title TITLE] [--comment COMMENT] [--datadir DATADIR] [--resolution RESOLUTION] [-x0 ORIGIN ORIGIN]
            [-x1 CORNER CORNER] [--plane {xy,xz,yz}] [--figname FIGNAME] [--fig-extension FIG_EXTENSION] [--ah-show] [--ah-color AH_COLOR]
            [--ah-edge-color AH_EDGE_COLOR] [--ah-alpha AH_ALPHA] [--ah-time-tolerance AH_TIME_TOLERANCE] --variable VARIABLE
            [--multilinear-interpolate] [--interpolation-method INTERPOLATION_METHOD] [--colorbar] [--logscale] [--vmin VMIN] [--vmax VMAX]
            [--absolute]
            [movie]

Make a video specifying all the details using command-line arguments. To use this utility, you have to specify a movie. This code will look for movies in the MOPI_MOVIES_DIR, which you can customize. To select one of these movies, just pass the file name as first argument. Alternatively, you can pass the argument -m and specify a file.

General options:
  movie                 Movie to render among the ones found in MOPI_MOVIES_DIR. See bottom of the help message for list.
  -m MOVIE_FILE, --movie-file MOVIE_FILE
                        Path of the movie file.
  -c CONFIG, --config CONFIG
                        Config file path
  --movies-dir MOVIES_DIR
                        Folder where to look form movies.   [env var: MOPI_MOVIES_DIR]
  -o OUTDIR, --outdir OUTDIR
                        Output directory for frames and video.
  --snapshot SNAPSHOT   Only produce the specified snapshot (useful for testing).
  --disable-progress-bar
                        Do not display the progress bar when generating frames.
  --parallel            Render frames in parallel.
  --num-workers NUM_WORKERS
                        Number of cores to use (default: 8).
  --only-render-movie   Do not generate frames but only render the final video.
  --frame-name-format FRAME_NAME_FORMAT
                        If only-render-movie is set, use this C-style frame name format instead of computing it. For example, '%04d.png' will assemble a video with frames with names 0000.png, 0001.png, and so on, as found in the outdir folder.
  -v, --verbose         Enable verbose output.
  -h, --help            Show this help message and exit.

Frame selection:
  --min-frame MIN_FRAME
                        Do not render frames before this one.
  --max-frame MAX_FRAME
                        Do not render frames after this one.
  --frames-every FRAMES_EVERY
                        Render a frame every N (default: render all the possible frames).

Video rendering options:
  --movie-name MOVIE_NAME
                        Name of output video file, without extension (default: video).
  --extension EXTENSION
                        File extension of the video (default: mp4).
  --fps FPS             Frames-per-second of the video (default: 25).
  --author AUTHOR       Author metadata in the final video.
  --title TITLE         Title metadata in the final video.
  --comment COMMENT     Comment metadata in the final video.

Movie custom options:
  --datadir DATADIR     Data directory.
  --resolution RESOLUTION
                        Resolution of the grid in number of points (default: 500)
  -x0 ORIGIN ORIGIN, --origin ORIGIN ORIGIN
  -x1 CORNER CORNER, --corner CORNER CORNER
  --plane {xy,xz,yz}    Plane to plot (default: xy)
  --figname FIGNAME     Name of the output figure (not including the extension).
  --fig-extension FIG_EXTENSION
                        Extension of the output figure (default: png).   [env var: KBIT_FIG_EXTENSION]
  --variable VARIABLE   Variable to plot.
  --multilinear-interpolate
                        Whether to interpolate to smooth data with multilinear interpolation before plotting.
  --interpolation-method INTERPOLATION_METHOD
                        Interpolation method for the plot. See docs of np.imshow. (default: none)
  --colorbar            Whether to draw the color bar.
  --logscale            Whether to use log scale.
  --vmin VMIN           Minimum value of the variable. If logscale is True, this has to be the log.
  --vmax VMAX           Maximum value of the variable. If logscale is True, this has to be the log.
  --absolute            Whether to take the absolute value.

No movies found in the MOPI_MOVIES_DIR (.)

Args that start with '--' (eg. -m) can also be set in a config file (specified via -c). Config file syntax allows: key=value, flag=true,
stuff=[a,b,c] (for details, see syntax at https://goo.gl/R74nmi). If an arg is specified in more than one place, then commandline values
override environment variables which override config file values which override defaults.

With this, you can now make a 2D movie of any given grid function of any given simulations with parameters you can control via command-line. One of the most useful option is --parallel to render frames using all the cores of the machine.

Let us have a look at a simplified version of grid_var:

from kuibit import argparse_helper as kah
from kuibit.simdir import SimDir
from kuibit.visualize_matplotlib import (
    plot_color,
    save,
)


def mopi_add_custom_options(parser):
    # These are the custom options that mopi will see.

    parser.add_argument("--datadir", default=".", help="Data directory.")
    kah.add_grid_to_parser(parser, dimensions=2)
    kah.add_figure_to_parser(parser)

    parser.add_argument(
        "--variable", type=str, required=True, help="Variable to plot."
    )

class MOPIMovie:
    def __init__(self, args):
        # Here we initialize all the objects that we need for all the frames.
        # All the expensive stuff has to be done here.

        self.sim = SimDir(args.datadir, ignore_symlinks=args.ignore_symlinks)
        self.x0, self.x1, self.res = args.origin, args.corner, args.resolution
        self.shape = [self.res, self.res]
        self.reader = self.sim.gridfunctions[args.plane]
        self.var = self.reader[args.variable]

        self.iterations = self.var.available_iterations

    def get_frames(self):
        # Here we define what is a "frame" (it is one iteration). This function
        # has to return an iterable on what we want to make frames of.
        return self.iterations

    def make_frame(self, path, iteration):
        # Here we plot a frame. This function has to take the output path and
        # the identifier of what is a frame (in this case, an iteration).

        plot_color(
            self.var[iteration],
            x0=self.x0,
            x1=self.x1,
            shape=self.shape,
            xlabel=self.args.plane[0],
            ylabel=self.args.plane[1],
            resample=self.args.multilinear_interpolate,
            colorbar=self.args.colorbar,
            logscale=self.args.logscale,
            vmin=self.args.vmin,
            vmax=self.args.vmax,
            label=label,
            interpolation=self.args.interpolation_method,
        )

        save(path)

As you see, movie files are relatively simple. They have one (optional) function mopi_add_custom_options that defines the command-line options, and a class MOPIMovie. This class has three methods: a __init__, which is run once and sets up the data that is used by all the frames, a get_frames, which defines what is a frame (here we used iteration, but it could be time, or anything else), and a method make_frame which produces a given frame. Read the official documentation for a detailed description on how to write movie files.