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

环境: Python 2.7,Matplotlib1.3,IPython 笔记本1.1,Linux 和 Chrome。代码在一个单独的输入单元中,使用 --pylab=inline

我想使用 IPython 笔记本电脑和熊猫消费一个流和动态更新一个情节,每五秒钟。

当我只使用 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) ,输出才会显示任何内容。在我打断它之后,图像正确地显示为多条重叠的线条。但是我真正想要的是一个每五秒显示一次并更新一次的绘图(或者每当调用 plot()函数时,就像我上面提到的 print 语句输出一样,它工作得很好)。只有显示最后的图表后,细胞是完全做的是 没有我想要的。

我甚至尝试在每个 plot()之后显式地添加 draw ()函数,等等。都不管用。如何在 IPython 笔记本的一个单元中通过 为了/同时循环动态更新一个绘图?

105625 次浏览

Try to add show() or gcf().show() after the plot() function. These will force the current figure to update (gcf() returns a reference for the current figure).

Use the IPython.display module:

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

You can further improve this by adding wait=True to clear_output:

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

A couple of improvement's on HYRY's answer:

  • call display before clear_output so that you end up with one plot, rather than two, when the cell is interrupted.
  • catch the KeyboardInterrupt, so that the cell output isn't littered with the traceback.
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

Adding a label to the other solutions posted here will keep adding new labels in every loop. To deal with that, clear the plot using clf.

For example:

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

You can do it like this. It accepts x,y as list and output a scatter plot plus a linear trend on the same plot.

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();

You just need to call live_plot(x, y) inside a loop. Here's how it looks:

Enter image description here

I tried many methods, but I found this as the simplest and the easiest way -> to add clear_output(wait=True), for example,

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

This overwrites on the same plot, and gives an illusion of plot animation