Анимация "растущего" сюжета в 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)

Пока это работает, он становится очень медленным, поскольку он масштабируется. Есть ли более быстрый способ сделать это?

Ответ 1

Несколько примечаний:

Во-первых, причина, по которой все становится медленнее, состоит в том, что вы все больше и больше накладываетесь на одну и ту же позицию.

Быстрое исправление заключается в том, чтобы очистить график каждый раз:

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