Hesaplamanın devam edebilmesi için matplotlib grafiklerini ayırmanın bir yolu var mı?


258

Python yorumlayıcısındaki bu talimatlardan sonra, bir komplo içeren bir pencere açılır:

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

Ne yazık ki, show()program daha fazla hesaplama yaparken yaratılan figürü etkileşimli olarak nasıl araştırmaya devam edeceğimi bilmiyorum .

Bütün bunlar mümkün mü? Bazen hesaplamalar uzundur ve ara sonuçların incelenmesi sırasında devam edip etmeyecekleri yararlı olabilir.


5
16:52 tarihinde nosklo'dan seçilen çözümün çalıştığını doğrulayamıyorum. Benim için çizim, çizimi görüntülemek için bir pencere açmaz, sadece sondaki engelleme şovu çözümü görüntüler. Ancak, saat 17: 00'den gelen yanıtı doğrudur. Etkileşimli modun üzerinden açılması ion()sorunu çözer.
H. Brandsmeier

gelişmiş bir programcıysanız kullanabilirsiniz, os.fork()ancak os.fork()eski işlemi kopyalayarak yeni bir işlem oluşturduğunuz için kullanımın zor olabileceğini unutmayın .
Trevor Boyd Smith

Yanıtlar:


214

matplotlibEngellenmeyen çağrıları kullanın :

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

Etkileşimli modu kullanma:

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

28
Matplotlib 0.98.3 ile doğru ithalat matplotlib.pyplot ithalat arsa, beraberlik, gösteri
meteore

112
draw()benim için çalışmıyor, herhangi bir pencere açmıyor. Ancak show(block=False)yerine draw()matplotlib 1.1 hile yapmak gibi görünüyor.
rumpel

4
@nosklo, gördün mü? Bir piton haline getirdiler öğretici
Jan

4
@noskolo birkaç figürüm varsa, Fig1'i nasıl çizebilir ve gösterebilirim? Bir sonraki incir üretilene kadar bu rakamın açık olmasını istiyorum, sonunda sonunda tüm incirleri açtım ve kod bitti. Mevcut çözümünüzle, Fig1'i kapatmamı bekliyorum ve kod devam ediyor. Teşekkürler!!
Physiker

9
draw()benim için de işe yaramadı, sadece pause(0.001)yaptı: stackoverflow.com/questions/28269157/…
NumesSanguis

133

Engelleme davranışını geçersiz kılmak için 'blok' anahtar kelimesini kullanın, ör.

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

kodunuza devam etmek için.


17
ancak bu, çizim penceresini hemen kapatacak, çizimi açık tutmayacaktır.
LWZ

8
Evet, komut dosyanızı komut satırından çağırırsanız bu doğrudur. Ipython kabuğundaysanız, pencere kapatılmaz.
Ocak

1
Genel durumda pencereyi açık bırakacak bir numara için @Nico'nun cevabını kontrol edin.
Ocak

2
Benim için, bu sadece komut dosyası tamamlandığında pencereyi hemen kapatmaz (böylece açık kalmasını istiyorsanız komut dosyasının sonunda manuel olarak engelleyebilirsiniz).
luator

Evet, komut dosyası kapatıldığında engellenmeyen pencereler kapanır . (A) son arsa üzerinde engellemeye izin verebilir veya (b) komut dosyasından çıkamazsınız (belki de girdi isteyebilirsiniz: "arsadan çıkmak için <Enter> tuşuna basın" veya bunun gibi bir şey).
Daniel Goldfarb

29

Kullanmayı engellemeyen bir şekilde destekleyip desteklemediğini her zaman kullandığınız kitaplıkla kontrol etmek daha iyidir .

Ancak daha genel bir çözüm istiyorsanız veya başka bir yol yoksa, multprocessingpython'da bulunan modülü kullanarak ayrı bir işlemde engellenen her şeyi çalıştırabilirsiniz . Hesaplama devam edecek:

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

