在Jupyter / iPython中动态更新图的当前正确方法是什么?


93

在有关如何在ipython笔记本中(一个单元内)在循环中动态更新绘图的答案中,给出了一个示例,说明了如何在Python循环内在Jupyter笔记本中动态更新绘图。但是,这可以通过在每次迭代中销毁并重新创建绘图来实现,并且其中一个线程中的注释指出,可以使用新颖的%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)

Answers:


62

这是一个循环更新图的示例。它会更新图中的数据,并且不会每次都重新绘制整个图。它确实会阻止执行,但是,如果您有兴趣运行有限的一组模拟并将结果保存在某处,则对您来说可能不是问题。

%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 Widget版本nbagg,目前正在Matplotlib存储库中进行。如果可以的话,那可能是最好的使用方式nbagg

编辑:更新以显示多个图


1
太好了,似乎效果不错。对于我来说,它在运行时缺乏交互性不是一个大问题。一件有点奇怪的事情:如果while True:将for更改为for循环,则当循环结束时,我会得到最后一个绘图的两个静态图像,而不是交互式nbagg图像。知道为什么吗?
纳撒尼尔(Nathaniel)2015年

我将while更改为for循环,并在tmpnb.org上进行了尝试,但是我没有看到第二张图像或失去交互性。在黑暗中拍摄,但是您可以尝试在函数调用周围移动循环,而不是在函数中放入循环。对于f在范围(10)中:pltsin(ax)time.sleep(1)
气动

3
@pneumatics不幸的是,Retina显示屏上的Matplotlib 2.0存在一些问题:在循环图中,其绘制通常比通常绘制的小两倍。
亚历山大·罗丹

1
似乎该图没有时间正确调整其大小。因此,在放置aplt.show()并将for循环移动到下一个单元格时,我有了更好的体验。
ImportanceOfBeingErnest

2
请确保您与绘图所在的jupyter笔记本单元格中有%matplotlib笔记本-我今天花了2个多小时来进行故障排除,因为我在第一个包含导入语句的单元格中有%matplotlib笔记本
aguazul

12

我正在使用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)

确保在图下方有一些单元格,否则每次重新绘制图时视图都会固定在适当的位置。


1
这每次都会创建一个新图,而不是更新现有图
气动

2
正确。我还没有找到在jupyter-lab中进行动态绘图的更好方法。
Ziofil '18 -10-15

1
有没有办法设置两次迭代之间等待的时间?而不是仅仅拥有“ wait = True”
艾哈迈德·穆萨

1
每次重绘绘图时,图形都会闪烁。有没有办法解决这个问题?我在情节下有一些空白单元格,但这似乎无济于事。
MasayoMusic,

@MasayoMusic看到“闪烁和跳跃输出” buildmedia.readthedocs.org/media/pdf/ipywidgets/latest/...
LEO

0

我已经调整了@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)在循环内调用即可。外观如下: 在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.