web-dev-qa-db-de.com

Gibt es eine Möglichkeit, Matplotlib-Diagramme zu trennen, damit die Berechnung fortgesetzt werden kann?

Nach diesen Anweisungen im Python Interpreter erhält man ein Fenster mit einem Plot:

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

Leider weiß ich nicht, wie ich die von show() erstellte Figur weiterhin interaktiv untersuchen kann, während das Programm weitere Berechnungen durchführt.

Ist das überhaupt möglich? Manchmal sind Berechnungen lang und es wäre hilfreich, wenn sie während der Prüfung der Zwischenergebnisse durchgeführt würden.

237
meteore

Verwenden Sie die Aufrufe von matplotlib, die nicht blockieren:

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

Verwenden des interaktiven Modus:

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

Verwenden Sie das Schlüsselwort "block", um das Blockierungsverhalten zu überschreiben, z.

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

um den Code fortzusetzen.

119
Jan

Es ist besser, immer bei der von Ihnen verwendeten Bibliothek nachzufragen, ob sie die Verwendung in einer nicht blockierenden Weise unterstützt.

Wenn Sie jedoch eine allgemeinere Lösung wünschen oder wenn es keine andere Möglichkeit gibt, können Sie alles, was blockiert, in einem getrennten Prozess ausführen, indem Sie das in Python enthaltene multprocessing -Modul verwenden. Die Berechnung wird fortgesetzt:

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

Das hat den Overhead, einen neuen Prozess zu starten, und ist manchmal schwieriger zu debuggen, daher würde ich die andere Lösung vorziehen (mit matplotlib 's nicht blockierende API-Aufrufe )

29
nosklo

Versuchen

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

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

Die show() Dokumentation sagt:

Zeigen Sie im nicht interaktiven Modus alle Figuren und den Block an, bis die Figuren geschlossen wurden. Im interaktiven Modus hat dies keine Auswirkung, es sei denn, die Figuren wurden vor dem Wechsel vom nicht interaktiven in den interaktiven Modus erstellt (nicht empfohlen). In diesem Fall werden die Zahlen angezeigt, jedoch nicht blockiert.

Ein einzelnes experimentelles Schlüsselwortargument, block, kann auf True oder False gesetzt werden, um das oben beschriebene Sperrverhalten zu überschreiben.

21
Nico Schlömer

Möglicherweise möchten Sie dieses Dokument in der Dokumentation von matplotlib mit dem Titel lesen:

Verwendung von matplotlib in einer python Shell

10
nosklo

WICHTIG : Nur um etwas klarer zu machen. Ich gehe davon aus, dass die Befehle in einem .py Skript und das Skript wird unter Verwendung von z.B. python script.py von der Konsole.

Ein einfacher Weg, der für mich funktioniert, ist:

  1. Verwenden Sie den Block = False inside show: plt.show (block = False)
  2. Verwenden Sie ein anderes show () am Ende des .py-Skripts.

Beispiel vonscript.py Datei:

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

9
serafeim

In meinem Fall wollte ich, dass beim Berechnen mehrere Fenster angezeigt werden. Als Referenz ist dies der Weg:

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. Eine recht nützliche Anleitung zur matplotlib's OO interface .

8
meteore

Nun, ich hatte große Probleme, die nicht blockierenden Befehle herauszufinden ... Aber schließlich gelang es mir, das Beispiel " Cookbook/Matplotlib/Animations - Animating selected plot elements " zu überarbeiten, damit es mit Threads funktioniert ( und übergibt Daten zwischen Threads entweder über globale Variablen oder über einen Multiprozess Pipe) an Python = 2.6.5 unter Ubuntu 10.04.

Das Skript finden Sie hier: Animating_selected_plot_elements-thread.py - Andernfalls wird es unten eingefügt ( mit weniger Kommentaren ) als Referenz:

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! 

Hoffe das hilft jemandem,
Prost!

6
sdaau

Wenn Sie in der Konsole arbeiten, d. H. IPython, können Sie plt.show(block=False) verwenden, wie in den anderen Antworten erläutert. Aber wenn Sie faul sind, können Sie einfach Folgendes eingeben:

plt.show(0)

Welches wird das gleiche sein.

5

In vielen Fällen ist es bequemer, um das Bild zu speichern als PNG-Datei auf der Festplatte. Hier ist warum:

Vorteile:

  • Sie können es jederzeit öffnen, ansehen und schließen. Dies ist besonders praktisch, wenn Ihre Anwendung über einen längeren Zeitraum ausgeführt wird.
  • Es wird nichts angezeigt und Sie müssen die Fenster nicht öffnen. Dies ist besonders praktisch, wenn Sie mit vielen Zahlen zu tun haben.
  • Ihr Bild ist für spätere Referenzzwecke zugänglich und geht beim Schließen des Figurenfensters nicht verloren.

Nachteil:

  • Das einzige, was mir einfällt, ist, dass Sie den Ordner suchen und das Bild selbst öffnen müssen.
5
elgehelge

Ich musste meinem Code auch plt.pause(0.001) hinzufügen, damit es wirklich in einer for-Schleife funktioniert (andernfalls würde nur der erste und der letzte Plot angezeigt):

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)
4
Martin Pecka

Ich wollte auch, dass meine Diagramme den Rest des Codes anzeigen (und dann weiter anzeigen), auch wenn ein Fehler auftritt (manchmal verwende ich Diagramme zum Debuggen). Ich habe diesen kleinen Hack so programmiert, dass sich alle Darstellungen in dieser with -Anweisung als solche verhalten.

Dies ist wahrscheinlich etwas zu ungewöhnlich und für den Seriencode nicht empfehlenswert. Es gibt wahrscheinlich viele versteckte "Fallstricke" in diesem Code.

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 __== '__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

