Python Matplotlib: динамически обновлять график — длина массива заранее неизвестна

Мне известны эти вопросы: (A), (B) и (C) - все они частично решают мою проблему.
Я также прочитали Поваренную книгу анимации
Однако мои вопросы, похоже, не рассмотрено в любом из вышеперечисленных.
Я хочу построить целевые функции, возвращаемые оптимизатором, во время работы оптимизатора. Я не знаю заранее, сколько итераций выполнит оптимизатор. Независимо от того, как я получаю массив, содержащий целевые функции, проблема может быть изолирована в этом минимальном примере:

import numpy as np  
import matplotlib.pyplot as plt  

SIZE = 50  
R1 = 0.5
R2 = 0.75

plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
fig.canvas.set_window_title('broken spiral')

for i in range(0, SIZE):
  A.append(R1 * i * np.sin(i))
  B.append(R2 * i * np.cos(i))
  line1, = ax.plot(A,'-k',label='black')
  line2, = ax.plot(B,'-r',label='red')
  legend = ax.legend(loc=0)
  plt.draw()

plt.savefig('test_broken_spiral.png')

Здесь сюжет только «псевдо» обновлен. Что действительно происходит, так это то, что для каждой итерации создается новая строка для A и B, перекрывающая исходную, но также генерирующая новую запись легенды. После 50 итераций у меня есть 100 строк и 100 записей легенды.
Я попробовал следующее:

for i in range(0, SIZE):
  A.append(R1 * i * np.sin(i))
  B.append(R2 * i * np.cos(i))
  if i == 0: 
    line1, = ax.plot(A,'-k',label='black')
    line2, = ax.plot(B,'-r',label='red')
    legend = ax.legend(loc=0)
    plt.draw()
  else:
    line1.set_ydata(A)
    line2.set_ydata(B)
    plt.draw()

plt.savefig('test_broken_spiral.png')

К сожалению, на этом графике полностью перепутана ось.
Я вставил оператор if i == 0, потому что заранее не знаю количество итераций (да, знаю в этом случае, но не в приложении, для которого это предназначено) и каким-то образом нужно «инициализировать» сюжет и легенду.
Мои вопросы можно резюмировать следующим образом:
1.) Как мне обновить свой сюжет? Если я запускаю оптимизатор на 10 000 итераций, мне не нужны 10 000 перекрывающихся линий на моем графике (размер файла).
2.) Где разместить команду legend?

Я использую python 2.6.6 и matplotlib 0.99.1.1.

Изменить:
Это похоже на аналогичный вопрос , с той же проблемой без ответа.


person Schorsch    schedule 10.04.2013    source источник


Ответы (1)


Просто создайте объекты линии с пустыми данными вне вашего цикла:

line1, = ax.plot([], [],'-k',label='black')
line2, = ax.plot([], [],'-r',label='red')
ax.legend()
for i in range(0, SIZE):
  A.append(R1 * i * np.sin(i))
  B.append(R2 * i * np.cos(i))
  line1.set_ydata(A)
  line1.set_xdata(range(len(A)))
  line2.set_ydata(B)
  line2.set_xdata(range(len(B)))
  ax.relim()
  ax.autoscale_view()
  plt.draw() 

Возможно, вы могли бы быть немного умнее, обновляя файл xdata.

Более полный пример см. здесь и полную галерею примеры анимации.

person tacaswell    schedule 10.04.2013