New Animation Class

Hi,

I've been "hard" at work over the last couple of months putting
together a set of classes that simplifies the creation of animations
in matplotlib. This started when I resurrected some old code for
animations to give to a colleague, when I realized just how bad the
old code was and how much better I could do. The result of this
"afternoon" hack is what I'm ready to put forth. Some of the goals:

* Run independently of the backend, unlike the examples we have now
(This is really accomplished by the Timer object we now have)
* Remove the boilerplate code of setting up loops
* Facilitate saving out animations as a movie file
* Provide a simple API that integrates well with the rest of Matplotlib
* Provide (optional) blitting support so that users don't have to
learn the ins and outs of blitting

Overall, I think I accomplished my goals, so I'm putting this out
there for wider comments. I've attached the python module which, when
run, displays two animated figures. There is also a git repository at:

http://github.com/dopplershift/Animation

which has some more examples, including ports of our old examples.
(The examples assume animation.py is in your python path somewhere,
which you'll have to do by hand. This can be as simple as dropping
animation.py into the directory).

Some things to note:
* The flow is broken into *a lot* of member functions. This is to
provide sufficient entry points for subclasses so that they really
only need to reimplement the parts they override. Optional blitting
support drove a lot of this.
* There are two main classes for end users:
  * FuncAnimation -- provide a callback which draws the next frame of animation
  * ArtistAnimation -- provide a sequence of collections of artists
which are turned off and on for each frame of animation
* There is support for saving movies with either mencoder or ffmpeg.
The config for this is really rough, and the place I could *really*
use suggestions. I'm not sure how best to go about it. I've been
unable to find a (currently maintained) python library for saving
movie files, so system calls to the utilities is the best I can do at
the moment. I'm not sure what to use on windows, since I'm not sure of
the state (and requirements) of mencode/ffmpeg on windows.

TODOs:
* Configuring saving movie files (formats, programs, etc.) (see above)
* Documentation (I promise not to commit until this is written)
* More examples (could use some more procedural examples, like
animating using data read from a socket, or inotify)

I welcome feedback on this, because I really want to see this become
an easy and bulletproof way of doing animations in matplotlib. This
seems to be an area of frequent question on the mailing list, and I
want this framework to lessen the questions, not increase them.

Ryan

animation.py (18.6 KB)

···

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma

In my haste to get this out, I forgot to mention that thanks go to Ben
Root for already banging on this quite a bit, giving quite a bit of
useful design feedback and helping me find some bugs.

Ryan

···

On Fri, Jul 9, 2010 at 5:22 PM, Ryan May <rmay31@...149...> wrote:

Hi,

I've been "hard" at work over the last couple of months putting
together a set of classes that simplifies the creation of animations
in matplotlib. This started when I resurrected some old code for
animations to give to a colleague, when I realized just how bad the
old code was and how much better I could do. The result of this
"afternoon" hack is what I'm ready to put forth. Some of the goals:

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma

Very nice -- people are going to really like this. I've had several
requests personally to add something like this so thanks for doing it
:slight_smile:

Some rapid fire comments, in no particular order

  * on recent ubuntu linux with gtkagg, dynamic_image has a "one
pixel" bug on the right side if blit=True. I suspect this has nothing
to do with your package and everything to do with gtkagg blitting code
having an off-by-one error somewhere. I added this to the tracker:
https://sourceforge.net/tracker/?func=detail&aid=3027636&group_id=80706&atid=560720

  * this is completely un-thought out, but could we define a subclass
of TimedAnimation to work like an iterator so users could do the
natural thing :

  line, = ax.plot(something)
  for frame in SomeTimedAnimation(fig, blit=True):
      line.set_data(mydata)
      frame.update()

or something along those lines....

* when you integrate this into trunk, I would like to see widgets.py
upgraded to use it. This is not a requirement and I would be happy to
help with it, but it is a good way to push on the new API and expand
the test cases.

* I am happy to see this pushed into trunk at any time. I would not
push it into the branch, but we can do a 1.1 trunk release as soon as
we are ready (release early, release often). Putting it in the trunk
will facilitate testing and other developer contributions. But if
you'd rather leave it in github for a while, I have no problem with
that either.

* you hardcode the artist visible state True/False in ArtistAnimation,
which overrides any settings the users may be trying to control. Not
sure if this is a problem, but it's something to think about. When
you set False in ArtistAnimation._init_draw, should you first store
the current state so you can restore the userland settings? You
comment that maybe you should be integrating with the "animated"
property. This is essentially what this is for, if animated is set it
should not be used in drawing the background. Not sure if this
matters since it may be sensible to assume they are handing you
control of visibility in ArtistAnimation, just throwing it out there.

* in Animation.save, why do you set blit=False? When making movies,
shouldn't we also depend on the efficiencies of blit? Or was the
idea: blit is buggy so for production movies turn it off cause I'm
willing to sacrifice performance for quality?
If so, I'd rather try an fix the bugs....or expose blit as a kwarg.

* a tutorial for the site docs would be awesome. It's one of the big
missing pieces in the docs, so this would be a good time to add it.

* when you include animation.py in the trunk, would you write the examples as

  import matplotlib.animation as animation
  ani = animation.FuncAnimation(fig, ...)

  per the style guidelines in the coding guide.

