当前在 Jupyter/iPython 中动态更新地块的正确方法是什么?
What is the currently correct way to dynamically update plots in Jupyter/iPython?
在 how to dynamically update a plot in a loop in ipython notebook (within one cell) 的答案中给出了一个示例,说明如何在 Python 循环中动态更新 Jupyter notebook 中的绘图。然而,这是通过在每次迭代中销毁和重新创建绘图来实现的,并且其中一个线程中的评论指出,可以通过使用新的 %matplotlib nbagg
魔法来改善这种情况,它提供了一个嵌入的交互式图形在笔记本中,而不是静态图像。
但是,据我所知,这个奇妙的新 nbagg
功能似乎完全没有记录,而且我找不到如何使用它动态更新绘图的示例。因此,我的问题是,如何使用 nbagg 后端有效地更新 Jupyter/Python 笔记本中的现有绘图? 由于在 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)
这是一个循环更新绘图的示例。它更新图中的数据,而不是每次都重新绘制整个图。它确实会阻止执行,但如果您对 运行 有限的模拟集感兴趣并将结果保存在某处,这对您来说可能不是问题。
%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)
I put this up on nbviewer here.
有一个IPython Widget version of nbagg
that is currently a work in progress at the Matplotlib repository。如果可用,那可能是使用 nbagg
.
的最佳方式
编辑:已更新以显示多个图
我正在使用 jupyter-lab,这对我有用(根据您的情况进行调整):
from IPython.display import clear_output
from matplotlib import pyplot as plt
import numpy as np
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)
确保绘图下方有几个单元格,否则每次重新绘制绘图时视图都会捕捉到位。
我改编了@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)
。
这是它的样子:
如果不想清除所有输出,可以使用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)
图的canvas.draw
方法动态更新图,对于当前图:
from matplotlib import pyplot as plt
plt.gcf().canvas.draw()
在 how to dynamically update a plot in a loop in ipython notebook (within one cell) 的答案中给出了一个示例,说明如何在 Python 循环中动态更新 Jupyter notebook 中的绘图。然而,这是通过在每次迭代中销毁和重新创建绘图来实现的,并且其中一个线程中的评论指出,可以通过使用新的 %matplotlib nbagg
魔法来改善这种情况,它提供了一个嵌入的交互式图形在笔记本中,而不是静态图像。
但是,据我所知,这个奇妙的新 nbagg
功能似乎完全没有记录,而且我找不到如何使用它动态更新绘图的示例。因此,我的问题是,如何使用 nbagg 后端有效地更新 Jupyter/Python 笔记本中的现有绘图? 由于在 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)
这是一个循环更新绘图的示例。它更新图中的数据,而不是每次都重新绘制整个图。它确实会阻止执行,但如果您对 运行 有限的模拟集感兴趣并将结果保存在某处,这对您来说可能不是问题。
%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)
I put this up on nbviewer here.
有一个IPython Widget version of nbagg
that is currently a work in progress at the Matplotlib repository。如果可用,那可能是使用 nbagg
.
编辑:已更新以显示多个图
我正在使用 jupyter-lab,这对我有用(根据您的情况进行调整):
from IPython.display import clear_output
from matplotlib import pyplot as plt
import numpy as np
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)
确保绘图下方有几个单元格,否则每次重新绘制绘图时视图都会捕捉到位。
我改编了@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)
。
这是它的样子:
如果不想清除所有输出,可以使用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)
图的canvas.draw
方法动态更新图,对于当前图:
from matplotlib import pyplot as plt
plt.gcf().canvas.draw()