Apakah ada cara untuk melepaskan plot matplotlib sehingga perhitungannya dapat dilanjutkan?

258

Setelah instruksi ini dalam interpreter Python satu mendapat jendela dengan plot:

from matplotlib.pyplot import *
plot([1,2,3])
show()
# other code

Sayangnya, saya tidak tahu bagaimana cara terus mengeksplorasi angka yang dibuat show()sementara program melakukan perhitungan lebih lanjut.

Apakah mungkin? Terkadang perhitungannya panjang dan akan membantu jika mereka akan melanjutkan selama pemeriksaan hasil antara.

meteore
sumber
5
Saya tidak dapat mengkonfirmasi, bahwa solusi yang dipilih dari nosklo pada 16:52 berfungsi. Bagi saya menggambar tidak membuka jendela untuk menampilkan plot, hanya acara pemblokiran di akhir yang menampilkan solusi. Namun, jawabannya sejak 17:00 benar. Mengaktifkan mode interaktif melalui ion()perbaikan masalah.
H. Brandsmeier
jika Anda seorang programmer tingkat lanjut, Anda dapat menggunakan os.fork()tetapi perlu diingat bahwa menggunakan os.fork()bisa rumit karena Anda membuat proses baru dengan menyalin proses lama.
Trevor Boyd Smith

Jawaban:

214

Gunakan matplotlibpanggilan yang tidak akan memblokir:

Menggunakan draw():

from matplotlib.pyplot import plot, draw, show
plot([1,2,3])
draw()
print 'continue computation'

# at the end call show to ensure window won't close.
show()

Menggunakan mode interaktif:

from matplotlib.pyplot import plot, ion, show
ion() # enables interactive mode
plot([1,2,3]) # result shows immediatelly (implicit draw())

print 'continue computation'

# at the end call show to ensure window won't close.
show()
nosklo
sumber
28
Dengan matplotlib 0.98.3 impor yang tepat adalah dari plot impor matplotlib.pyplot, draw, show
meteore
112
draw()tidak berfungsi untuk saya, tidak membuka jendela apa pun. Namun menggunakan show(block=False)bukannya draw()tampaknya melakukan trik di matplotlib 1.1.
rumpel
4
@nosklo, apakah Anda melihat? Anda membuatnya menjadi python tutorial
Jan
4
@noskolo bagaimana jika saya memiliki beberapa angka, bagaimana menggambar dan memperlihatkan Fig1 sambil melanjutkan latar belakang untuk melanjutkan? Saya ingin angka ini terbuka sampai gambar berikutnya dibuat, jadi pada akhirnya saya memiliki semua buah ara terbuka dan kode selesai. Dengan solusi Anda saat ini, itu membuat saya menunggu untuk menutup Fig1 dan kemudian kode berjalan. Terima kasih!!
physiker
9
draw()tidak bekerja untuk saya juga, hanya pause(0.001)melakukan: stackoverflow.com/questions/28269157/…
NumesSanguis
133

Gunakan kata kunci 'blok' untuk mengganti perilaku pemblokiran, mis

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

untuk melanjutkan kode Anda.

Jan
sumber
17
tetapi ini akan segera menutup jendela plot, tidak akan membuat plot tetap terbuka.
LWZ
8
Ya, itu benar jika Anda memanggil skrip Anda dari baris perintah. Jika Anda berada di shell Ipython, jendela tidak akan ditutup.
Jan
1
periksa jawaban @Nico untuk trik yang akan membiarkan jendela terbuka dalam kasus umum.
Jan
2
Bagi saya, ini tidak menutup jendela segera, hanya ketika skrip selesai (jadi Anda dapat secara manual memblokir di akhir skrip jika Anda ingin tetap terbuka).
luator
Ya, jendela yang tidak diblokir akan menutup saat skrip keluar . Anda dapat (a) mengizinkan pemblokiran pada plot terakhir Anda, atau (b) tidak keluar dari skrip (mungkin meminta input: "tekan <Enter> untuk keluar dari plot" atau sesuatu seperti itu).
Daniel Goldfarb
29

Lebih baik untuk selalu memeriksa dengan perpustakaan yang Anda gunakan jika mendukung penggunaan dengan cara yang tidak menghalangi .

Tetapi jika Anda menginginkan solusi yang lebih umum, atau jika tidak ada cara lain, Anda dapat menjalankan apa pun yang menghalangi dalam proses yang terpisah dengan menggunakan multprocessingmodul yang termasuk dalam python. Perhitungan akan berlanjut:

from multiprocessing import Process
from matplotlib.pyplot import plot, show

def plot_graph(*args):
    for data in args:
        plot(data)
    show()

