Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ArthurDelannoyazerty/577e1bb56b9a07d023fef6975fefe640 to your computer and use it in GitHub Desktop.
Save ArthurDelannoyazerty/577e1bb56b9a07d023fef6975fefe640 to your computer and use it in GitHub Desktop.
A function that create a gif/mp4 of a rotating 3d matplotlib plot.
def rotanimate(ax, output_filename:str, angles:list=None, elevation:list=None, width:float=8, height:float=8, filename_prefix:str='tmprot_', nb_image:int=120, fps:int=30):
if angles==None: angles = np.linspace(0, 360, nb_image+1)
if elevation==None: elevation = np.linspace(20, 20, nb_image+1)
ax.figure.set_size_inches(width,height)
files = []
for i, angle in enumerate(angles):
ax.view_init(elev = elevation[i], azim=angle)
fname = '%s%03d.jpeg'%(filename_prefix,i)
ax.figure.savefig(fname)
files.append(fname)
os.system('ffmpeg -y -r ' + str(fps) + ' -i tmprot_%03d.jpeg ' + output_filename)
for f in files:
os.remove(f)
@ArthurDelannoyazerty
Copy link
Author

ArthurDelannoyazerty commented May 22, 2024

With all comments & import

import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import axes3d
import os, sys
import numpy as np


def rotanimate(ax, output_filename:str, angles:list=None, elevation:list=None, width:float=8, height:float=8, filename_prefix:str='tmprot_', nb_image:int=120, fps:int=30):
    """
    Produces an animation (.mp4,.ogv,.gif) from a 3D matplotlib plot.
     
    Parameters
    -
        ax (3D axis): the ax containing the plot of interest
        output_filename : name of the output file. The extension determines the kind of animation used.
        angles: list of horizontal angles from where we view the plot. If defined, `nb_image` is not used
        elevation : list of vertical angles from where we view the plot. If defined, a constant of 20° is used
        width : in inches
        heigth: in inches
        filename_prefix : filename prefix of the temporary files 
        nb_image : the number of images generated
        fps : Frame Per Second
    """
    # Generate the angles based on 'nb_image' if 'angles' not defined
    if angles==None: angles = np.linspace(0, 360, nb_image+1)
    if elevation==None: elevation = np.linspace(20, 20, nb_image+1)
    
    ax.figure.set_size_inches(width,height)
    
    # Loop to render and save the images of the plot 
    files = []
    for i, angle in enumerate(angles):
        ax.view_init(elev = elevation[i], azim=angle)
        fname = '%s%03d.jpeg'%(filename_prefix,i)
        ax.figure.savefig(fname)
        files.append(fname)
     
    # Transform the images into animation
    os.system('ffmpeg -y -r ' + str(fps) + ' -i tmprot_%03d.jpeg ' + output_filename)
    
    # Remove the images
    for f in files:
        os.remove(f)

With small comments :

def rotanimate(ax, output_filename:str, angles:list=None, elevation:list=None, width:float=8, height:float=8, filename_prefix:str='tmprot_', nb_image:int=120, fps:int=30):
    # Generate the angles based on 'nb_image' if 'angles' not defined
    if angles==None: angles = np.linspace(0, 360, nb_image+1)
    if elevation==None: elevation = np.linspace(20, 20, nb_image+1)
    
    ax.figure.set_size_inches(width,height)
    
    # Loop to render and save the images of the plot 
    files = []
    for i, angle in enumerate(angles):
        ax.view_init(elev = elevation[i], azim=angle)
        fname = '%s%03d.jpeg'%(filename_prefix,i)
        ax.figure.savefig(fname)
        files.append(fname)
     
    # Transform the images into animation
    os.system('ffmpeg -y -r ' + str(fps) + ' -i tmprot_%03d.jpeg ' + output_filename)
    
    # Remove the images
    for f in files:
        os.remove(f)

Example of code

fig = plt.figure()
ax = fig.add_subplot(projection='3d')
sc = ax.scatter(np.random.random(50),
                np.random.random(50), 
                np.random.random(50), 
                c=np.random.random(50), 
                cmap='copper')
cbar = plt.colorbar(sc)

rotanimate(ax, output_filename='out.gif', nb_image=100, fps=10) 

Output example

FPS 10 30
Number
of
images
50
100
200
350

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment