Ipython: %matplotlib inline tidak bekerja dengan baik dengan ipywidgets 6.0 berinteraksi

Dibuat pada 3 Mar 2017  ·  46Komentar  ·  Sumber: ipython/ipython

Tampaknya di notebook jupyter, %matplotlib inline tidak berfungsi dengan baik dengan ipywidgets 6.0 @interact lagi. Sejauh yang saya tahu, backend sebaris menunggu hingga sel benar-benar selesai sebelum mengirim pesan display_data dengan gambar (lihat kait pasca-eksekusi yang terdaftar di https://github.com/ipython/ipython/blob/7cde22957303ab53df8bd464ad5d7ed616197f31/ IPython/core/pylabtools.py#L383). Di ipywidgets 6.0, kami telah mengubah cara kerja interaksi menjadi lebih spesifik tentang keluaran yang kami tangkap - kami menangkap pesan keluaran yang dikirim selama eksekusi fungsi, dan menampilkannya dalam keluaran interaktif. Namun, karena backend inline matplotlib mengirimkan gambarnya setelah fungsi dijalankan, kami hanya mendapatkan serangkaian besar gambar di area keluaran sel.

import matplotlib.pyplot as plt
from ipywidgets import interact

%matplotlib inline
x = [1,2,5,4,3]
@interact(n=(2,5))
def f(n):
    plt.plot(x[:n])

Masalah ini adalah tentang memulai diskusi untuk melihat apakah ada cara bagi kami untuk menemukan solusi yang baik yang bekerja dengan baik dengan backend inline (yang berguna) dan juga bekerja dengan baik dengan ipywidgets berinteraksi.

Misalnya, jika ada cara untuk memberi tahu backend sebaris untuk segera menghapus gambarnya dan tidak setelah sel selesai dieksekusi, itu mungkin sudah cukup. Kode ini berfungsi, misalnya ( tanpa backend inline diaktifkan)

import matplotlib.pyplot as plt
from ipywidgets import interact

x = [1,2,5,4,3]
@interact(n=(2,5))
def f(n):
    plt.plot(x[:n])
    plt.show()

CC @SylvainCorlay , @tacaswell.

Komentar yang paling membantu

Hai semua, saya belum mengikuti detail teknis ini, tetapi mengalami masalah. Terlepas dari detail implementasi, saya pikir sangat penting bahwa matplotlib+berinteraksi "berfungsi" sebanyak mungkin.

Semua 46 komentar

Ini sepertinya berhasil, tetapi apakah ada yang punya solusi untuk cara yang lebih baik?

import matplotlib.pyplot as plt
from ipywidgets import interact
from ipykernel.pylab.backend_inline import flush_figures

%matplotlib inline
x = [1,2,5,4,3]
@interact(n=(2,5))
def f(n):
    plt.plot(x[:n])
    flush_figures()

CC @minrk , yang mengerjakan backend mpl sebaris.

Saya rasa tidak banyak yang bisa kita lakukan.

Heuristik apa yang akan Anda gunakan untuk menampilkan gambar? Anda tidak dapat melakukannya sama sekali angka memperbarui karena banyak angka penggunaan kembali kode, tetapi itu umum untuk memiliki animasi.

Casing khusus @interact untuk menyiram setelah setiap operasi ?

Casing khusus @interact untuk menyiram setelah setiap operasi?

Poin bagus, terima kasih atas sarannya. Rasanya tidak terlalu bersih untuk melakukannya (untuk kasus khusus satu backend khusus untuk matplotlib). Mungkin saya akan menunggu untuk melihat apakah itu masalah besar bagi pengguna untuk secara eksplisit menyiram output seperti pada contoh di atas. Maksudku, eksplisit lebih baik daripada implisit dan semua itu...

Sunting: untuk meringkas, saya pikir saya setuju bahwa tidak banyak yang dapat (atau harus) kita lakukan ...

Ternyata ini semua jauh lebih mudah daripada yang saya kira - saya pasti telah melakukan sesuatu yang salah ketika saya mencoba menguji ini sebelumnya. Kita tidak perlu memanggil flush_figures, cukup memanggil plt.show standar saja:

import matplotlib.pyplot as plt
from ipywidgets import interact

%matplotlib inline
x = [1,2,5,4,3]
@interact(n=(2,5))
def f(n):
    plt.plot(x[:n])
    plt.show()

Saya pikir itu sangat masuk akal untuk meminta orang memasukkan perintah show() dalam interaksi mereka, jadi saya menutup ini.

Jika kita ingin mempertahankan perilaku ini (dan potensi keluaran pasca-eksekusi lainnya), mungkin kait pasca-X dapat dipanggil secara eksplisit dalam interaksi sebelum pengambilan keluaran selesai? Secara umum, harapan saya untuk memanggil fungsi melalui interaksi adalah bahwa ia berperilaku persis sama seperti jika saya memanggil fungsi sekali dalam sel.

Saya berharap orang akan terkejut dengan semua contoh interaksi-dengan-matplotlib untuk berhenti menampilkan angka, karena matplotlib 'interaktif' umumnya berarti plt.show tidak diperlukan. Menempatkannya dalam fungsi interaktif mungkin tidak akan mengubah itu.

Itu mengingatkan saya sedikit membutuhkan sys.stdout.flush() untuk melihat output, sebelum IOThread diperkenalkan. Masuk akal mengapa itu diperlukan ketika Anda memikirkan cara kerja, tetapi itu tidak membuatnya kurang mengejutkan karena tidak berperilaku seperti yang diharapkan orang.

Saya tidak berpikir kita harus mengeksekusi semua penangan pasca-eksekusi secara otomatis (siapa yang tahu apa yang akan mereka lakukan - mungkin banyak hal!). Bagaimana dengan memiliki pengait flush_display ? Kami akan menyiramnya sebelum memulai interaksi, dan menyiramnya lagi tepat sebelum mengakhirinya. Dengan cara itu persis analog dengan pembilasan stdout/stdin.

Yah, atau di sisi lain, mungkin masuk akal untuk memanggil post-execute, jika kita memikirkan interaksi yang benar-benar bertindak seperti sel tunggal. Tapi kemudian kita mungkin ingin memanggil post-execute sebelum interaksi dijalankan dan juga setelahnya, untuk berjaga-jaga jika interaksi berada dalam sel dengan hal-hal lain.

Dibuka kembali, karena percakapan belum ditutup...

Saya suka ide hook flush_display, dan itu akan bekerja secara teori, meskipun itu akan membutuhkan rilis ipython dan ipykernel dan ipywidgets yang terkoordinasi untuk mendefinisikan hook baru dan mengganti backend untuk menggunakannya.

jika kita memikirkan interaksi yang benar-benar bertindak seperti sel tunggal sendiri

Saya pikir ini adalah kunci mereka, dan ini adalah 'jika' yang besar. Begitulah cara saya memikirkannya, tetapi saya bukan semua orang (belum).

jika kita memikirkan interaksi yang benar-benar bertindak seperti sel tunggal sendiri
Saya pikir ini adalah kunci mereka, dan ini adalah 'jika' yang besar. Begitulah cara saya memikirkannya, tetapi saya belum (belum).

Hal yang membingungkan tentang ini adalah bahwa jika kita memiliki sel dengan kode, kemudian menjalankan interaksi, kemudian beberapa kode lagi, sel tersebut sebenarnya akan dieksekusi seperti tiga sel (yaitu, pasca-eksekusi dijalankan tiga kali berbeda). Saya pikir flush_display lebih masuk akal dalam kasus itu.

Pertanyaan tambahan: apakah output yang dicerminkan di JLab berfungsi?

@willingc widget bekerja dengan output cermin.

@SylvainCorlay Saya tahu mereka bekerja sekarang, dan orang-orang di Ann Arbor menyukainya. Pertanyaan saya adalah apakah akan berhasil jika perubahan dilakukan seperti yang dibahas di atas.

gotcha maaf untuk kebisingan.

Dalam jangka panjang, saya pikir pendekatan yang seharusnya bekerja lebih baik adalah backend widget ipympl ke matplotlib.

Namun, kita perlu membuat semua ini lebih mudah diinstal dengan conf.d dll...

Ya, output yang dicerminkan harus bekerja dengan perubahan yang dibahas di atas. Terima kasih telah memastikan!

Hal yang membingungkan tentang ini adalah bahwa jika kita memiliki sel dengan kode, kemudian menjalankan interaksi, kemudian beberapa kode lagi, sel tersebut sebenarnya akan dieksekusi seperti tiga sel (yaitu, pasca-eksekusi dijalankan tiga kali berbeda).

Memang, itu akan sedikit aneh. Bukankah itu akan menjadi dua kali? Satu untuk sel secara keseluruhan dan satu untuk permintaan interaksi pertama? Bergantung pada bagaimana Anda memikirkannya, ini juga masuk akal: dengan @interact , Anda memiliki dua eksekusi: satu untuk deklarasi, dan eksekusi lain untuk pemanggilan pertama dari fungsi yang berinteraksi.

Saya tidak berpikir Anda akan memiliki lebih dari satu jika Anda menggunakan @interact_manual , misalnya (saya tidak yakin).

Bukankah itu akan menjadi dua kali? Satu untuk sel secara keseluruhan dan satu untuk permintaan interaksi pertama?

Pertimbangkan kode ini:

plt.plot([1,2,3])
@interact(n=(1,10))
def f(n):
    plt.plot([1,n])
plt.plot([4,5,6])

Karena plotnya bersifat kumulatif, dan Anda ingin memperlakukan interaksi sebagai sel yang terpisah, Anda perlu menghapus gambar sebelum interaksi berjalan, lalu menyiram gambar di dalam interaksi, dan sekali lagi di akhir sel. Inilah yang kami lakukan dengan flushing stdout juga.

Sebenarnya, saya tidak yakin apa yang diharapkan pengguna dalam contoh di atas. Apa yang Anda harapkan?

Hanya sebuah pemikiran: contoh di atas sangat tidak logis; secara pribadi saya mengharapkan tiga plot di mana hanya satu yang berubah secara dinamis tetapi jika saya melakukan sesuatu seperti itu, saya akan melakukan semua panggilan plot di dalam @interact .

Apakah ada alasan untuk tidak memanggil flush_figures setelah setiap .plot() ?

@myyc itu adalah perubahan semantik yang signifikan dari perilaku. plot menambahkan item di plot....

Maksud saya dalam perilaku inline ipython spesifik, sebagai lawan dari matplotlib.

edit : Saya yakin ini adalah kasus penggunaan yang lebih umum untuk memiliki satu interaksi per sel dengan itu sebagai "satu-satunya fungsi plot", yang bertentangan dengan kasus yang dijelaskan di atas ...

Saya mengerti. Meskipun saya tidak berpikir bahwa ini harus memiliki perilaku yang sangat berbeda.

Pendekatan yang tepat di masa depan mungkin akan menggunakan backend notebook atau ipympl dan mengedit gambar.

Menerapkan solusi khusus matplotlib untuk backend sebaris dalam interaksi ipywidgets sepertinya tidak benar.

Dalam kode yang diberikan oleh jason:

plt.plot([1,2,3])
@interact(n=(1,10))
def f(n):
    plt.plot([1,n])
plt.plot([4,5,6])

output yang diharapkan adalah sosok dengan banyak garis..

Ya saya setuju sekali. Saya sementara memperbaikinya seperti itu (mengganti metode plot pandas) di pengaturan lokal saya, "menunggu perbaikan" :) Abaikan itu, itu memperkenalkan banyak efek samping yang mengerikan.

