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.
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()
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.
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 )
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 aufTrue
oderFalse
gesetzt werden, um das oben beschriebene Sperrverhalten zu überschreiben.
Möglicherweise möchten Sie dieses Dokument in der Dokumentation von matplotlib
mit dem Titel lesen:
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:
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()
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 .
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!
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.
In vielen Fällen ist es bequemer, um das Bild zu speichern als PNG-Datei auf der Festplatte. Hier ist warum:
Vorteile:
Nachteil:
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)
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 .
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.
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
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?
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
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.
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()
Wenn Sie mehrere Figuren öffnen möchten, während alle geöffnet bleiben, hat dieser Code für mich funktioniert:
show(block=False)
draw()