Як динамічно оновлювати графік у циклі в блокноті Ipython (в межах однієї комірки)


93

Середовище: Python 2.7, matplotlib 1.3, ноутбук IPython 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()функція викликається, як і те, що виводиться оператором друку, про який я згадав вище, що добре працює). Тільки показ остаточної діаграми після того, як клітинка буде повністю виконана - це НЕ те, що я хочу.

Я навіть намагався явно додати функцію draw () після кожної plot()тощо. Жодна з них не працює. Цікаво, як динамічно оновлювати графік за допомогою циклу for / while в одній комірці в блокноті IPython.

Відповіді:


122

використовувати 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

3
Додавання clear_output(wait=True)вирішує цю проблему. Дивіться відповідь wabu нижче.
ahwillia

3
У ці дні ви можете досягти кращих результатів, завдяки %matplotlib nbaggяким ви зможете пограти з живою фігурою.
tacaswell

@tcaswell Я додав нове запитання, в якому запитував, як хтось використовує nbaggдля досягнення цього. (Запитує вас на випадок, якщо вам цікаво відповісти на нього.) Stackoverflow.com/questions/34486642/…
Натаніель

3
це працює, але також знищує будь-що інше в клітині, як друковані мірки. Чи є спосіб насправді просто оновити сюжет і зберегти все інше на місці?
KIC

31

Ви можете ще більше вдосконалити це, додавши wait=Trueдо clear_output:

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

1
+1. Це дуже важливо. Я думаю, що відповідь HYRY слід доповнити цією інформацією.
ahwillia

5
Це добре, але має прикрий побічний ефект від очищення друкованих даних.
Пітер

31

Кілька покращень щодо відповіді HYRY :

  • дзвоніть displayранішеclear_output щоб у вас вийшов один сюжет, а не два, коли клітина перервана.
  • catch 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().show()після plot()функції. Вони змусять поточну цифру оновитись (gcf () повертає посилання на поточну цифру).


2
Дякую. gcf (). show () також працює. Потрібно додати clear_output (), запропоновану HYRY, щоб показувати речі на тому ж фігу
user3236895

Це окрім "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

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)всередині циклу. Ось як це виглядає: введіть тут опис зображення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.