web-dev-qa-db-ja.com

python matplotlibアニメーションで停止/開始/一時停止

基本的なアニメーションには、matplotlibのアニメーションモジュールでFuncAnimationを使用しています。この関数は、アニメーションを永続的にループします。マウスのクリックなどでアニメーションを一時停止および再開できる方法はありますか?

24
Jaco Vermaak

これが FuncAnimationの例 で、マウスクリックで一時停止するように変更しました。アニメーションはジェネレーター関数simDataによって駆動されるため、グローバル変数pauseがTrueの場合、同じデータを生成するとアニメーションが一時停止しているように見えます。

pausedの値は、イベントコールバックを設定することで切り替えられます。

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()
30
unutbu

これは機能します...

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

#pause
anim.event_source.stop()

#unpause
anim.event_source.start()
12
fred

ここで@fredと@unutbuの両方の回答を組み合わせると、アニメーションの作成後にonClick関数を追加できます。

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()

これで、クリックするだけでアニメーションを停止または開始できます。

11
woodenflute

私は同じ機能を実装しようとしてこのページにアクセスし、matplotlibsアニメーションを一時停止しました。他の答えは素晴らしいですが、それに加えて、矢印キーを使用して手動でフレームをループできるようにしたいと思いました。同じ機能を探している人のために、これが私の実装です:

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()

いくつかのメモ:

  • runningdirectionの値を変更できるように、それらをanimに割り当てました。非ローカル(Python2.7では使用できません)またはグローバル(別の関数内でこのコードを実行しているので望ましくありません)の使用を回避します。これが良い習慣であるかどうかはわかりませんが、私はそれがとてもエレガントだと思いました。
  • 手動更新では、FuncAnimationがプロットの更新に使用するanimのジェネレーターオブジェクトにアクセスしています。これにより、アニメーションを再開したときに、最初に一時停止した場所からではなく、アクティブなフレームから開始することが保証されます。
3
Peter9192