* let's preserve the old gui specific examples in a subdir of
examples/animation, so people who need bare metal control will still
have examples to follow. You can add a README in that dir suggesting
the use of the new API unless necessary.

Nice work.

JDH

···

On Fri, Jul 9, 2010 at 5:22 PM, Ryan May <rmay31@...149...> wrote:

I've been "hard" at work over the last couple of months putting
together a set of classes that simplifies the creation of animations
in matplotlib. This started when I resurrected some old code for

Some rapid fire comments, in no particular order
* this is completely un-thought out, but could we define a subclass
of TimedAnimation to work like an iterator so users could do the
natural thing :

line, = ax.plot(something)
for frame in SomeTimedAnimation(fig, blit=True):
line.set_data(mydata)
frame.update()

That's an interesting thought. The challenge would be notifying
SomeTimedAnimation that it needs to stop. Then again, FuncAnimation
already handles this, so it would likely just be a change in syntax,
albeit a good one.

What strikes me now is how to deal with show(). All the animations are
created, and then start once the figures() are displayed with show().
Any ideas on how to make this play with that? At a fundamental level,
these classes are simplifying creating callbacks within the GUI event
loop. I'm not sure the above example can work with that, but I am
ready/willing to be proven wrong.

* when you integrate this into trunk, I would like to see widgets.py
upgraded to use it. This is not a requirement and I would be happy to
help with it, but it is a good way to push on the new API and expand
the test cases.

Interested, but I'm not sure I see your vision here. But then again
I'm too close and only see this animation framework as useful for
animating whole figures. I'm willing to help, but would have to be
led along the way. I will say I was looking at using widgets to make
play/stop/step buttons but haven't really fleshed that out. Those
might also be better done with actual GUI toolkit buttons.

* I am happy to see this pushed into trunk at any time. I would not
push it into the branch, but we can do a 1.1 trunk release as soon as
we are ready (release early, release often). Putting it in the trunk
will facilitate testing and other developer contributions. But if
you'd rather leave it in github for a while, I have no problem with
that either.

Github was a learning experience and a quick convenience for doing
revision control before it was trunk ready. (Which is a reason by
itself to switch to git, full development history rather than
completed chunks.) I'll check in
after I square away a couple more things.

* you hardcode the artist visible state True/False in ArtistAnimation,
which overrides any settings the users may be trying to control. Not
sure if this is a problem, but it's something to think about. When
you set False in ArtistAnimation._init_draw, should you first store
the current state so you can restore the userland settings? You
comment that maybe you should be integrating with the "animated"
property. This is essentially what this is for, if animated is set it
should not be used in drawing the background. Not sure if this
matters since it may be sensible to assume they are handing you
control of visibility in ArtistAnimation, just throwing it out there.

I'll have to think about that.

* in Animation.save, why do you set blit=False? When making movies,
shouldn't we also depend on the efficiencies of blit? Or was the
idea: blit is buggy so for production movies turn it off cause I'm
willing to sacrifice performance for quality?
If so, I'd rather try an fix the bugs....or expose blit as a kwarg.

You pretty much hit the nail on the head. To be honest, I don't think
I've actually tested blitting when saving, I just wasn't ready to
trust the blitting code that much. It should definitely at least be a
kwarg, and I'll have to test to see how reliable it is.

* a tutorial for the site docs would be awesome. It's one of the big
missing pieces in the docs, so this would be a good time to add it.

Definitely. Besides getting everything working, this is #1.

* when you include animation.py in the trunk, would you write the examples as

import matplotlib.animation as animation
ani = animation.FuncAnimation(fig, ...)

per the style guidelines in the coding guide.

Didn't realize we had that codified. I probably need to go read that now....

* let's preserve the old gui specific examples in a subdir of
examples/animation, so people who need bare metal control will still
have examples to follow. You can add a README in that dir suggesting
the use of the new API unless necessary.

Define "bare metal." Since we have the new timer class, I could
convert the old examples to be backend agnostic without using the
animation framework. Just a thought.

Thanks for the useful feedback,

Ryan

···

On Fri, Jul 9, 2010 at 7:27 PM, John Hunter <jdh2358@...149...> wrote:

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma

Since this has stalled 6 weeks with me not doing much with it, I went
ahead and checked it in. Hopefully I'll have an easier time doing
incremental development (especially ReST docs) with it in. There are
definitely still some things to clean up, especially in the area of
saving movies.

Ryan

···

On Fri, Jul 9, 2010 at 7:27 PM, John Hunter <jdh2358@...149...> wrote:

On Fri, Jul 9, 2010 at 5:22 PM, Ryan May <rmay31@...149...> wrote:

I've been "hard" at work over the last couple of months putting
together a set of classes that simplifies the creation of animations
in matplotlib. This started when I resurrected some old code for

Very nice -- people are going to really like this. I've had several
requests personally to add something like this so thanks for doing it
:slight_smile:

* I am happy to see this pushed into trunk at any time. I would not
push it into the branch, but we can do a 1.1 trunk release as soon as
we are ready (release early, release often). Putting it in the trunk
will facilitate testing and other developer contributions. But if
you'd rather leave it in github for a while, I have no problem with
that either.

--
Ryan May
Graduate Research Assistant
School of Meteorology
University of Oklahoma