matplotlib/matplotlib — pull request #1012 by jdh2358 (2012-07-15 17:55:05+00:00)
Title: Animation fixes

This PR fixes a few problems with the new animation write functionality.

The first commit addresses the problem that there was no way to get
the args to setup that you may want to customize. The
MovieWriter.setup method only gets called Animation.save in the "with
writer.saving" call, but there is no way to pass extra args through to
setup like "clear_temp=False" to the FileMovieWriter.

To fix this, I added an optional dictionary argument to Animation.save
called "writer_setup_kwargs" that get passed through to "saving" and
ultimately "setup", so you can use it like:

im_ani.save('movies/im1.mp4', writer=writer,
writer_setup_kwargs=dict(clear_temp=False))

The second commit fixes a serious problem in the that the args and
kwargs passed to the writer were being dropped on the floor. This
ultimately is another example of why multiple inheritance is
dangerous. Effectively, what we have in master is:

class MovieWriter:
def __init__(self, name='jdh'):
self.name = 'jdh'

class FFMpegBase:
# no init method
def getx(self):
return 1

class FFMpegWriter(MovieWriter, FFMpegBase):
pass

mixin = FFMpegWriter(name='tom')
print mixin.name

which when you test this you will see that "mixin.name" still gets the
default value for name="jdh" because the FFMpegWriter did not define
an init method and pass the args to the proper base class Moviewriter.
The second commit fixes this. However, I strongly advise @dopplershift to
reconsider the design and get rid of multiple inheritance. There is
just not enough advantage to overweigh the dangers, as we see here.

Here is a real-world example using the existing animation code that shows the problem:

writer = animation.FFMpegFileWriter(fps=15, codec='webm', bitrate=1800)
print 'CODEC', writer.codec
print 'FPS', writer.fps

The third commit adds information to the docstrings for Animation.save to
point out that the fps, bitrate and codec args are only utilized if
the writer is a string; if the writer is a class instance they are
ignored in the current code. We may want to change this to set them
on the writer unconditionally (I actually favor this) but in this
commit I just clarify the current behavior. I also added support for
the special codec 'None'. We use None to mean "use the default codec"
but there is at least one case when you want to force the codec to not
be included on the command line, and that is when you are using a
special -f arg to ffmpeg. Eg, in order to get webm movies, I need a
line like:

ffmpeg -r 15 -i _tmp%04d.png -f webm -y im1.webm

which I could do if I could get the writer to drop the 'vcodec' arg and add the -f arg using:

writer = Writer(fps=15, codec='None', extra_args=['-f', 'webm'])

In the fourth commit, I added support for the ipython display protocol so animations made in the notebook would display a movie window in the browser.

In the fifth commit, I fixed the basic_animation_writer.py example so
that we woud not be creatig a huge list of ax.colleciotns with every
call to pcolor. The new loop looks like:

for add in np.arange(15):
ax.cla() # clear the last frame
im = ax.pcolor(x, y, base + add, norm=plt.Normalize(0, 30))
ims.append([im])

and the cla call prevents pcolor from creating 15 different
collections.

The final commit adds a commented out example to the basic_animation_writer.py example that shows how to create webm movies using ffmpeg. These are supported by chrome and firefox by default, so work using the embedded html ipython display protocol with most stock browsers.