p = Process(target=plot_graph, args=([1, 2, 3],))
p.start()

print 'yay'
print 'computation continues...'
print 'that rocks.'

print 'Now lets wait for the graph be closed to continue...:'
p.join()

Yang memiliki overhead meluncurkan proses baru, dan kadang-kadang sulit untuk debug pada skenario yang kompleks, jadi saya lebih memilih solusi lain (menggunakan matplotlib's panggilan API nonblocking )

nosklo
sumber
Terima kasih! Karena saya belum memiliki Python 2.6 di sistem saya, saya menggunakan threading. Baca sebagai pengganti Proses. Saya mengamati bahwa pernyataan cetak berikutnya menjadi lambat tak tertahankan (cetakan ketiga, saya mengeluarkan KeyboardInterrupt setelah 1 menit menunggu). Apakah ini efek menggunakan threading daripada multiprocessing?
meteore
@meteore: Ya, threading payah. Anda selalu bisa mendapatkan multiprosesor untuk python <2.6 dari sini: pyprocessing.berlios.de
nosklo
Ini sangat bagus. Apakah Anda punya ide mengapa pernyataan cetak tidak dieksekusi ketika dalam Emacs (mode python) sampai jendela plot ditutup?
meteore
Di Ubuntu 8.10 (Intrepid) paket (untuk python <2.6) disebut pemrosesan python dan Anda mengimpornya dengan 'import processing'
meteore
1
Bukankah Anda melewatkannya if __name__ == '__main__':?
Wernight
25

Mencoba

import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.show(block=False)
# other code
# [...]

# Put
plt.show()
# at the very end of your script to make sure Python doesn't bail out
# before you finished examining.

The show()dokumentasi mengatakan:

Dalam mode non-interaktif, tampilkan semua gambar dan blokir hingga angka ditutup; dalam mode interaktif tidak akan berpengaruh kecuali angka dibuat sebelum perubahan dari mode non-interaktif ke interaktif (tidak disarankan). Dalam hal ini menampilkan angka tetapi tidak menghalangi.

Argumen kata kunci eksperimental tunggal, blok, dapat disetel ke Benar atau Salah untuk menimpa perilaku pemblokiran yang dijelaskan di atas.

Nico Schlömer
sumber
mengapa tidak menggunakan draw (); [. kode lain]; tampilkan ()? Sejauh yang saya tahu blok = Salah telah ditinggalkan
Bogdan
Menurut Anda mengapa itu sudah usang? Saya melihatnya didokumentasikan di sini .
Nico Schlömer
11

PENTING : Hanya untuk memperjelas sesuatu. Saya berasumsi bahwa perintah berada di dalam .pyskrip dan skrip dipanggil menggunakan mis python script.pydari konsol.

Cara sederhana yang bekerja untuk saya adalah:

  1. Gunakan blok = False inside show: plt.show (block = False)
  2. Gunakan pertunjukan lain () di akhir skrip .py.

Contoh script.py file:

plt.imshow(*something*)                                                               
plt.colorbar()                                                                             
plt.xlabel("true ")                                                                   
plt.ylabel("predicted ")                                                              
plt.title(" the matrix")  

# Add block = False                                           
plt.show(block = False)

################################
# OTHER CALCULATIONS AND CODE HERE ! ! !
################################

# the next command is the last line of my script
plt.show()

seralouk
sumber
8

Dalam kasus saya, saya ingin memiliki beberapa jendela yang muncul saat mereka sedang dihitung. Untuk referensi, ini caranya:

from matplotlib.pyplot import draw, figure, show
f1, f2 = figure(), figure()
af1 = f1.add_subplot(111)
af2 = f2.add_subplot(111)
af1.plot([1,2,3])
af2.plot([6,5,4])
draw() 
print 'continuing computation'
show()

PS. Panduan yang cukup berguna untuk antarmuka OO matplotlib .

meteore
sumber
6

Yah, saya mengalami kesulitan besar mencari tahu perintah non-blocking ... Tapi akhirnya, saya berhasil mengolah kembali " Cookbook / Matplotlib / Animasi - Animating elemen plot yang dipilih " contoh, sehingga bekerja dengan thread ( dan mengirimkan data antara thread baik melalui variabel global, atau melalui multiprosesPipe ) di Python 2.6.5 di Ubuntu 10.04.

Skrip dapat ditemukan di sini: Animating_selected_plot_elements-thread.py - jika tidak ditempel di bawah ( dengan lebih sedikit komentar ) untuk referensi:

import sys
import gtk, gobject
import matplotlib
matplotlib.use('GTKAgg')
import pylab as p
import numpy as nx 
import time

import threading 



ax = p.subplot(111)
canvas = ax.figure.canvas

# for profiling
tstart = time.time()

# create the initial line
x = nx.arange(0,2*nx.pi,0.01)
line, = ax.plot(x, nx.sin(x), animated=True)

# save the clean slate background -- everything but the animated line
# is drawn and saved in the pixel buffer background
background = canvas.copy_from_bbox(ax.bbox)


# just a plain global var to pass data (from main, to plot update thread)
global mypass

# http://docs.python.org/library/multiprocessing.html#pipes-and-queues
from multiprocessing import Pipe
global pipe1main, pipe1upd
pipe1main, pipe1upd = Pipe()


# the kind of processing we might want to do in a main() function,
# will now be done in a "main thread" - so it can run in
# parallel with gobject.idle_add(update_line)
def threadMainTest():
    global mypass
    global runthread
    global pipe1main

    print "tt"

    interncount = 1

    while runthread: 
        mypass += 1
        if mypass > 100: # start "speeding up" animation, only after 100 counts have passed
            interncount *= 1.03
        pipe1main.send(interncount)
        time.sleep(0.01)
    return


# main plot / GUI update
def update_line(*args):
    global mypass
    global t0
    global runthread
    global pipe1upd

    if not runthread:
        return False 

    if pipe1upd.poll(): # check first if there is anything to receive
        myinterncount = pipe1upd.recv()

    update_line.cnt = mypass

    # restore the clean slate background
    canvas.restore_region(background)
    # update the data
    line.set_ydata(nx.sin(x+(update_line.cnt+myinterncount)/10.0))
    # just draw the animated artist
    ax.draw_artist(line)
    # just redraw the axes rectangle
    canvas.blit(ax.bbox)

    if update_line.cnt>=500:
        # print the timing info and quit
        print 'FPS:' , update_line.cnt/(time.time()-tstart)

        runthread=0
        t0.join(1)   
        print "exiting"
        sys.exit(0)

    return True



global runthread

update_line.cnt = 0
mypass = 0

runthread=1

gobject.idle_add(update_line)

global t0
t0 = threading.Thread(target=threadMainTest)
t0.start() 

# start the graphics update thread
p.show()

print "out" # will never print - show() blocks indefinitely! 

Semoga ini bisa membantu seseorang,
Ceria!

sdaau
sumber
5

Dalam banyak kasus, lebih mudah menyimpan gambar sebagai file .png pada hard drive. Inilah alasannya:

Keuntungan:

  • Anda dapat membukanya, melihatnya dan menutupnya kapan saja dalam proses. Ini sangat nyaman ketika aplikasi Anda berjalan untuk waktu yang lama.
  • Tidak ada yang muncul dan Anda tidak dipaksa untuk membuka jendela. Ini sangat nyaman ketika Anda berhadapan dengan banyak tokoh.
  • Gambar Anda dapat diakses untuk referensi di kemudian hari dan tidak hilang ketika menutup jendela gambar.

Kekurangan:

  • Satu-satunya hal yang dapat saya pikirkan adalah bahwa Anda harus pergi dan mencari folder dan membuka gambar sendiri.
elgehelge
sumber
Jika Anda mencoba menghasilkan banyak gambar, saya sepenuh hati setuju.
fantabolous
6
Draw back png's tidak interaktif: \
Invers
5

Jika Anda bekerja di konsol, yaitu IPythonAnda dapat menggunakan plt.show(block=False)sebagaimana ditunjukkan dalam jawaban lain. Tetapi jika Anda malas, Anda bisa mengetik:

plt.show(0)

Yang akan sama.

Anton Protopopov
sumber
5

Saya juga harus menambahkan plt.pause(0.001)kode saya agar benar-benar berfungsi di dalam for for loop (jika tidak, hanya akan menampilkan plot pertama dan terakhir):

import matplotlib.pyplot as plt

plt.scatter([0], [1])
plt.draw()
plt.show(block=False)

for i in range(10):
    plt.scatter([i], [i+1])
    plt.draw()
    plt.pause(0.001)
Martin Pecka
sumber
Ini berhasil bagi saya dengan matplotlib3 di macOS. Bagus!
Jerry Ma
4

Pada sistem saya show () tidak memblokir, meskipun saya ingin skrip menunggu pengguna untuk berinteraksi dengan grafik (dan mengumpulkan data menggunakan callback 'pick_event') sebelum melanjutkan.

Untuk memblokir eksekusi sampai jendela plot ditutup, saya menggunakan yang berikut:

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x,y)

