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


92

环境:Python 2.7,matplotlib 1.3,IPython Notebook 1.1,Linux,Chrome。该代码位于一个输入单元格中,使用--pylab=inline

我想使用IPython笔记本和熊猫消耗流并每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 Notebook中的一个单元格中通过for / while循环动态更新绘图。

Answers:


118

使用IPython.display模块:

%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)

4
这不是一个平滑的选项,该图是从头开始重新创建的,单元格在其中之间上下波动
denfromufa 2014年

3
添加clear_output(wait=True)解决了这个问题。请参阅下面的wabu的答案。
亚历克斯·威廉姆斯

3
这些天,您可以做得更好,%matplotlib nbagg从而给您一个活泼的角色。
tacaswell

@tcaswell我添加了一个新问题,询问人们如何使用它nbagg来实现这一目标。(ping命令你如果你有兴趣在回答它。)stackoverflow.com/questions/34486642/...
纳撒尼尔

3
这行之有效,但也像打印的度量一样破坏单元格中的其他任何内容。是否真的有办法只是更新情节并保持其他所有内容不变?
KIC

30

您可以通过添加进一步提高这wait=Trueclear_output

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

1
+1。这个非常重要。我认为HYRY的答案应使用此信息进行更新。
Alex Williams

5
这很好,但也有清除打印输出的烦人的副作用。
彼得

30

HYRY的答案有几处改进:

  • 先调用displayclear_output以便在单元格中断时得到一个图,而不是两个图。
  • 捕捉KeyboardInterrupt,这样单元格的输出就不会出现回溯。
import matplotlib.pylab as plt
import pandas as pd
import numpy as np
import time
from IPython import display
%matplotlib inline

i = pd.date_range('2013-1-1',periods=100,freq='s')

while True:
    try:
        plt.plot(pd.Series(data=np.random.randn(100), index=i))
        display.display(plt.gcf())
        display.clear_output(wait=True)
        time.sleep(1)
    except KeyboardInterrupt:
        break

7
确实,display.display(gcf())应该在此之前 display.clear_output(wait=True)
herrlich10

谢谢,@ csta。添加了。
汤姆·菲利普斯

@ herrlich10为什么应display在之前调用clear_output?您不应该先清除输出然后显示新数据,而不是相反地做吗?
雅各布·阿诺德

1
图表更新仍使屏幕闪烁,但是并非一直如此。有没有解决方法?
MasayoMusic

2

尝试在该函数后添加show()或。这些将强制更新当前图形(gcf()返回当前图形的引用)。gcf().show()plot()


2
谢谢。gcf()。show()也可以。需要添加HYRY建议的clear_output()以在同一图上显示内容
user3236895 2014年

这是“ display.display(pl.gcf())”之外的吗?
MasayoMusic

2

在此处发布的其他解决方案中添加标签将继续在每个循环中添加新标签。为了解决这个问题,使用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())

4
谢谢plt.clf()作品。但是,是否有一些方法可以消除更新中的闪烁?
MasayoMusic '19

0

你可以这样 它接受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.