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 days.
I can do this using matplotlib.animation.FuncAnimation
, and I have code that does this successfully for a small test period. However, with the complete set of figures this is taking an impractical amount of time to render and will result in a very large movie file.
I have read that apparently moviepy
offers both speed and file size advantages. However, I am having trouble getting this to work – I believe my problem is that I have not understood how to correctly set the duration
and fps
arguments.
A simplified version of my code is :
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()
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)
def animate(i):
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)
return mplfig_to_npimage(fig)
fps = 1
duration = len(time)
animation = mpy.VideoClip(animate, duration=duration)
animation.write_videofile("test.mp4", fps=fps)
However, this does not produce the intended result of producing a movie with one frame for each element of time
and saving this to an .mp4. I can’t see where I have gone wrong, any help or pointers would be appreciated.
Best wishes, Luke
Same observations:
animate
a float number will be passedSo you can do the following:
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.
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: