Apa cara yang benar saat ini untuk memperbarui plot secara dinamis di Jupyter / iPython?

93

Dalam jawaban tentang cara memperbarui plot secara dinamis dalam loop di notebook ipython (dalam satu sel) , contoh diberikan tentang cara memperbarui plot secara dinamis di dalam notebook Jupyter dalam loop Python. Namun, ini bekerja dengan menghancurkan dan membuat ulang plot pada setiap iterasi, dan komentar di salah satu utas mencatat bahwa situasi ini dapat diperbaiki dengan menggunakan %matplotlib nbaggsihir new-ish , yang menyediakan figur interaktif yang disematkan di notebook, bukan daripada gambar statis.

Namun, nbaggfitur baru yang luar biasa ini tampaknya sepenuhnya tidak terdokumentasi sejauh yang saya tahu, dan saya tidak dapat menemukan contoh bagaimana menggunakannya untuk memperbarui plot secara dinamis. Jadi pertanyaan saya adalah, bagaimana cara memperbarui plot yang ada secara efisien di notebook Jupyter / Python, menggunakan backend nbagg? Karena memperbarui plot secara dinamis di matplotlib adalah masalah yang rumit secara umum, contoh kerja sederhana akan sangat membantu. Sebuah penunjuk ke dokumentasi apapun tentang topik juga akan sangat membantu.

Untuk memperjelas apa yang saya minta: yang ingin saya lakukan adalah menjalankan beberapa kode simulasi untuk beberapa iterasi, lalu menggambar plot dari statusnya saat ini, lalu menjalankannya untuk beberapa iterasi lagi, lalu memperbarui plot untuk mencerminkan keadaan saat ini, dan seterusnya. Jadi idenya adalah menggambar plot dan kemudian, tanpa interaksi apa pun dari pengguna, memperbarui data dalam plot tanpa merusak dan membuat ulang semuanya.

Berikut adalah beberapa kode yang sedikit dimodifikasi dari jawaban untuk pertanyaan terkait di atas, yang mencapai ini dengan menggambar ulang seluruh gambar setiap saat. Saya ingin mencapai hasil yang sama, tetapi menggunakan lebih efisien 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)
Nathaniel
sumber

Jawaban:

62

Berikut adalah contoh yang memperbarui plot dalam satu lingkaran. Ini memperbarui data pada gambar dan tidak menggambar ulang seluruh gambar setiap saat. Itu memang memblokir eksekusi, meskipun jika Anda tertarik menjalankan serangkaian simulasi terbatas dan menyimpan hasilnya di suatu tempat, itu mungkin tidak menjadi masalah bagi Anda.

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

Saya memasang ini di nbviewer di sini.

Ada versi Widget IPython nbaggyang saat ini sedang dikerjakan di repositori Matplotlib . Jika itu tersedia, itu mungkin cara terbaik untuk menggunakannya nbagg.

EDIT: diperbarui untuk menampilkan banyak plot

pneumatik
sumber
1
Bagus, sepertinya itu bekerja dengan baik. Minimnya interaktivitas saat sedang berjalan bukanlah masalah besar bagi saya. Satu hal yang agak aneh: jika saya mengubah while True:ke loop for, ketika loop berakhir saya mendapatkan dua gambar statis dari plot terakhir, daripada gambar nbagg interaktif. Tahu mengapa demikian?
Nathaniel
Saya mengubah while menjadi for loop dan mencobanya di tmpnb.org, dan saya tidak melihat gambar kedua atau hilangnya interaktivitas. Dibidik dalam gelap, tetapi Anda bisa mencoba memindahkan loop di sekitar panggilan ke fungsi, daripada menggunakan loop di fungsi. untuk f dalam rentang (10): waktu pltsin (ax). tidur (1)
pneumatik
3
@pneumatics Sayangnya ada beberapa masalah dengan Matplotlib 2.0 pada tampilan Retina: dalam plot loop dua kali lebih kecil dari biasanya.
Alexander Rodin
1
Tampaknya sosok tersebut tidak diberi waktu untuk mengubah ukurannya dengan benar. Jadi saya memiliki pengalaman yang jauh lebih baik saat meletakkan plt.show()dan memindahkan loop-for ke sel berikutnya.
ImportanceOfBeingErnest
2
Pastikan Anda memiliki notebook% matplotlib di sel notebook jupyter yang sama dengan plot Anda - Saya menghabiskan lebih dari 2 jam hari ini untuk memecahkan masalah ini karena saya memiliki% notebook matplotlib di sel pertama dengan pernyataan impor
aguazul
12

Saya menggunakan jupyter-lab dan ini berfungsi untuk saya (sesuaikan dengan kasus Anda):

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

Kemudian dalam satu lingkaran Anda mengisi kamus dan Anda meneruskannya ke 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)

pastikan Anda memiliki beberapa sel di bawah plot, jika tidak, tampilan akan terkunci di tempatnya setiap kali plot digambar ulang.

Ziofil
sumber
1
ini membuat plot baru setiap kali daripada memperbarui plot yang ada
pneumatik
2
Benar. Saya belum menemukan cara yang lebih baik untuk memiliki plot dinamis di jupyter-lab.
Ziofil
1
Adakah cara untuk mengatur berapa lama menunggu di antara iterasi? daripada hanya memiliki 'menunggu = Benar'
Ahmad Moussa
1
Setiap kali plot digambar ulang, grafik berkedip. Adakah cara untuk menyelesaikan masalah ini? Saya memiliki beberapa sel kosong di bawah plot, tetapi itu tampaknya tidak membantu.
MasayoMusic
@MasayoMusic lihat "Keluaran berkedip
leo
0

Saya telah mengadaptasi jawaban @Ziofil dan memodifikasinya untuk menerima x, y sebagai daftar dan mengeluarkan plot pencar ditambah tren linier pada plot yang sama.

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

Anda hanya perlu menelepon live_plot(x, y)dalam satu lingkaran. begini tampilannya: masukkan deskripsi gambar di sini

Miguel Silva
sumber