Cara memperbarui plot secara dinamis dalam satu lingkaran di notebook Ipython (dalam satu sel)


93

Lingkungan: Python 2.7, matplotlib 1.3, notebook IPython 1.1, linux, chrome. Kode berada dalam satu sel input tunggal, menggunakan--pylab=inline

Saya ingin menggunakan notebook dan panda IPython untuk menggunakan streaming dan secara dinamis memperbarui plot setiap 5 detik.

Ketika saya hanya menggunakan pernyataan cetak untuk mencetak data dalam format teks, itu berfungsi dengan baik: sel keluaran hanya terus mencetak data dan menambahkan baris baru. Tetapi ketika saya mencoba untuk memplot data (dan kemudian memperbaruinya dalam satu lingkaran), plot tersebut tidak pernah muncul di sel keluaran. Tetapi jika saya menghapus loop, cukup plot sekali. Ini bekerja dengan baik.

Kemudian saya melakukan beberapa tes sederhana:

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)

Output tidak akan menampilkan apa pun sampai saya menghentikan proses secara manual (ctrl + m + i). Dan setelah saya menghentikannya, plot ditampilkan dengan benar sebagai beberapa garis yang tumpang tindih. Tapi yang benar-benar saya inginkan adalah plot yang muncul dan diperbarui setiap 5 detik (atau setiap kali plot()fungsi dipanggil, seperti output pernyataan cetak yang saya sebutkan di atas, yang berfungsi dengan baik). Hanya menampilkan bagan akhir setelah sel selesai sepenuhnya BUKANLAH yang saya inginkan.

Saya bahkan mencoba untuk secara eksplisit menambahkan fungsi draw () setelah masing-masing plot(), dll. Tak satu pun dari mereka berfungsi. Bertanya-tanya bagaimana cara memperbarui plot secara dinamis dengan loop for / while dalam satu sel di notebook IPython.

Jawaban:


122

menggunakan IPython.displaymodul:

%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
ini bukan pilihan yang mulus, plot dibuat ulang dari awal dengan sel naik dan turun di antaranya
denfromufa

3
Menambahkan clear_output(wait=True)memecahkan masalah ini. Lihat jawaban wabu di bawah ini.
ahwillia

3
Anda dapat melakukan lebih baik hari ini %matplotlib nbaggyang memberi Anda sosok hidup untuk dimainkan.
tacaswell

@tcaswell Saya telah menambahkan pertanyaan baru yang menanyakan bagaimana seseorang menggunakan nbagguntuk mencapai ini. (Ping Anda jika Anda tertarik untuk menjawabnya.) Stackoverflow.com/questions/34486642/…
Nathaniel

3
ini berfungsi tetapi juga menghancurkan apa pun di dalam sel seperti ukuran yang dicetak. Apakah ada cara yang benar-benar hanya memperbarui plot dan menyimpan yang lainnya?
KIC

31

Anda dapat lebih meningkatkan ini dengan menambahkan wait=Trueke clear_output:

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

1
+1. Ini sangat penting. Saya pikir jawaban HYRY harus diperbarui dengan info ini.
ahwillia

5
Ini bagus, tetapi memiliki efek samping yang mengganggu karena menghapus hasil cetak juga.
Peter

31

Beberapa perbaikan pada jawaban HYRY :

  • panggil displaysebelumnya clear_outputsehingga Anda berakhir dengan satu plot, bukan dua, saat sel terputus.
  • tangkap KeyboardInterrupt, sehingga keluaran sel tidak dikotori oleh pelacakan balik.
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
Memang, display.display(gcf())harus pergi SEBELUM display.clear_output(wait=True)
herrlich10

Terima kasih, @csta. Menambahkannya.
Tom Phillips

@ herrlich10 Mengapa harus displaydipanggil sebelumnya clear_output? Bukankah Anda harus terlebih dahulu menghapus output dan kemudian menampilkan data baru, alih-alih melakukannya dengan cara lain?
Jakub Arnold

1
Saya masih mendapatkan layar berkedip dengan pembaruan grafik, namun tidak selalu. Apakah ada solusi untuk ini?
MasayoMusic

3

Menambahkan label ke solusi lain yang diposting di sini akan terus menambahkan label baru di setiap loop. Untuk mengatasinya, bersihkan plot menggunakanclf

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
Terima kasih plt.clf()bekerja. Namun apakah ada cara untuk menyingkirkan flicker dari pembaruan?
MasayoMusic

2

Coba tambahkan show()atau gcf().show()setelah plot()fungsi. Ini akan memaksa gambar saat ini untuk diperbarui (gcf () mengembalikan referensi untuk gambar saat ini).


2
Terima kasih. gcf (). show () juga berfungsi. Perlu menambahkan clear_output () yang disarankan oleh HYRY untuk menampilkan hal-hal pada gambar yang sama
pengguna3236895

Apakah ini selain "display.display (pl.gcf ())"?
MasayoMusic

0

Anda bisa melakukannya seperti ini. Ini 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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.