如何在Ipython笔记本中动态更新循环中的绘图(在一个单元格内)

如何在Ipython笔记本中动态更新循环中的绘图(在一个单元格内),python,pandas,matplotlib,jupyter-notebook,ipython,Python,Pandas,Matplotlib,Jupyter Notebook,Ipython,环境:Python 2.7、matplotlib 1.3、IPython笔记本电脑1.1、linux、chrome。代码位于单个输入单元中,使用--pylab=inline 我想使用IPython笔记本和pandas来消耗一个流,并每5秒动态更新一次绘图 当我只使用print语句以文本格式打印数据时,它工作得非常好:输出单元格只需不断打印数据并添加新行。但当我尝试绘制数据(然后在循环中更新数据)时,输出单元格中永远不会显示该绘图。但是如果我去掉这个循环,就画一次。它很好用 然后我做了一些简单的测

环境:Python 2.7、matplotlib 1.3、IPython笔记本电脑1.1、linux、chrome。代码位于单个输入单元中,使用
--pylab=inline

我想使用IPython笔记本和pandas来消耗一个流,并每5秒动态更新一次绘图

当我只使用print语句以文本格式打印数据时,它工作得非常好:输出单元格只需不断打印数据并添加新行。但当我尝试绘制数据(然后在循环中更新数据)时,输出单元格中永远不会显示该绘图。但是如果我去掉这个循环,就画一次。它很好用

然后我做了一些简单的测试:

i = pd.date_range('2013-1-1',periods=100,freq='s')
while True:
    plot(pd.Series(data=np.random.randn(100), index=i))
    #pd.Series(data=np.random.randn(100), index=i).plot() also tried this one
    time.sleep(5)
在我手动中断进程(ctrl+m+I)之前,输出不会显示任何内容。在我打断它之后,绘图正确地显示为多条重叠线。但我真正想要的是一个每5秒显示并更新一次的绘图(或者每当调用
plot()
函数时,就像我上面提到的print语句输出一样,效果很好)。我不希望在单元格完全完成后才显示最终图表


我甚至尝试在每个
plot()
等之后显式添加draw()函数。它们都不起作用。想知道如何通过IPython笔记本中一个单元格内的for/while循环动态更新绘图。

尝试在
plot()
函数后添加
show()
gcf().show()
。这些将强制更新当前地物(gcf()返回当前地物的参考)。

使用
IPython。显示
模块:

%matplotlib inline
import time
import pylab as pl
from IPython import display
for i in range(10):
    pl.plot(pl.randn(100))
    display.clear_output(wait=True)
    display.display(pl.gcf())
    time.sleep(1.0)

您可以通过将
wait=True
添加到
clear\u输出
来进一步改进此功能:

display.clear_output(wait=True)
display.display(pl.gcf())

以下是一些改进:

  • 清除输出之前调用
    display
    ,这样当单元格被中断时,您将得到一个绘图,而不是两个绘图
  • 捕捉
    键盘中断
    ,这样单元格输出就不会被回溯弄得乱七八糟

将标签添加到此处发布的其他解决方案将在每个循环中不断添加新标签。要解决此问题,请使用
clf

for t in range(100)
   if t % refresh_rate == 0:

     plt.clf()
     plt.plot(history['val_loss'], 'r-', lw=2, label='val')
     plt.plot(history['training_loss'], 'b-', lw=1, label='training')
     plt.legend()
     display.clear_output(wait=True)
     display.display(plt.gcf())


你可以这样做。它接受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\u plot(x,y)
。下面是它的外观:

我尝试了许多方法,但我发现这是添加clear_输出(wait=True)的最简单、最简单的方法,例如

from IPython.display import clear_output

for i in range(n_iterations):
     clear_output(wait=True)
     x = some value
     y = some value
     plt.plot(x, y, '-r')
     plt.show()

这会覆盖同一个情节,并产生情节动画的错觉

谢谢。gcf().show()也可以工作。需要添加HYRY建议的clear_output(),以在同一个figIs上显示内容。除了“display.display(pl.gcf())”?这是一个不平滑的选项,绘图是从头开始重新创建的,单元格在显示
clear_output(wait=True)之间上下移动。
解决了这个问题。请参阅下面wabu的答案。现在使用
%matplotlib nbagg
可以让您玩一个活生生的人物。@tcaswell我添加了一个新问题,询问如何使用
nbagg
来实现这一点。(打电话给你,以防你有兴趣回答。)这样做有效,但也会破坏单元格中的任何其他内容,如打印的度量值。有没有一种方法真的只是更新情节,并保持其他一切到位?+1。这是非常重要的。我认为HYRY的答案应该用这些信息更新。这很好,但也有清除打印输出的恼人的副作用。事实上,
display.display(gcf())
应该在
display.clear\u output(wait=True)
谢谢,@csta。添加了它。@herrlich10为什么要在
清除输出之前调用
显示
?你不应该先清除输出,然后显示新的数据,而不是以相反的方式进行吗?我仍然会在图形更新时看到屏幕闪烁,但并非总是如此。有解决方法吗?如果您也尝试在循环开始时打印文本,我发现这会导致图形消失,因此它仅在一瞬间可见。当
display()
调用放在
clear\u output()
之后时,我没有这个问题。谢谢
plt.clf()
工作。但是,有没有办法消除更新中的闪烁?
from IPython.display import clear_output

for i in range(n_iterations):
     clear_output(wait=True)
     x = some value
     y = some value
     plt.plot(x, y, '-r')
     plt.show()