Bu, yeni bir işlem başlatma yüküne sahiptir ve bazen karmaşık senaryolarda hata ayıklamak daha zordur, bu yüzden diğer çözümü tercih ederim ( matplotlib'ın engellemeyen API çağrılarını kullanarak )


Teşekkürler! Henüz sistemimde Python 2.6 olmadığından, iş parçacığı olarak iş parçacığı olarak iş parçacığı kullandım. Sonraki baskı deyimlerinin dayanılmaz derecede yavaşladığını gözlemledim (üçüncü baskı, 1 dakika bekledikten sonra KeyboardInterrupt verdim). Bu, çoklu işlem yerine iplik kullanmanın bir etkisi midir?
meteor

@meteore: Evet, iş parçacığı berbat. Python <2.6 için her zaman buradan çok işlem yapabilirsiniz: pyprocessing.berlios.de
nosklo

Bu kesinlikle mükemmel. Emacs'da (python modu) çizim penceresi kapanana kadar print ifadelerinin neden yürütülmediğine dair bir fikriniz var mı?
meteor

Ubuntu 8.10'da (Intrepid) paket (python <2.6 için) python-işleme olarak adlandırılır ve 'içe aktarma işlemi' ile içe aktarırsınız
meteore

1
Kaçırmadın mı if __name__ == '__main__':?
Wernight

25

Deneyin

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.

show()Dokümantasyon diyor ki:

Etkileşimli olmayan modda, tüm rakamları görüntüleyin ve rakamlar kapanana kadar engelleyin; etkileşimli modda, etkileşimli olmayan moddan etkileşimli moda geçmeden önce rakamlar oluşturulmadıkça etkisi yoktur (önerilmez). Bu durumda rakamları görüntüler ancak engellemez.

Yukarıda açıklanan engelleme davranışını geçersiz kılmak için tek bir deneysel anahtar kelime bağımsız değişkeni olan blok Doğru veya Yanlış olarak ayarlanabilir.


neden draw () kullanmıyorsunuz; [. diğer kod]; göstermek() ? Bildiğim kadarıyla block = False kullanımdan kaldırıldı
Bogdan

Sizce neden kullanımdan kaldırıldı? Burada belgelendiğini görüyorum .
Nico Schlömer

11

ÖNEMLİ : Sadece bir şeyi netleştirmek için. Komutların bir .pykomut dosyasının içinde olduğunu ve komut dosyasının örneğin python script.pykonsoldan kullanılarak çağrıldığını varsayıyorum .

Benim için çalışan basit bir yol:

  1. Block = False inside show'u kullanın: plt.show (block = False)
  2. .Py komut dosyasının sonunda başka bir show () kullanın .

script.pyDosya örneği :

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



8

Benim durumumda, hesaplanırken birkaç pencerenin açılmasını istedim. Referans için, bu yol:

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. Matplotlib'in OO arayüzü için oldukça kullanışlı bir rehber .


6

Peki, engellemeyen komutları bulmakta büyük bir sorun yaşadım ... Ama son olarak, " Yemek Kitabı / Matplotlib / Animasyonlar - Seçili çizim öğelerini canlandırma " örneğini yeniden çalışmayı başardım , bu yüzden iş parçacıklarıyla çalışır ( ve iş parçacıkları arasında veri Pipeiletir) global değişkenler aracılığıyla veya çok işlemli ) Ubuntu 10.04'te Python 2.6.5 üzerinde.

Komut dosyası burada bulunabilir: Animating_selected_plot_elements-thread.py - aksi takdirde referans için aşağıda yapıştırılmış ( daha az yorum ile ):

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! 

Umarım bu birine yardımcı olur,
Şerefe!


5

Çoğu durumda , görüntüyü sabit sürücüye .png dosyası olarak kaydetmek daha uygundur . İşte nedeni:

Avantajları:

  • İşlem sırasında istediğiniz zaman açabilir, inceleyebilir ve kapatabilirsiniz. Bu, özellikle uygulamanız uzun süre çalıştığında kullanışlıdır.
  • Hiçbir şey açılmaz ve pencereleri açmak zorunda kalmazsınız. Bu, özellikle birçok figürle uğraşırken kullanışlıdır.
  • Resminize daha sonra başvurmak üzere erişilebilir ve şekil penceresi kapatılırken kaybolmaz.

dezavantajı:

  • Düşünebileceğim tek şey, klasörü bulup görüntüyü kendiniz açmanız gerekecek.

Çok fazla görüntü oluşturmaya çalışıyorsanız, yürekten katılıyorum.
fantastik

6
Png geri çekin etkileşimli değildir: \
Ters

5

Konsolda çalışıyorsanız , diğer yanıtlarda belirtildiği gibi IPythonkullanabilirsiniz plt.show(block=False). Ancak tembelseniz şunları yazabilirsiniz:

plt.show(0)

Hangisi aynı olacak.


5

Ayrıca plt.pause(0.001)gerçekten bir for döngüsü içinde çalışmasını sağlamak için benim kod eklemek zorunda kaldı (aksi takdirde sadece ilk ve son arsa gösterecektir):

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)

Bu benim için macOS'ta matplotlib3 ile işe yaradı. Harika!
Jerry Ma

4

Ben komut dosyası kullanıcının grafik ile etkileşim (ve 'pick_event' geri aramalarını kullanarak veri toplamak için) beklemek istedim rağmen benim sistem show () engellemiyor.

Çizim penceresi kapanana kadar yürütmeyi engellemek için aşağıdakileri kullandım:

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

Ancak canvas.start_event_loop_default () yönteminin aşağıdaki uyarıyı verdiğini unutmayın:

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)

komut dosyası hala çalışmasına rağmen.


Teşekkür ederim! Spyder başlangıçta -pylab'ı genellikle yararlı olan içe aktarır, ancak show () ioff () olduğunda engellenmeyeceği anlamına gelir - bu, bu davranışı düzeltmenize izin verir!
kaybetti

3

