Каков в настоящее время правильный способ динамического обновления графиков в Jupyter/iPython?
В ответах на вопросы о том, как динамически обновлять график в цикле в записной книжке ipython (в пределах одной ячейки), приводится пример того, как динамически обновлять график внутри записной книжки Jupyter в цикле Python. Тем не менее, это работает путем уничтожения и воссоздания графика на каждой итерации, и комментарий в одном из потоков отмечает, что эту ситуацию можно улучшить с помощью new-ish %matplotlib nbagg
магия, которая обеспечивает интерактивную фигуру, встроенную в ноутбук, а не статичное изображение.
Тем не менее, этот замечательный новый nbagg
Насколько я могу судить, эта функция полностью недокументирована, и я не могу найти пример того, как использовать ее для динамического обновления графика. Таким образом, мой вопрос состоит в том, как эффективно обновить существующий график в блокноте Jupyter/Python, используя бэкэнд nbagg? Так как динамическое обновление графиков в matplotlib является сложной задачей в целом, простой рабочий пример был бы огромной помощью. Указатель на любую документацию по теме также был бы чрезвычайно полезен.
Чтобы было ясно, о чем я прошу: я хочу запустить код моделирования для нескольких итераций, затем нарисовать график его текущего состояния, затем запустить еще несколько итераций, а затем обновить график, чтобы отразить текущее состояние и тд. Таким образом, идея состоит в том, чтобы нарисовать график, а затем, без какого-либо взаимодействия с пользователем, обновить данные в графике, не разрушая и не создавая заново все это.
Вот некоторый слегка измененный код из ответа на связанный вопрос выше, который достигает этого, перерисовывая всю фигуру каждый раз. Я хочу добиться того же результата, но более эффективно используя nbagg
,
%matplotlib inline
import time
import pylab as pl
from IPython import display
for i in range(10):
pl.clf()
pl.plot(pl.randn(100))
display.display(pl.gcf())
display.clear_output(wait=True)
time.sleep(1.0)
5 ответов
Вот пример, который обновляет график в цикле. Он обновляет данные на рисунке и не перерисовывает всю фигуру каждый раз. Он блокирует выполнение, хотя, если вы заинтересованы в запуске конечного набора симуляций и сохранении результатов где-то, это может не быть проблемой для вас.
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import time
def pltsin(ax, colors=['b']):
x = np.linspace(0,1,100)
if ax.lines:
for line in ax.lines:
line.set_xdata(x)
y = np.random.random(size=(100,1))
line.set_ydata(y)
else:
for color in colors:
y = np.random.random(size=(100,1))
ax.plot(x, y, color)
fig.canvas.draw()
fig,ax = plt.subplots(1,1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
pltsin(ax, ['b', 'r'])
time.sleep(1)
Я разместил это на nbviewer здесь.
Существует версия виджета IPython nbagg
в настоящее время эта работа ведется в хранилище Matplotlib. Когда это будет доступно, это, вероятно, будет лучшим способом использования nbagg
,
РЕДАКТИРОВАТЬ: обновлено, чтобы показать несколько графиков
Я использую jupyter-lab, и это работает для меня (адаптируйте его к вашему случаю):
from IPython.display import clear_output
from matplotlib import pyplot as plt
import collections
%matplotlib inline
def live_plot(data_dict, figsize=(7,5), title=''):
clear_output(wait=True)
plt.figure(figsize=figsize)
for label,data in data_dict.items():
plt.plot(data, label=label)
plt.title(title)
plt.grid(True)
plt.xlabel('epoch')
plt.legend(loc='center left') # the plot evolves to the right
plt.show();
Затем в цикле вы заполняете словарь и передаете его live_plot()
:
data = collections.defaultdict(list)
for i in range(100):
data['foo'].append(np.random.random())
data['bar'].append(np.random.random())
data['baz'].append(np.random.random())
live_plot(data)
убедитесь, что у вас есть несколько ячеек под графиком, в противном случае представление фиксируется на месте каждый раз, когда график перерисовывается.
Если вы не хотите очищать все выходы, вы можете использовать
display_id=True
получить ручку и использовать
.update()
в теме:
import numpy as np
import matplotlib.pyplot as plt
import time
from IPython import display
def pltsin(ax, *,hdisplay, colors=['b']):
x = np.linspace(0,1,100)
if ax.lines:
for line in ax.lines:
line.set_xdata(x)
y = np.random.random(size=(100,1))
line.set_ydata(y)
else:
for color in colors:
y = np.random.random(size=(100,1))
ax.plot(x, y, color)
hdisplay.update(fig)
fig,ax = plt.subplots(1,1)
hdisplay = display.display("", display_id=True)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
pltsin(ax, colors=['b', 'r'], hdisplay=hdisplay)
time.sleep(1)
plt.close(fig)
(адаптировано из @pneumatics)
Я адаптировал ответ @Ziofil и изменил его, чтобы принимать x,y в качестве списка и выводить график рассеяния плюс линейный тренд на том же графике.
from IPython.display import clear_output
from matplotlib import pyplot as plt
%matplotlib inline
def live_plot(x, y, figsize=(7,5), title=''):
clear_output(wait=True)
plt.figure(figsize=figsize)
plt.xlim(0, training_steps)
plt.ylim(0, 100)
x= [float(i) for i in x]
y= [float(i) for i in y]
if len(x) > 1:
plt.scatter(x,y, label='axis y', color='k')
m, b = np.polyfit(x, y, 1)
plt.plot(x, [x * m for x in x] + b)
plt.title(title)
plt.grid(True)
plt.xlabel('axis x')
plt.ylabel('axis y')
plt.show();
тебе просто нужно позвонить live_plot(x, y)
внутри петли. вот как это выглядит:
https://i.st ack.imgur.com/68I8z.png
The
canvas.draw
метод фигуры динамически обновляет свои графики для текущей фигуры:
from matplotlib import pyplot as plt
plt.gcf().canvas.draw()