Blitting for animations

[Putting this back on list after I mistakenly took it off.]

Hi Ryan,

Thanks for your reply.

In the course of adding the animations, I also
added a "close_event" to the other backends, so that the
timers would stop on figure close and the users wouldn't
get weird messages. Did you happen to add this?

I added the close_event to the Mac OS X backend today.

I'm not sure you can move this to figure.draw(renderer),
since that's going to draw *everything*.

One solution is to add an .animation attribute to the Figure class, which is None by default (for non-animated drawing).

Roughly, the code should then look as follows:

In the Animation class, the _step method sets Figure.animation and lets the canvas know that it should redraw itself:

def _step(self, *args):
try:
framedata = self.frame_seq.next()
self.figure.animation = self, framedata
self.figure.canvas.draw_idle()
return True
except StopIteration:
return False

Note that no actual drawing is done here.

In the Figure class, the draw method should then become:

def draw(self, renderer):
if self.animation:
animation, framedata = self.animation
animation._draw_next_frame(framedata, animation._blit)
return
# otherwise, draw as usual.

Then all actual drawing is done from inside Figure.draw, which is what the Mac OS X backend needs.

How does this look? If this looks OK, I can try to work out the details and send you the modified code so you can check it out.

I'm not completely wild about it, because it just feels wrong to put
something specific to animation inside figure. The problem we're
trying to solve here is biltting, so is there some way we can improve
how blitting is handled? This would also be a time where we could
(possibly) simplify/improve the blitting API. Do any of the current
uses of blitting work with the MacOSX backend? If those *do* work,
then I'm doing something wrong and need to rework animations. If not,
then we need to find a way to make it so blitting can work in general.

Ryan

···

On Fri, Oct 22, 2010 at 11:45 PM, Michiel de Hoon <mjldehoon@...42...> wrote:

--- On Mon, 10/18/10, Ryan May <rmay31@...149...> wrote:

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

> One solution is to add an .animation attribute to the
> Figure class, which is None by default (for non-animated
> drawing).
I'm not completely wild about it, because it just feels
wrong to put something specific to animation inside figure.

OK I see your point.

The problem we're trying to solve here is biltting, so is
there some way we can improve how blitting is handled?

For a general API for blitting (something that is not restricted to animations), we need two functions: one that tells matplotlib that we want to blit something, and one that does the actual blitting. Right now we only have the latter. Let me point out also that there is nothing peculiar about blitting in Quartz. It's just that in Quartz all drawing operations should be performed from inside the event loop.

For comparison, this is roughly what happens if you draw a line:

plot(x,y)
# tells matplotlib that we want to draw a line
# this triggers a call to
draw_if_interactive()
# this marks the canvas as invalid
# the event loop then calls a callback function to redraw the canvas
# the callback function calls
figure.draw(renderer)
# which calls
renderer.draw_path
# which does the actual drawing

For a general blitting API, we need the equivalent of the plot function; something that informs matplotlib that we want to blit but doesn't do the actual blitting. The actual blitting should then be done from inside figure.draw.

If you just want to implement blitting for animations, one option is to add a draw() method to TimedAnimation, and to set fig.draw = self.draw in the __init__.py of TimedAnimation. Then when a figure needs to be redrawn, TimedAnimation.draw will be called from inside the event loop. Such a TimedAnimation.draw function should then be roughly the same as the current _draw_next_frame function.

Best,
--Michiel.

···

--- On Sun, 10/24/10, Ryan May <rmay31@...149...> wrote: