web-dev-qa-db-ja.com

Python / Matplotlibで「成長する」ラインプロットをアニメーション化する

成長する線のプロットをアニメーション化するために使用できる一連のフレームを作成したいと考えています。以前は、plt.draw()とset_ydata()を使用して、時間の経過とともに変化するyデータを再描画していました。今回は、時間とともにグラフを横切る「伸びる」線を描きたいと思います。このため、set_ydataは機能しません(xdataが長さを変更しています)。例えば、

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure()
for n in range(len(x)):
    plt.plot(x[:n], y[:n], color='k')
    plt.axis([0, 10, 0, 1])
    plt.savefig('Frame%03d.png' %n)

これは機能しますが、スケーリングすると非常に遅くなります。これを行うより速い方法はありますか?

22
Blink

いくつかのメモ:

まず、物事が次第に遅くなるのは、同じ位置に線がどんどん重なっているためです。

簡単な修正は、毎回プロットをクリアすることです:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure()
for n in range(len(x)):
    plt.cla()
    plt.plot(x[:n], y[:n], color='k')
    plt.axis([0, 10, 0, 1])
    plt.savefig('Frame%03d.png' %n)

ただし、xデータとyデータの両方を同時に更新する方が良いでしょう。

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots()
line, = ax.plot(x, y, color='k')

for n in range(len(x)):
    line.set_data(x[:n], y[:n])
    ax.axis([0, 10, 0, 1])
    fig.canvas.draw()
    fig.savefig('Frame%03d.png' %n)

アニメーションモジュールを使用する場合(補足:blit=Trueは一部のバックエンド(OSXなど)では正しく機能しない可能性があるため、問題がある場合はblit=Falseを試してください):

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

x = np.linspace(0, 10, 100)
y = np.sin(x)

fig, ax = plt.subplots()
line, = ax.plot(x, y, color='k')

def update(num, x, y, line):
    line.set_data(x[:num], y[:num])
    line.axes.axis([0, 10, 0, 1])
    return line,

ani = animation.FuncAnimation(fig, update, len(x), fargs=[x, y, line],
                              interval=25, blit=True)
ani.save('test.gif')
plt.show()

enter image description here

35
Joe Kington