Wenn ich eine ordnungsgemäße Methode implementiere, die es mir ermöglicht, "die Diagramme offen zu halten (auch wenn ein Fehler auftritt) und die Anzeige neuer Diagramme zuzulassen", möchte ich, dass das Skript ordnungsgemäß beendet wird, wenn keine Benutzereingriffe dies anders anzeigen (zu Batch-Ausführungszwecken).

Ich verwende möglicherweise so etwas wie eine Timeout-Frage "Skriptende!\NDrücken Sie p, wenn die Plotausgabe angehalten werden soll (Sie haben 5 Sekunden Zeit):" von https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interrupt-implementierung .

3
Simon Streicher

In meinem System blockiert show () nicht, obwohl ich wollte, dass das Skript wartet, bis der Benutzer mit dem Diagramm interagiert (und Daten mithilfe von 'pick_event'-Rückrufen sammelt), bevor ich fortfahre.

Um die Ausführung zu blockieren, bis das Plotfenster geschlossen ist, habe ich Folgendes verwendet:

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

Beachten Sie jedoch, dass canvas.start_event_loop_default () die folgende Warnung erzeugt hat:

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)

obwohl das Skript noch lief.

2
Andrew
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
2
thanhtang

Meiner Meinung nach bieten die Antworten in diesem Thread Methoden, die nicht für jedes System und in komplexeren Situationen wie Animationen funktionieren. Ich schlage vor, einen Blick auf die Antwort von MiKTeX im folgenden Thread zu werfen, in dem eine robuste Methode gefunden wurde: Wie warte ich, bis die Matplotlib-Animation endet?

1
MikeTeX

Das OP fragt nach dem Löschen von matplotlib Plots. Die meisten Antworten gehen von einer Befehlsausführung innerhalb eines python Interpreters aus. Der hier dargestellte Anwendungsfall ist meine Präferenz für das Testen von Code in einem Terminal (z. B. bash), in dem ein file.py Ausgeführt wird, und Sie möchten, dass die Handlung (en) angezeigt wird, aber das Skript python abgeschlossen wird und zu einer Eingabeaufforderung zurückkehrt.

Diese eigenständige Datei verwendet multiprocessing, um einen separaten Prozess zum Plotten von Daten mit matplotlib zu starten. Der Haupt-Thread wird mit der in this post erwähnten os._exit(1) beendet. Die os._exit() erzwingt das Beenden von main, lässt jedoch den matplotlib Child-Prozess lebendig und ansprechend, bis das Plotfenster geschlossen wird. Es ist ein völlig separater Prozess.

Dieser Ansatz ähnelt einer Matlab-Entwicklungssitzung mit Zahlenfenstern, die eine reaktionsfähige Eingabeaufforderung enthalten. Mit diesem Ansatz haben Sie den Kontakt zum Figurenfenster-Prozess verloren, aber das ist für die Entwicklung und das Debuggen in Ordnung. Einfach das Fenster schließen und weiter testen.

multiprocessing ist nur für die Ausführung von Python-Code vorgesehen, weshalb es möglicherweise besser geeignet ist als subprocess. multiprocessing ist plattformübergreifend, daher sollte dies unter Windows oder Mac mit geringen oder keinen Anpassungen gut funktionieren. Das zugrunde liegende Betriebssystem muss nicht überprüft werden. Dies wurde unter Linux, Ubuntu 18.04LTS getestet.

#!/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 __== "__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

Wenn Sie file.py Ausführen, wird ein Zahlenfenster geöffnet, und dann wird __main__ Beendet. Das Zahlenfenster multiprocessing + matplotlib reagiert jedoch weiterhin mit Zoom-, Schwenk- und anderen Schaltflächen ist ein unabhängiger Prozess.

Überprüfen Sie die Prozesse an der Bash-Eingabeaufforderung mit:

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

0
Marc Compere

Verwenden Sie plt.show(block=False) und rufen Sie am Ende Ihres Skripts plt.show() auf.

Dadurch wird sichergestellt, dass das Fenster nicht geschlossen wird, wenn das Skript beendet ist.

0
Ken Mueller

Hier ist ein Update (Python 3.6.5 unter Windows 10).

Ich habe alle möglichen Kombinationen ausprobiert - das Einfachste, was ich gefunden habe, ist, pause(0.01) nach jedem Plot zu verwenden - keine show() für die Zwischenplots erforderlich - dann eine einzelne show() am Ende stellt sicher, dass Sie den endgültigen Plot vor der Beendigung anzeigen können.

Als Beispiel hier ein bisschen Code, den ich verwende, um die Geschwindigkeit für verschiedene Array-Größen zu überprüfen - höhere geplottete Werte sind höhere Geschwindigkeiten ... es gibt 10 überlagerte Plots ...

from pylab import *
import matplotlib.pyplot as plt
from time import *
ttot=clock();
mmax=6;npts=20;nplts=10;
x=[int(a+0.5) for a in 10**linspace(0,mmax,npts)]
for nrun in range(nplts):
    j=0;aa=1;bb=1;b=1;
    tim=zeros(npts)
    for n in x:
        aa=Rand(n);bb=aa;b=aa;
        if n<100:m=10000
        Elif n<5000:m=1000
        Elif n<20000:m=100
        else:m=100
        tt=clock()
        for ii in range(1,m+1):
          b=aa*bb+aa
        tt1=clock()-tt
        tim[j]=tt1/n/m
        j=j+1
    print(n,2/(tt1/n/m)/1e6);
    plt.semilogx(x,2/tim/1e6)
    pause(0.01)
print(clock()-ttot)
show()
0
marzetti

Wenn Sie mehrere Figuren öffnen möchten, während alle geöffnet bleiben, hat dieser Code für mich funktioniert:

show(block=False)
draw()
0
DomDev