Ben de bir hata olsa bile benim araziler kodun geri kalanını çalıştırmak görüntülemek (ve daha sonra görüntülemeye devam etmek) istedim (bazen hata ayıklama için araziler kullanın). Bu küçük hack'i kodladım, böylece bu withifadenin içindeki araziler böyle davranıyor.

Bu muhtemelen biraz standart dışıdır ve üretim kodu için önerilmez. Muhtemelen bu kodda çok fazla gizli "gotchas" vardır.

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

Eğer uygun bir "ben açık tutmak (bir hata olsa bile) ve yeni grafiklerin gösterilmesine izin vermek" uygun / uygulamak, hiçbir kullanıcı müdahalesi aksini (toplu yürütme amaçları için) söylerse, komut dosyası düzgün çıkmak istiyorum.

Https://stackoverflow.com/questions/26704840/corner adresinden "Çıktı sonu! \ NPlotlama çıktısının duraklatılmasını istiyorsanız (5 saniyeniz var):" zaman aşımı sorusu gibi bir şey kullanabilirim. -kullan-için-bekle-için-kullanıcı-girdi-kesinti-uygulama .


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

16
Bir basın varolmadan önce nasıl girer?
grovina

2

OP matplotlibparsellerin sökülmesini ister . Çoğu yanıt, bir python yorumlayıcısından komut yürütüldüğünü varsayar. Burada sunulan kullanım örneği, a'nın file.pyçalıştırıldığı bir terminalde (örn. Bash) kod test etme tercihimdir ve çizimlerin ortaya çıkmasını istiyorsunuz, ancak python betiğinin tamamlanmasını ve bir komut istemine geri dönmesini istiyorsunuz.

Bu tek başına dosya, multiprocessingverileri çizmek için ayrı bir işlem başlatmak için kullanılır matplotlib. Ana iş parçacığı bu yazıda os._exit(1)belirtilen kullanılarak çıkar . Ana kuvvetleri çıkmaya zorlar, ancak çizim penceresi kapanana kadar alt süreci canlı ve duyarlı bırakır . Bu tamamen ayrı bir süreç.os._exit()matplotlib

Bu yaklaşım biraz duyarlı bir komut istemi ile gelen şekil pencereleri ile bir Matlab geliştirme oturumu gibidir. Bu yaklaşımla, şekil penceresi işlemi ile tüm teması kaybettiniz, ancak geliştirme ve hata ayıklama için sorun değil. Pencereyi kapatın ve test etmeye devam edin.

multiprocessingbelki sadece daha uygun hale getiren sadece python kod yürütme için tasarlanmıştır subprocess. multiprocessingçapraz platformdur, bu nedenle Windows veya Mac'te çok az ayarlama yaparak veya hiç ayarlama yapmadan iyi çalışmalıdır. Temel işletim sistemini kontrol etmeye gerek yoktur. Bu linux, Ubuntu 18.04LTS üzerinde test edildi.

#!/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

Koşmak file.pybir şekil penceresi getirir, sonra __main__çıkar ancak multiprocessing+ matplotlibşekil penceresi, bağımsız bir işlem olduğu için yakınlaştırma, yatay kaydırma ve diğer düğmelerle yanıt verir.

Bash komut istemindeki işlemleri aşağıdakilerle kontrol edin:

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


Çözümünüzü kullanmaya çalışıyordum ama benim için işe yaramıyor ve nedenini anlamaya çalışıyorum. Kod terminal üzerinden değil, Pycharm IDE'den herhangi bir fark yaratırsa çalıştırmıyorum, olmamalı.
ttsesm

1
Tamam, nihayet benim için neyin işe yaradığını .daemon=Falseburada açıklandığı gibi alt süreci ayarlamak oldu stackoverflow.com/a/49607287/1476932 Ancak, sys.exit()ben çocuk penceresini kapatana kadar orada ana işlemi sonlandırıldı. Öte yandan os._exit(0)yukarıdaki örnekten kullanarak işe yaradı.
ttsesm


0

Hepsini açık tutarken birden fazla rakam açmak istiyorsanız, bu kod benim için çalıştı:

show(block=False)
draw()

show (block = False) kullanımdan kaldırıldı ve artık çalışmıyor
Bogdan

0

OP'nin isteğini doğrudan yanıtlamasa da, bu durumda birisine yardımcı olabileceği için bu geçici çözümü gönderiyorum:

  • Im ben arazileri oluşturmak için gereken python yükleyemiyor çünkü pyinstaller ile bir .exe oluşturma, bu yüzden arsa oluşturmak için python komut dosyası gerekir .png kaydedin, kapatın ve sonraki devam, birkaç parsel olarak bir döngü veya bir işlev kullanarak.

Bunun için kullanıyorum:

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

Burada "var", döngüdeki grafiği tanımlar ve üzerine yazılmaz.


-1

plt.show(block=False)Komut dosyası çağrınızın sonunda ve tuşunu kullanın plt.show().

Bu, komut dosyası tamamlandığında pencerenin kapatılmamasını sağlar.


@ Nico-schlömer kullanıcısının yanıtı
Josh Wolff
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.