stop / start / pause dans l'animation matplotlib de python

J'utilise FuncAnimation dans le module d'animation de matplotlib pour une animation de base. Cette fonction boucle perpétuellement à travers l'animation. Y a-t-il un moyen de faire une pause et de redémarrer l'animation par, disons, des clics de souris?

17
demandé sur Jaco Vermaak 2013-05-24 14:01:43

4 réponses

Ici un exemple de fonctionnement que j'ai modifié pour faire une pause sur les clics de souris. Comme l'animation est pilotée par une fonction de générateur, simData, quand la variable globale pause est vrai, donner les mêmes données fait apparaître l'animation en pause.

La valeur paused est activée par la mise en place d'un rappel d'événement:

def onClick(event):
    global pause
    pause ^= True
fig.canvas.mpl_connect('button_press_event', onClick)

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation

pause = False
def simData():
    t_max = 10.0
    dt = 0.05
    x = 0.0
    t = 0.0
    while t < t_max:
        if not pause:
            x = np.sin(np.pi*t)
            t = t + dt
        yield x, t

def onClick(event):
    global pause
    pause ^= True

def simPoints(simData):
    x, t = simData[0], simData[1]
    time_text.set_text(time_template%(t))
    line.set_data(t, x)
    return line, time_text

fig = plt.figure()
ax = fig.add_subplot(111)
line, = ax.plot([], [], 'bo', ms=10)
ax.set_ylim(-1, 1)
ax.set_xlim(0, 10)

time_template = 'Time = %.1f s'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
fig.canvas.mpl_connect('button_press_event', onClick)
ani = animation.FuncAnimation(fig, simPoints, simData, blit=False, interval=10,
    repeat=True)
plt.show()
28
répondu unutbu 2016-12-06 13:01:27

en combinant les réponses de @fred et @unutbu ici, nous pouvons ajouter une fonction onClick après avoir créé l'animation:

import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig = plt.figure()

def run_animation():
    anim_running = True

    def onClick(event):
        nonlocal anim_running
        if anim_running:
            anim.event_source.stop()
            anim_running = False
        else:
            anim.event_source.start()
            anim_running = True

    def animFunc( ...args... ):
        # Animation update function here

    fig.canvas.mpl_connect('button_press_event', onClick)

    anim = animation.FuncAnimation(fig, animFunc[,...other args])

run_animation()

Maintenant, nous pouvons simplement arrêter ou démarrer l'animation avec des clics.

7
répondu woodenflute 2017-11-14 12:04:14

Cela fonctionne...

anim = animation.FuncAnimation(fig, animfunc[,..other args])

#pause
anim.event_source.stop()

#unpause
anim.event_source.start()
5
répondu fred 2016-09-13 02:29:06

j'ai atterri sur cette page en essayant d'implémenter la même fonctionnalité, en arrêtant l'animation matplotlibs. Les autres réponses sont excellentes, mais en plus je voulais être capable de faire une boucle manuelle à travers les cadres en utilisant les touches fléchées. Pour ceux qui recherchent la même fonctionnalité, voici mon oeuvre:

import matplotlib.pyplot as plt
import matplotlib.animation as ani

fig, ax = plt.subplots()
txt = fig.text(0.5,0.5,'0')

def update_time():
    t = 0
    t_max = 10
    while t<t_max:
        t += anim.direction
        yield t

def update_plot(t):
    txt.set_text('%s'%t)
    return txt

def on_press(event):
    if event.key.isspace():
        if anim.running:
            anim.event_source.stop()
        else:
            anim.event_source.start()
        anim.running ^= True
    elif event.key == 'left':
        anim.direction = -1
    elif event.key == 'right':
        anim.direction = +1

    # Manually update the plot
    if event.key in ['left','right']:
        t = anim.frame_seq.next()
        update_plot(t)
        plt.draw()

fig.canvas.mpl_connect('key_press_event', on_press)
anim = ani.FuncAnimation(fig, update_plot, frames=update_time,
                         interval=1000, repeat=True)
anim.running = True
anim.direction = +1
plt.show()

Quelques remarques:

  • pour pouvoir modifier les valeurs de running et direction, je les ai assignés à anim. Il évite d'utiliser non Local (pas disponible dans Python2.7) ou global (pas souhaitable puisque j'exécute ce code dans une autre fonction). Je ne sais pas si c'est une bonne pratique, mais je l'ai trouvée assez élégante.
  • pour la mise à jour manuelle, j'accède à anim's générateur objet que FuncAnimation utilise pour mettre à jour le tracé. Cela garantit que lorsque je reprends l'animation, elle commence à partir du cadre actif plutôt que de l'endroit où elle a été initialement interrompue.
1
répondu Peter9192 2018-03-20 10:58:37