Saya telah melihat masalah ini terpental di sekitar berbagai proyek github, jadi saya bertanya-tanya apa jalur resolusi terbaik yang seharusnya.

sunting : mengapa tidak menulisnya seperti ini, jauh lebih eksplisit?

@interact(n=(1,10))
def f(n):
    plt.plot([1,2,3])
    plt.plot([1,n])
    plt.plot([4,5,6])

Anda dapat melihat paket ipympl (https://github.com/matplotlib/jupyter-matplotlib), yang merupakan widget matplotlib. ipympl masih tahap awal, tetapi harus memiliki jadwal rilis yang lebih cepat daripada inti matplotlib, dan dukungan sebelumnya untuk jupyterlab dll ...

OK ternyata override adalah ide yang buruk. Saya akan menantikan perbaikan di hulu :)

Hanya untuk menyumbangkan sudut pandang pengguna yang tidak berpendidikan: setelah memperbarui ke ipywidgets 6.0, saya menemukan bahwa banyak kode widget saya tidak berfungsi (karena masalah yang dibahas di sini). Saya dapat memperbaikinya dengan menambahkan panggilan ke plt.show() , tetapi saya juga menemukan bahwa saya harus sangat berhati-hati tentang di mana saya menambahkan panggilan tersebut; tampaknya terkadang memanggil ini terlalu cepat menyebabkan plot selanjutnya tidak muncul (bahkan jika plt.show() dipanggil lagi). Saya belum cukup memburu ini untuk membuat contoh minimal, tetapi perilaku saat ini tampaknya tidak intuitif bagi saya - saya memprogram dengan coba-coba untuk menyiasatinya.

