Making Movies#
Author: Mike Wood
Learning Objectives: By the end of this notebook, you should be able to:
Create a series of images to use as frames of a movie
Compile frames into a movie with Python
Import the libraries for this notebook
# import the numpy, matplotlib, parametric curves, and moviepy libraries
import os
import numpy as np
import matplotlib.pyplot as plt
import parametric_curves as pc
import moviepy.video.io.ImageSequenceClip
Creating Movies#
Creating movies out of data is pretty simple - we just need to make the frames of a movie and then stitch them together.
In this notebook, we will create a movie that sketches out a profile of a face using a given function. The profiles will be generated with parametric curves generated by Wolfram Alpha. The curves for many famous people can be viewed on HERE.
Creating a framework#
To create a movie, first we will need to generate the frames of our movie. Here, we will construct our first image - a testing ground for an eventual function we can update with each timestep to generate the frames.
# define a given time between 0 and 60*pi
time = 9*np.pi
# define a timespan up to the given time
t = np.arange(0.01,time,0.1)
# create a figure object
fig = plt.figure(figsize=(6,8))
# read the curve from the module
x, y = pc.equation_1(t)
# plot a blue circle around the last point
plt.plot(x[-1],y[-1],'bo',markersize=10)
# plot the curve
plt.plot(x,y,'k-')
# show the plot
plt.show()
/Users/mike/Documents/Teaching/Github/intro_to_python_book/data_visualization/parametric_curves.py:58: RuntimeWarning: invalid value encountered in sqrt
322/17)*np.heaviside(3*np.pi - t, 1)*np.heaviside(t + np.pi, 1))*np.heaviside(np.sqrt(np.sign(np.sin(t/2))), 1)
/Users/mike/Documents/Teaching/Github/intro_to_python_book/data_visualization/parametric_curves.py:107: RuntimeWarning: invalid value encountered in sqrt
2103/29)*np.heaviside(3*np.pi - t, 1)*np.heaviside(t + np.pi,1))*np.heaviside(np.sqrt(np.sign(np.sin(t/2))), 1)
Updating the image#
Next, we’ll make the following updates to the image:
set the axis bounds (-500 to 500 in the x direction, -800 to 600 in the y direction)
remove the axes
# make these updates in the following plot
# define a given timebetween 0 and 60*pi
time = 9*np.pi
# define a timespan up to the given time
t = np.arange(0.01,time,0.1)
# create a figure object
fig = plt.figure(figsize=(6,8))
# read the curve from the module
x, y = pc.equation_1(t)
# plot a blue circle around the last point
plt.plot(x[-1],y[-1],'bo',markersize=10)
# plot the curve
plt.plot(x,y,'k-')
# set the axis labels
plt.gca().set_xlim([-500, 500])
plt.gca().set_ylim([-800, 600])
# turn off the axes
plt.axis('off')
# show the plot
plt.show()
Create a function for each frame#
Using the code generated above, make a function to generate each panel. The function should take in time and an output_file path as arguments. Be sure to close each figure after you open them.
# define a frame_function give the time and the output_file
def frame_function(time, output_file):
# paste the plot code from above
# define a timespan up to the given time
t = np.arange(0.01,time,0.01)
# create a figure object
fig = plt.figure(figsize=(6,8))
# read the curve from the module
x, y = pc.equation_1(t)
# plot a blue circle around the last point
plt.plot(x[-1],y[-1],'bo',markersize=10)
# plot the curve
plt.plot(x,y,'k-')
plt.gca().set_xlim([-500, 500])
plt.gca().set_ylim([-800, 600])
plt.axis('off')
# save the plot as a figure
plt.savefig(output_file)
# close the figure
plt.close(fig)
Test the file for one timestep here:
# make an output directory if it does not exist
if 'panels_1' not in os.listdir(os.getcwd()):
os.mkdir(os.path.join(os.getcwd(), 'panels_1'))
# test the function
time = 4
output_file = 'panels_1/frame_'+'{:04d}'.format(0)+'.png'
frame_function(time, output_file)
Make the panels#
With the function created and tested, now we can loop through a number of timesteps to generate the image
# make a time array
times = np.arange(0.02,np.pi*60,0.2)
# make an empty file list to keep track of the file names
file_paths = []
# loop through the time array to generate the panels
for timestep in range(len(times)):
time = times[timestep]
output_file = 'panels_1/frame_'+'{:04d}'.format(timestep)+'.png'
frame_function(time, output_file)
file_paths.append(output_file)
Make the movie#
# sort the file paths (just to be sure they
# are in the correct order)
file_paths.sort()
# set the frames per second
fps=10
# use the ImageSequenceClip module to set up the clip
clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(file_paths, fps=fps)
# write the video to a file
clip.write_videofile('Person 1.mp4')
🤔 Mini-Exercise#
Try it for yourself! See if you can make a movie with the second function provided with the parametric_curve module. Thw following information will be helpful:
the time is 0 to 124\(\pi\)
the x bounds are -800 to 800
the y bounds -1000 to 800