Create a movie out of many frames in e.g. mp4 or gif format.

    If the filename ends in `.gif`, `convert` is used to convert all frames to an animated gif using the `cmd_template_gif`
    template. Otherwise `ffmpeg is assumed to know the file format`.

    Example:

    >>> def set_angles(fig, i, fraction):
    >>>     fig.angley = fraction*np.pi*2
    >>> # 4 second movie, that rotates around the y axis
    >>> p3.movie('test2.gif', set_angles, fps=20, frames=20*4,
            endpoint=False)

    Note that in the example above we use `endpoint=False` to avoid to first and last frame to be the same

    :param str f: filename out output movie (e.g. 'movie.mp4' or 'movie.gif')
    :param function: function called before each frame with arguments (figure, framenr, fraction)
    :param fps: frames per seconds
    :param int frames: total number of frames
    :param bool endpoint: if fraction goes from [0, 1] (inclusive) or [0, 1) (endpoint=False is useful for loops/rotatations)
    :param str cmd_template_ffmpeg: template command when running ffmpeg (non-gif ending filenames)
    :param str cmd_template_gif: template command when running imagemagick's convert (if filename ends in .gif)
    :param gif_loop: None for no loop, otherwise the framenumber to go to after the last frame
    :return: the temp dir where the frames are stored

def movie(
    f="movie.mp4",
    function=_change_azimuth_angle,
    fps=30,
    frames=30,
    endpoint=False,
    cmd_template_ffmpeg="ffmpeg -y -r {fps} -i {tempdir}/frame-%5d.png -vcodec h264 -pix_fmt yuv420p {filename}",
    cmd_template_gif="convert -delay {delay} {loop} {tempdir}/frame-*.png {filename}",
    gif_loop=0,
):
    """Create a movie out of many frames in e.g. mp4 or gif format.

    If the filename ends in `.gif`, `convert` is used to convert all frames to an animated gif using the `cmd_template_gif`
    template. Otherwise `ffmpeg is assumed to know the file format`.

    Example:

    >>> def set_angles(fig, i, fraction):
    >>>     fig.angley = fraction*np.pi*2
    >>> # 4 second movie, that rotates around the y axis
    >>> p3.movie('test2.gif', set_angles, fps=20, frames=20*4,
            endpoint=False)

    Note that in the example above we use `endpoint=False` to avoid to first and last frame to be the same

    :param str f: filename out output movie (e.g. 'movie.mp4' or 'movie.gif')
    :param function: function called before each frame with arguments (figure, framenr, fraction)
    :param fps: frames per seconds
    :param int frames: total number of frames
    :param bool endpoint: if fraction goes from [0, 1] (inclusive) or [0, 1) (endpoint=False is useful for loops/rotatations)
    :param str cmd_template_ffmpeg: template command when running ffmpeg (non-gif ending filenames)
    :param str cmd_template_gif: template command when running imagemagick's convert (if filename ends in .gif)
    :param gif_loop: None for no loop, otherwise the framenumber to go to after the last frame
    :return: the temp dir where the frames are stored
    """
    movie_filename = f
    tempdir = tempfile.mkdtemp()
    output = ipywidgets.Output()
    display(output)
    fig = gcf()
    for i in range(frames):
        with output:
            fraction = i / (frames - 1.0 if endpoint else frames)
            function(fig, i, fraction)
            frame_filename = os.path.join(tempdir, "frame-%05d.png" % i)
            savefig(frame_filename, output_widget=output)
    with output:
        if movie_filename.endswith(".gif"):
            if gif_loop is None:
                loop = ""
            else:
                loop = "-loop %d" % gif_loop
            delay = 100 / fps
            cmd = cmd_template_gif.format(delay=delay, loop=loop, tempdir=tempdir, filename=movie_filename)
        else:
            cmd = cmd_template_ffmpeg.format(fps=fps, tempdir=tempdir, filename=movie_filename)
        print(cmd)
        os.system(cmd)
    return tempdir