# set processing to continue when window closed
def onclose(event):
    fig.canvas.stop_event_loop()
fig.canvas.mpl_connect('close_event', onclose)

fig.show() # this call does not block on my system
fig.canvas.start_event_loop_default() # block here until window closed

# continue with further processing, perhaps using result from callbacks

Namun, perhatikan bahwa canvas.start_event_loop_default () menghasilkan peringatan berikut:

C:\Python26\lib\site-packages\matplotlib\backend_bases.py:2051: DeprecationWarning: Using default event loop until function specific to this GUI is implemented
  warnings.warn(str,DeprecationWarning)

meskipun skripnya masih berjalan.

Andrew
sumber
Terima kasih! Spyder mengimpor -pylab saat startup yang umumnya bermanfaat, tetapi berarti show () tidak akan memblokir ketika ioff () - ini memungkinkan Anda untuk memperbaiki perilaku ini!
kalah
3

Saya juga ingin plot saya untuk menampilkan menjalankan sisa kode (dan kemudian terus menampilkan) bahkan jika ada kesalahan (kadang-kadang saya menggunakan plot untuk debugging). Saya membuat kode hack kecil ini sehingga setiap plot di dalam withpernyataan ini berperilaku seperti itu.

Ini mungkin agak terlalu non-standar dan tidak disarankan untuk kode produksi. Mungkin ada banyak "gotcha" tersembunyi dalam kode ini.

