Javier
Javier

Reputation: 4623

Using Matplotlib animation inside event handler

I have an animation I would like to fire each time the user presses a specific key. I have data that represents an animated plot (so one different plot per frame) and an empty plot, so the idea is that when you press R (for example) the animated plot runs, and if you press R again it runs again. The following code works:

### Lots of code before

fig = plt.figure()
anim = animation.FuncAnimation(fig, animate, repeat=True)
plt.show()

where animate is a function I wrote. When I run this the Matplotlib window pops up and the animation runs over and over. This is fine, but I'd like the animation to fire on command, so I did this:

### Lots of code before

def press(event):
    if event.key == "r":
        print("r") # for debugging purposes
        anim = animation.FuncAnimation(fig, animate)

fig = plt.figure()
fig.canvas.mpl_connect("key_press_event", press)
plt.show()

The event registers as evidenced by the print, but nothing happens, just an empty plot window. Now, I read that this doesn't work because the animation object needs to stay alive after the function ends, so I added global anim to the event handler before I create the animation object, and now when I press R the program simply stops and the plot window closes.

The global approach works fine if the FuncAnimation call is inside some function, like this:

def f():
    global anim
    anim = animation.FuncAnimation(fig, animate)

f()

but not inside the event handler.

What should I do? How do I create an animation object inside the event handler and make it stay alive?

Update: apparently what causes the crash is having blit=True in the FuncAnimationcall (which I didn't include in my example since I thought it was irrelevant). Setting blit=False stops the crashing, but still nothing happens when I trigger the event.

Upvotes: 0

Views: 1829

Answers (2)

Javier
Javier

Reputation: 4623

This is not a complete answer but hopefully it may be of help to anyone with the same problem: inspired by @tacaswell's comment above I tried switching backends to TkAgg, and now it works. Maybe it's a bug with QT?

Upvotes: 0

tacaswell
tacaswell

Reputation: 87536

You have to keep a live refernce to the animation object or it (and it's timers) get garbage collected. See http://matplotlib.org/devdocs/api/animation_api.html#animation

It is odd that the global technique does not work in the event callback, but if that is the case, the best approach is probably to make a small helper class

class AnimManager:
    def __init__(self):
        self.anim = None

    def __call__(self, event):
        fig = make_a_figure_function()
        self.anim = animation.FuncAnimation(fig, animate)

am = AnimManager()
fig.canvas.mpl_connect("key_press_event", am) 

Upvotes: 1

Related Questions