Який на даний час правильний спосіб динамічного оновлення графіків у Jupyter / iPython?


93

У відповідях на те, як динамічно оновлювати графік у циклі в блокноті ipython (у межах однієї комірки) , наводиться приклад того, як динамічно оновлювати графік усередині блокнота Jupyter у циклі Python. Однак це працює, руйнуючи та відтворюючи сюжет на кожній ітерації, а коментар в одній з ниток зазначає, що цю ситуацію можна покращити, використовуючи %matplotlib nbaggмагію new-ish , яка забезпечує інтерактивну фігуру, вбудовану в блокнот, швидше ніж статичне зображення.

Однак ця чудова нова nbaggфункція, наскільки я можу судити, видається абсолютно недокументованою, і я не можу знайти приклад того, як використовувати її для динамічного оновлення сюжету. Таким чином, моє запитання полягає в тому, як ефективно оновити існуючий сюжет у блокноті Jupyter / Python, використовуючи серверну систему nbagg? Оскільки динамічне оновлення графіків у 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)

Відповіді:


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, nbaggяка наразі триває у сховищі Matplotlib . Коли це буде доступно, це, мабуть, буде найкращим способом використання nbagg.

РЕДАГУВАТИ: оновлено, щоб показати кілька графіків


1
Чудово, це, здається, добре працює. Відсутність інтерактивності під час роботи для мене не становить великої проблеми. Одна трохи дивна річ: якщо я while True:заміню цикл for на, коли цикл закінчується, я отримую два статичних зображення останнього сюжету, а не інтерактивний nbagg. Будь-яка ідея, чому це так?
Натаніель

Я змінив цикл for на цикл for і спробував це на tmpnb.org, але не бачу другого зображення або втрати інтерактивності. Постріл у темряві, але ви можете спробувати перемістити цикл навколо виклику до функції, а не мати цикл у функції. для f в діапазоні (10): час плцину (сокира). сон (1)
пневматика

3
@pneumatics На жаль, у нього є деякі проблеми з Matplotlib 2.0 на дисплеї Retina: в циклі ділянки вдвічі менші, ніж зазвичай.
Олександр Роден

1
Здається, фігурі не дано часу, щоб правильно змінити розмір. Тож я мав набагато кращий досвід, коли ставив plt.show()і переміщував цикл for до наступної комірки.
ImportanceOfBeingErnest

2
Переконайтеся, що у вас є блокнот% matplotlib у тій самій комірці блокнота jupyter, що і ваша ділянка - сьогодні я витратив більше 2 годин на усунення цього, оскільки у мене був% matplotlib блокнот у першій комірці зі
статусами

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.
Ziofil

1
Чи є спосіб встановити, скільки часу він очікує між ітераціями? а не просто "зачекати = Істинно"
Ахмад Мусса,

1
Щоразу, коли графік перемальовується, графік мерехтить. Чи є спосіб вирішити цю проблему? У мене є кілька порожніх клітинок під змовою, але це, здається, не допомагає.
MasayoMusic

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

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