from contextlib import contextmanager

@contextmanager
def keep_plots_open(keep_show_open_on_exit=True, even_when_error=True):
    '''
    To continue excecuting code when plt.show() is called
    and keep the plot on displaying before this contex manager exits
    (even if an error caused the exit).
    '''
    import matplotlib.pyplot
    show_original = matplotlib.pyplot.show
    def show_replacement(*args, **kwargs):
        kwargs['block'] = False
        show_original(*args, **kwargs)
    matplotlib.pyplot.show = show_replacement

    pylab_exists = True
    try:
        import pylab
    except ImportError: 
        pylab_exists = False
    if pylab_exists:
        pylab.show = show_replacement

    try:
        yield
    except Exception, err:
        if keep_show_open_on_exit and even_when_error:
            print "*********************************************"
            print "Error early edition while waiting for show():" 
            print "*********************************************"
            import traceback
            print traceback.format_exc()
            show_original()
            print "*********************************************"
            raise
    finally:
        matplotlib.pyplot.show = show_original
        if pylab_exists:
            pylab.show = show_original
    if keep_show_open_on_exit:
        show_original()

# ***********************
# Running example
# ***********************
import pylab as pl
import time
if __name__ == '__main__':
    with keep_plots_open():
        pl.figure('a')
        pl.plot([1,2,3], [4,5,6])     
        pl.plot([3,2,1], [4,5,6])
        pl.show()

        pl.figure('b')
        pl.plot([1,2,3], [4,5,6])
        pl.show()

        time.sleep(1)
        print '...'
        time.sleep(1)
        print '...'
        time.sleep(1)
        print '...'
        this_will_surely_cause_an_error

Jika / ketika saya menerapkan "biarkan plot tetap terbuka (bahkan jika terjadi kesalahan) dan izinkan plot baru ditampilkan", saya ingin skrip keluar dengan benar jika tidak ada campur tangan pengguna yang memberi tahu sebaliknya (untuk tujuan eksekusi batch).

Saya dapat menggunakan sesuatu seperti pertanyaan time-out "End of script! \ NTekan p jika Anda ingin output ploting dijeda (Anda memiliki 5 detik):" dari /programming/26704840/corner -cases-for-my-wait-for-user-input-interupsi-implementasi .

Simon Streicher
sumber
2
plt.figure(1)
plt.imshow(your_first_image)

plt.figure(2)
plt.imshow(your_second_image)

plt.show(block=False) # That's important 

raw_input("Press ENTER to exist") # Useful when you run your Python script from the terminal and you want to hold the running to see your figures until you press Enter
Thanhtang
sumber
16
Bagaimana satu tekan enter sebelum ada?
grovina
2

OP bertanya tentang mengirim matplotlibplot. Sebagian besar jawaban menganggap eksekusi perintah dari dalam interpreter python. Use-case yang disajikan di sini adalah preferensi saya untuk menguji kode di terminal (misalnya bash) di mana a file.pydijalankan dan Anda ingin plot (s) muncul tetapi skrip python untuk menyelesaikan dan kembali ke prompt perintah.

File yang berdiri sendiri ini digunakan multiprocessinguntuk meluncurkan proses terpisah untuk memplot data matplotlib. Utas utama keluar menggunakan yang os._exit(1)disebutkan dalam posting ini . The os._exit()kekuatan utama untuk keluar tapi daun matplotlibproses anak hidup dan responsif sampai jendela plot ditutup. Ini adalah proses yang terpisah sepenuhnya.