Perubahan tepat apa dalam ipywidgets yang sebenarnya menyebabkan perilaku baru? Apakah kait pasca-eksekusi tidak dipanggil sama sekali, atau masih dipanggil tetapi keluarannya sekarang dibuang karena widget secara khusus tentang keluaran mana yang dimiliki oleh widget? Jika ini yang terakhir, maka sepertinya mengisolasi output yang ditangkap selama tubuh fungsi bukanlah hal yang benar untuk dilakukan.

Kait pasca-eksekusi sedang dipanggil (saya cukup yakin) - Anda dapat melihat ini dari melakukan:

import matplotlib.pyplot as plt
from ipywidgets import interact
%matplotlib inline

@interact(n=(0,10))
def f(n):
    plt.plot([0,n])

dan menggerakkan penggeser. Plot akan ditambahkan ke sel - kait eksekusi posting mengirim pesan data tampilan. Eksekusi interaksi memang khusus tentang hanya menangkap output yang terjadi selama pemanggilan fungsi. Saya pikir itu hal yang benar untuk dilakukan. Misalnya, dua interaksi berbeda mungkin berbagi instance slider yang sama persis:

import matplotlib.pyplot as plt
from ipywidgets import interact, IntSlider
%matplotlib inline

x = IntSlider()
@interact(n=x)
def f(n):
    plt.plot([0,n])
    plt.show()
