I have to make an animation of a large number (~90,000) figures. For context, it\'s a plot of a map for every day from 1700 - 1950, with events of interest marked on relevent da
Same solution as JuniorCompressor, with just one frame kept in memory to avoid RAM issues. This example runs in 30 seconds on my machine and produces a good quality 400-second clip of 6000 frames, weighing 600k.
import numpy as np
import matplotlib.pyplot as plt
from moviepy.video.io.bindings import mplfig_to_npimage
import moviepy.editor as mpy
fig = plt.figure(facecolor="white") # <- ADDED FACECOLOR FOR WHITE BACKGROUND
ax = plt.axes()
x = np.random.randn(10, 1)
y = np.random.randn(10, 1)
p = plt.plot(x, y, 'ko')
time = np.arange(2341973, 2342373)
last_i = None
last_frame = None
def animate(t):
global last_i, last_frame
i = int(t)
if i == last_i:
return last_frame
xn = x + np.sin(2 * np.pi * time[i] / 10.0)
yn = y + np.cos(2 * np.pi * time[i] / 8.0)
p[0].set_data(xn, yn)
last_i = i
last_frame = mplfig_to_npimage(fig)
return last_frame
duration = len(time)
fps = 15
animation = mpy.VideoClip(animate, duration=duration)
animation.write_videofile("test.mp4", fps=fps)
On a sidenote, there is dedicated class of videoclips called DataVideoClip for precisely this purpose, which looks much more like matplotlib's animate
. For the moment it's not really speed-efficient (I didn't include that little memoizing trick above). Here is how it works:
from moviepy.video.VideoClip import DataVideoClip
def data_to_frame(time):
xn = x + np.sin(2 * np.pi * time / 10.0)
yn = y + np.cos(2 * np.pi * time / 8.0)
p[0].set_data(xn, yn)
return mplfig_to_npimage(fig)
times = np.arange(2341973, 2342373)
clip = DataVideoClip(times, data_to_frame, fps=1) # one plot per second
#final animation is 15 fps, but still displays 1 plot per second
animation.write_videofile("test2.mp4", fps=15)