Исправить легенду в анимации, созданной целлулоидом - PullRequest
0 голосов
/ 24 января 2020

Я хочу оживить процесс нахождения минимальной точки функции различными методами оптимизации градиентного спуска. Для этого я использую пакеты matplotlib и celluloid. Проблема в том, что невозможно зафиксировать легенду графика в анимации, и в каждом l oop новая легенда добавляется под предыдущей легендой, как вы можете видеть на рисунке ниже. Есть ли способ исправить легенду и избежать этой проблемы?

from celluloid import Camera
fig,ax = plt.subplots(1, 1,figsize=(10, 10))
camera = Camera(fig)
for i in range(path1.shape[1])
  ax.contour(x_mesh, y_mesh, z, levels=np.logspace(0, 5, 35), norm=LogNorm(), cmap=plt.cm.jet)
  ax.plot(*minima_, 'r*', markersize=18)

  line, = ax.plot([], [], 'k', label='Simple SGD', lw=2)
  point, = ax.plot([], [], 'ko')
  line.set_data(path1[::,:i])
  point.set_data(path1[::,i-1:i])

  line, = ax.plot([], [], 'r', label='SGD with momentum', lw=2)
  point, = ax.plot([], [], 'ro')
  line.set_data(*path2[::,:i])
  point.set_data(*path2[::,i-1:i])

  line, = ax.plot([], [], 'g', label='SGD with Nesterov', lw=2)
  point, = ax.plot([], [], 'go')
  line.set_data(*path3[::,:i])
  point.set_data(*path3[::,i-1:i])

  line, = ax.plot([], [], 'b', label='SGD with Adagrad', lw=2)
  point, = ax.plot([], [], 'bo')
  line.set_data(*path4[::,:i])
  point.set_data(*path4[::,i-1:i])

  line, = ax.plot([], [], 'c', label='SGD with Adadelta', lw=2)
  point, = ax.plot([], [], 'co')
  line.set_data(*path5[::,:i])
  point.set_data(*path5[::,i-1:i]) 

  line, = ax.plot([], [], 'm', label='SGD with RMSprob', lw=2)
  point, = ax.plot([], [], 'mo')
  line.set_data(*path6[::,:i])
  point.set_data(*path6[::,i-1:i])

  line, = ax.plot([], [], 'y', label='SGD with Adam', lw=2)
  point, = ax.plot([], [], 'yo')
  line.set_data(*path7[::,:i])
  point.set_data(*path7[::,i-1:i])

  line, = ax.plot([], [], 'y', label='SGD with Adamax', lw=2)
  point, = ax.plot([], [], 'y*')
  line.set_data(*path8[::,:i])
  point.set_data(*path8[::,i-1:i])

  line, = ax.plot([], [], 'k', label='SGD with Nadam', lw=2)
  point, = ax.plot([], [], 'kp')
  line.set_data(*path9[::,:i])
  point.set_data(*path9[::,i-1:i])

  line, = ax.plot([], [], 'r', label='SGD with AMSGrad', lw=2)
  point, = ax.plot([], [], 'rD')
  line.set_data(*path10[::,:i])
  point.set_data(*path10[::,i-1:i])

  ax.legend(loc='upper left') 
  camera.snap()
animation = camera.animate()
animation.save('2D_animation_overlap.gif', writer='imagemagick')

enter image description here

1 Ответ

0 голосов
/ 24 января 2020

Лучшей практикой здесь будет создание пользовательской легенды вместо автоматической генерации легенды, в этом случае это может быть сделано с помощью

import matplotlib.pyplot as plt
from matplotlib.lines import Line2D

labels = ['Single SGD', 'SGD with momentum', 'SGD with Nesterov', 
          'SGD with Adagrad', 'SGD with Adadelta', 'SGD with RMSprob', 'SGD with Adam', 
          'SGD with Adamax', 'SGD with Nadam', 'SGD with AMSgrad']
colors = ['k', 'r', 'g', 'b', 'c', 'm', 'y', 'y', 'k', 'r']
handles = []
for c, l in zip(colors, labels):
    handles.append(Line2D([0], [0], color = c, label = l))

plt.legend(handles = handles, loc = 'upper left')

, которая даст вам легенду, подобную этой:

enter image description here

Вам не нужно иметь ничего из этого в l oop, вы можете сделать это до или после, и это все еще будет работать. Это также будет работать в l oop, но перерисовывать легенду каждый раз не нужно.

Было бы также достаточно просто защитить создание легенды оператором if вместо создания легенды вручную. Т.е.

    # ...
    if i == 0:
        ax.legend(loc = 'upper left')

Но я бы не советовал практиковать генерацию легенды c в пользу автоматического создания легенды.

...