@interact(n=x)
def f(n):
    plt.plot([0,n,0,n])
    plt.show()

Ketika penggeser tunggal di-tweak (di salah satu UI), kedua interaksi akan menunjukkan penggeser bergerak dan kedua fungsi yang berinteraksi akan berjalan dalam panggilan eksekusi yang sama. Akan salah jika kedua interaksi mencoba menangkap keluaran apa pun dari kait pasca-eksekusi. Saya pikir kekurangannya di sini adalah kita menggunakan post-execute untuk menghasilkan output, dan itu terlalu kasar. Kita harus memiliki metode yang lebih halus untuk membilas output yang dihasilkan dalam blok kode, yang dapat dipanggil beberapa kali dalam satu eksekusi.

Kita harus memiliki metode yang lebih halus untuk membilas output yang dihasilkan dalam blok kode

Untuk plot matplotlib, pembilasan ini terjadi saat melakukan plt.show

Saya harus sangat berhati-hati tentang di mana saya menambahkan panggilan seperti itu; tampaknya terkadang menyebut ini terlalu cepat menyebabkan plot selanjutnya tidak muncul

Saya sangat tertarik melihat contoh di mana ini terjadi. Kami ingin membuat perilaku intuitif dan dapat dimengerti.

Saya harus sangat berhati-hati tentang di mana saya menambahkan panggilan seperti itu; tampaknya terkadang menyebut ini terlalu cepat menyebabkan plot selanjutnya tidak muncul

Saya sangat tertarik melihat contoh di mana ini terjadi. Kami ingin membuat perilaku intuitif dan dapat dimengerti.

Untuk menguraikan, saya pikir Anda harus bisa mendapatkan yang setara dengan perilaku sebelumnya hanya dengan menambahkan plt.show() sebagai baris terakhir dari setiap fungsi interaksi yang melakukan plot. Saya sangat tertarik melihat contoh di mana ini tidak berhasil.

@jasongrout Terima kasih telah melihat ini. Kode tempat saya menekan ini agak rumit, dan mungkin saya melakukan kesalahan lain. Jika saya melihatnya lagi saya akan mencoba mengisolasinya dan memberikan contoh.

@jasongrout Setelah menggali lebih dalam, saya pikir apa yang saya temui adalah properti dari notebook Jupyter itu sendiri, bukan dari widget (tetapi berinteraksi dengan widget sekarang karena kami terpaksa memanggil plt.show() ).

Jika seseorang membuat plot di sel buku catatan dan memanggil plt.show() , maka modifikasi selanjutnya pada gambar tidak muncul. Berikut adalah contoh minimal:

%matplotlib inline
import matplotlib.pyplot as plt

def plotfun(t):
    fig, ax = plt.subplots(1,1)
    ax.plot([0,t],[0,t])
    plt.show()
    ax.plot([t,0],[0,t])
    plt.show()

plotfun(2)

Hanya plot baris pertama yang muncul.