Pendekatan ini sedikit mirip dengan sesi pengembangan Matlab dengan jendela angka yang muncul dengan prompt perintah responsif. Dengan pendekatan ini, Anda telah kehilangan semua kontak dengan proses jendela angka, tetapi, itu tidak masalah untuk pengembangan dan debugging. Tutup saja jendela dan terus pengujian.

multiprocessingdirancang untuk eksekusi kode hanya python yang membuatnya mungkin lebih cocok daripada subprocess. multiprocessingadalah cross-platform sehingga ini harus bekerja dengan baik di Windows atau Mac dengan sedikit atau tanpa penyesuaian. Tidak perlu memeriksa sistem operasi yang mendasarinya. Ini diuji di linux, Ubuntu 18.04LTS.

#!/usr/bin/python3

import time
import multiprocessing
import os

def plot_graph(data):
    from matplotlib.pyplot import plot, draw, show
    print("entered plot_graph()")
    plot(data)
    show() # this will block and remain a viable process as long as the figure window is open
    print("exiting plot_graph() process")

if __name__ == "__main__":
    print("starting __main__")
    multiprocessing.Process(target=plot_graph, args=([1, 2, 3],)).start()
    time.sleep(5)
    print("exiting main")
    os._exit(0) # this exits immediately with no cleanup or buffer flushing

Menjalankan file.pymenampilkan jendela gambar, lalu __main__keluar tetapi jendela multiprocessing+ matplotlibgambar tetap responsif dengan zoom, pan, dan tombol lainnya karena ini adalah proses yang independen.

Periksa proses di bash command prompt dengan:

ps ax|grep -v grep |grep file.py

Marc Compere
sumber
Saya mencoba menggunakan solusi Anda tetapi sepertinya tidak berhasil untuk saya dan saya mencoba mencari tahu mengapa. Saya tidak menjalankan kode melalui terminal tetapi dari Pycharm IDE jika itu membuat perbedaan, meskipun seharusnya tidak.
ttsesm
1
ok, yang akhirnya berhasil untuk saya adalah mengatur proses anak dengan .daemon=Falseseperti yang dijelaskan di sini stackoverflow.com/a/49607287/1476932 Namun, sys.exit()tidak menghentikan proses induk seperti yang dijelaskan di sana sampai saya menutup jendela anak. Di sisi lain menggunakan os._exit(0)dari contoh di atas berhasil.
ttsesm
1

Menurut pendapat saya, jawaban di utas ini menyediakan metode yang tidak berfungsi untuk setiap sistem dan dalam situasi yang lebih kompleks seperti animasi. Saya menyarankan untuk melihat jawaban MiKTeX di utas berikut, di mana metode yang kuat telah ditemukan: Bagaimana cara menunggu sampai animasi matplotlib berakhir?

MikeTeX
sumber
0

Jika Anda ingin membuka beberapa angka, sambil tetap membuka semuanya, kode ini berfungsi untuk saya:

show(block=False)
draw()
DomDev
sumber
show (block = False) telah ditinggalkan dan sekarang tidak berfungsi lagi
Bogdan
0

Meskipun tidak secara langsung menjawab permintaan OP, saya memposting solusi ini karena dapat membantu seseorang dalam situasi ini:

  • Saya membuat .exe dengan pyinstaller karena saya tidak bisa menginstal python di mana saya perlu membuat plot, jadi saya perlu skrip python untuk menghasilkan plot, simpan sebagai .png, tutup dan lanjutkan dengan yang berikutnya, diimplementasikan sebagai beberapa plot di loop atau menggunakan fungsi.

untuk Im ini menggunakan:

import matplotlib.pyplot as plt
#code generating the plot in a loop or function
#saving the plot
plt.savefig(var+'_plot.png',bbox_inches='tight', dpi=250) 
#you can allways reopen the plot using
os.system(var+'_plot.png') # unfortunately .png allows no interaction.
#the following avoids plot blocking the execution while in non-interactive mode
plt.show(block=False) 
#and the following closes the plot while next iteration will generate new instance.
plt.close() 

Di mana "var" mengidentifikasi plot di loop sehingga tidak akan ditimpa.

patowski1981
sumber
-1

Gunakan plt.show(block=False), dan di akhir panggilan skrip Anda plt.show().

Ini akan memastikan bahwa jendela tidak akan ditutup ketika skrip selesai.

Ken Mueller
sumber
Lihat jawaban @ nico-schlömer
Josh Wolff