Cannot save matplotlib animation with ffmpeg

animation, matplotlib, python

Solution

So it turns out there were two issues.

Issue #1: The path to ffmpeg was wrong. I thought I needed to provide the path to the directory that ffmpeg resides in, but I needed to provide the path all the way to the ffmpeg binary.

Issue #2: Prior to testing out my code to generate videos, I sometimes would import a module with the setting `plt.rcParams['savefig.bbox'] = 'tight'`. (I did not think much of it, because I did not use the module, but rcParams persist until you restart the python interpreter.) This `plt.rcParams['savefig.bbox'] = 'tight'` causes the video file to save without any errors, but the frames are all garbled when you try to play the video. Although it took me all evening to track this down, it turns out this is a known issue.

Here is the updated solution that creates a video file for me with a nice, translating, sine wave.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin/ffmpeg'

fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)

def init():
    line.set_data([], [])
    return line,

def animate(i):
    x = np.linspace(0, 2, 1000)
    y = np.sin(2 * np.pi * (x - 0.01 * i))
    line.set_data(x, y)
    return line,

anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)

FFwriter = animation.FFMpegWriter(fps=30, extra_args=['-vcodec', 'libx264'])
anim.save('basic_animation.mp4', writer=FFwriter)

Problem

I am trying to save a simple matplotlib animation from Jake Vanderplas, but I keep getting `OSError: [Errno 13] Permission denied`. I should note that I made two small modifications to Jake Vanderplas's example. I installed ffmpeg from MacPorts so I added the line `plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin'` and I ran into the problem discussed in (Using FFmpeg and IPython), so I added `FFwriter = animation.FFMpegWriter()`. Here is the code: ``` import numpy as np from matplotlib import pyplot as plt from matplotlib import animation plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin' fig = plt.figure() ax = plt.axes(xlim=(0, 2), ylim=(-2, 2)) line, = ax.plot([], [], lw=2) def init(): line.set_data([], []) return line, def animate(i): x = np.linspace(0, 2, 1000) y = np.sin(2 * np.pi * (x - 0.01 * i)) line.set_data(x, y) return line, anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True) FFwriter = animation.FFMpegWriter() anim.save('basic_animation.mp4', writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264']) ``` Here is the traceback: ``` File "ani_debug.py", line 34, in <module> anim.save('basic_animation.mp4', writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264']) File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site- packages/matplotlib/animation.py", line 712, in save with writer.saving(self._fig, filename, dpi): File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/contextlib.py", line 17, in __enter__ return self.gen.next() File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 169, in saving self.setup(*args) File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 159, in setup self._run() File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 186, in _run stdin=subprocess.PIPE) File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/subprocess.py", line 709, in __init__ errread, errwrite) File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/subprocess.py", line 1326, in _execute_child raise child_exception OSError: [Errno 13] Permission denied ``` I have also tried using Spyder's built-in python and received a similar traceback. Any suggestions? EDIT: I realized that I did not give the proper path to ffmpeg. Apparently, `plt.rcParams['animation.ffmpeg_path']` does not work similar to `PYTHONPATH`. You must tell the animation module exactly where ffmpeg is with `plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin/ffmpeg'`. Now, I get a movie file that will play, but the content is completely garbled. I can't tell what I am looking at. Here is the traceback: ``` Exception in Tkinter callback Traceback (most recent call last): File "Tkinter.pyc", line 1470, in __call__ File "Tkinter.pyc", line 531, in callit File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/backends/backend_tkagg.py", line 141, in _on_timer TimerBase._on_timer(self) File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/backend_bases.py", line 1203, in _on_timer ret = func(*args, **kwargs) File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 876, in _step still_going = Animation._step(self, *args) File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 735, in _step self._draw_next_frame(framedata, self._blit) File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 753, in _draw_next_frame self._pre_draw(framedata, blit) File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 766, in _pre_draw self._blit_clear(self._drawn_artists, self._blit_cache) File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 806, in _blit_clear a.figure.canvas.restore_region(bg_cache[a]) KeyError: <matplotlib.axes.AxesSubplot object at 0x104cfb150> ``` EDIT: For some reason, everything is working fine now. I have tried things on my home computer and my work computer, and neither one can recreate the garbled video file I got after I fixed the ffmpeg path issue. EDIT: Aaaahaaa! I tracked this sucker down. Sometimes I would import a module that had `plt.rcParams['savefig.bbox'] = 'tight'` in it. (I would never use that module, but rcParams persist, until you restart your python interpreter.) That setting causes the video to come out all garbled. I will post my solution below.

Original source

Related problems