Berikut adalah contoh yang lebih sederhana. Dua sel, tanpa backend %matplotlib inline . Mungkin @tacaswell bisa menjelaskan mengapa plt.show tidak menunjukkan plot.

import matplotlib.pyplot as plt
fig, ax = plt.subplots(1,1)
ax.plot([0,1],[0,1])
plt.show()

menunjukkan plot

ax.plot([1,0],[0,1])
plt.show()

tidak menunjukkan apa-apa

Dikonfirmasi di mesin saya dengan jupyter stabil terbaru, ipython, ipywidgets, matplotlib, python 3.

Dikonfirmasi di sini juga.

@jasongrout Itu adalah perilaku yang diharapkan karena di sel pertama Anda membuat gambar (dan kanvas dan sumbu) dan kemudian menampilkannya. Di sel kedua Anda kemudian menambahkan garis ke sumbu yang ada (pada gambar yang ada). Dengan %matplotlib qt atau ipympl (atau GUI lengkap mana pun) plot _harus_ diperbarui dengan baris kedua. Saya tidak berharap ini berfungsi dengan inline karena Anda hanya mendapatkan satu kesempatan untuk memperbaruinya (itulah sebabnya saya sangat bukan penggemar inline, itu membuang _semua_ fungsionalitas interaktif).

@tacaswell Apakah perilaku inline ini juga masuk akal untuk contoh sebelumnya yang saya berikan, yang semuanya dalam satu sel? Ini dia lagi:

%matplotlib inline
import matplotlib.pyplot as plt

def plotfun(t):
    fig, ax = plt.subplots(1,1)
    ax.plot([0,t],[0,t])
    plt.show()
    ax.plot([t,0],[0,t])
    plt.show()

plotfun(2)

Saya pikir pada plt.show backend sebaris merender dirinya sendiri ke png dan kemudian menghapus registrasi gambar dari pyplot sehingga tidak akan dirender lagi pada acara berikutnya, bahkan jika itu berada di sel yang sama, namun beberapa panggilan ke metode sumbu tanpa tambahan show s akan berfungsi.

Untuk memperjelas, berikut adalah kode backend sebaris: https://github.com/ipython/ipykernel/blob/master/ipykernel/pylab/backend_inline.py

Apakah ada versi ipywidgets dan/atau matplotlib dapat saya putar kembali agar widget interaktif saya berfungsi kembali?

@jasongrout Tampaknya dari kode seperti saya mungkin ingin mengatur InlineBackend.close_figures ke False . Tapi saya tidak yakin bagaimana mengatur atribut itu -- apakah saya perlu menggunakan semacam sihir?

(pertanyaan itu terdengar lucu tapi saya sungguh-sungguh)

https://github.com/jupyter-widgets/ipywidgets/issues/1457 mengangkat masalah ini lagi. @ellisonbg - bagaimana jika kita menerapkan solusi flush_figures yang saya sebutkan di atas - panggil flush_figures sebelum dan sesudah interaksi berjalan, untuk menghapus plot apa pun sebelum interaksi, dan menghapus apa pun yang diplot selama interaksi? Saya pikir kita mungkin harus memeriksa untuk melihat apakah kita berjalan di backend mpl inline.

Ini adalah kesalahan besar, tapi mungkin itu cukup penting untuk dilakukan. Mungkin kita juga dapat mendeteksi jika kita benar-benar mem-flush gambar dan mengeluarkan peringatan yang meminta orang untuk melakukan panggilan show() secara eksplisit?

Hai semua, saya belum mengikuti detail teknis ini, tetapi mengalami masalah. Terlepas dari detail implementasi, saya pikir sangat penting bahwa matplotlib+berinteraksi "berfungsi" sebanyak mungkin.

Dengan plt.show() atau flush_figures() , jika notebook di-refresh (tanpa me-restart kernel), angka tersebut hilang bahkan dengan Save Notebook with Widgets. Tanpa mitigasi ini, hal ini tidak terjadi meskipun kemudian masih ada masalah keluaran beberapa plot. Apakah ini dimaksudkan? Hal yang sama berlaku jika kernel dimatikan, sedangkan dengan versi ipywidgets yang lebih lama, status akhir gambar akan disimpan ke dalam notebook mirip dengan plot non-interaktif, yang cukup berguna.

Maaf jika ini di luar jangkauan, atau jika saya melakukan sesuatu yang salah. Menjalankan ipywidgets 6.0.0, matplotlib 2.0.2, notebook 5.0.0, dan python 3.6.1.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat