¿Hay una manera de separar las gráficas de matplotlib para que el cálculo pueda continuar?


Después de estas instrucciones en el intérprete de Python se obtiene una ventana con un gráfico:

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

Desafortunadamente, no se como continuar explorando interactivamente la figura creada por show() mientras el programa hace más cálculos.

Es posible en absoluto? A veces los cálculos son largos y ayudaría si procedieran durante el examen de los resultados intermedios.

Author: Anton Protopopov, 2009-01-19

18 answers

Usa las llamadas de matplotlib que no bloquearán:

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

Usando el modo interactivo:

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()
 174
Author: nosklo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-26 23:09:47

Use la palabra clave 'block' para anular el comportamiento de bloqueo, por ejemplo,

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

Para continuar su código.

 113
Author: Jan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-26 16:35:45

Es mejor verificar siempre con la biblioteca que está utilizando si admite el uso de una manera no bloqueante.

Pero si desea una solución más genérica, o si no hay otra manera, puede ejecutar cualquier cosa que bloquee en un proceso separado utilizando el multprocessing módulo incluido en python. El cómputo continuará:

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

Que tiene la sobrecarga de lanzar un nuevo proceso, y a veces es más difícil de depurar en escenarios complejos, por lo que preferiría la otra solución (usando matplotlib ' s llamadas API sin bloqueo )

 26
Author: nosklo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:38

Intenta

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.

El show() la documentación dice:

En modo no interactivo, mostrar todas las figuras y bloquear hasta que las figuras se han cerrado; en modo interactivo no tiene ningún efecto a menos que las figuras se crearon antes de un cambio de modo no interactivo a interactivo (no recomendado). En ese caso muestra las figuras pero no bloquea.

Un argumento de palabra clave experimental, block, se puede establecer en True o False para anular el bloqueo comportamiento descrito anteriormente.

 20
Author: Nico Schlömer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-02 10:29:47

Es posible que desee leer este documento en la documentación de matplotlib, titulado:

Usando matplotlib en un shell de python

 10
Author: nosklo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-19 17:00:04

En mi caso, quería tener varias ventanas emergentes a medida que se están computando. Para referencia, este es el camino:

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. Una guía bastante útil para la interfaz OO de matplotlib.

 7
Author: meteore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-11 22:13:17

Bueno, tuve grandes problemas para averiguar los comandos que no bloquean... Pero finalmente, logré volver a trabajar el ejemplo "Cookbook/Matplotlib/Animations - Animating selected plot elements", por lo que funciona con subprocesos ( y pasa datos entre subprocesos a través de variables globales o a través de un multiproceso Pipe) en Python 2.6.5 en Ubuntu 10.04.

El script se puede encontrar aquí: Animating_selected_plot_elements-thread.py - de lo contrario pegado a continuación ( con menos comentarios ) para referencia:

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! 

Espero que esto ayude a alguien,
¡Salud!

 6
Author: sdaau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-10 21:55:48

Si está trabajando en la consola, es decir, IPython podría usar plt.show(block=False) como se indica en las otras respuestas. Pero si eres perezoso, puedes escribir:

plt.show(0)

Que será lo mismo.

 5
Author: Anton Protopopov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-18 11:11:44

IMPORTANTE : Solo para dejar algo claro. Asumo que los comandos están dentro de un script .py y el script se llama usando, por ejemplo, python script.py desde la consola.

Una manera simple que funciona para mí es:

  1. Use el bloque = False dentro de show : plt.show (block = False)
  2. Use otroshow() al final del script .py.

Ejemplo de script.py archivo:

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

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

 5
Author: seralouk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-12 23:08:20

En muchos casos es más conveniente guardar la imagen como a .archivo png en el disco duro. He aquí por qué:

Ventajas:

  • Puede abrirlo, echarle un vistazo y cerrarlo en cualquier momento del proceso. Esto es particularmente conveniente cuando su aplicación se está ejecutando durante mucho tiempo tiempo.
  • Nada aparece y no estás obligado a tener las ventanas abiertas. Esto es particularmente conveniente cuando se trata de muchas figuras.
  • Tu imagen es accesible para referencia posterior y no se pierde al cerrar la ventana de la figura.

Inconveniente:

  • Lo único que se me ocurre es que tendrás que ir a buscar la carpeta y abrir la imagen tú mismo.
 4
Author: elgehelge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-18 18:21:54

Yo también quería mi maquina para mostrar ejecutar el resto del código (y luego mostrar) incluso si hay un error (yo a veces uso de parcelas para la depuración). Codifiqué este pequeño truco para que cualquier parcela dentro de esta declaración with se comporte como tal.

Esto es probablemente un poco no estándar y no recomendable para el código de producción. Probablemente hay muchas "trampas" ocultas en este código.

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

If / when I implement a proper " keep the plots open (even if an error occurs) and permitir que se muestren nuevas gráficas", me gustaría que el script saliera correctamente si ninguna interferencia del usuario le indica lo contrario (para fines de ejecución por lotes).

Puedo usar algo así como una pregunta de tiempo fuera "¡Fin del script! \nPress p si desea que la salida de trazado se detenga (tiene 5 segundos): "desde https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interruption-implementation.

 3
Author: Simon Streicher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:32

En mi sistema, show() no se bloquea, aunque quería que el script esperara a que el usuario interactuara con el gráfico (y recopilara datos usando 'pick_event' callbacks) antes de continuar.

Para bloquear la ejecución hasta que se cierre la ventana del gráfico, utilicé lo siguiente:

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

Tenga en cuenta, sin embargo, que el lienzo.start_event_loop_default() produjo la siguiente advertencia:

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)

Aunque el script todavía se ejecutaba.

 2
Author: Andrew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-17 05:06:56

También tuve que agregar plt.pause(0.001) a mi código para que realmente funcione dentro de un bucle for (de lo contrario solo mostraría la primera y la última gráfica):

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)
 2
Author: Martin Pecka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-09 14:16:16
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
Author: thanhtang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-06 14:49:02

En mi opinión, las respuestas en este hilo proporcionan métodos que no funcionan para todos los sistemas y en situaciones más complejas como las animaciones. Sugiero echar un vistazo a la respuesta de MikeTex en el siguiente hilo, donde se ha encontrado un método robusto: ¿Cómo esperar hasta que termine la animación matplotlib?

 1
Author: MikeTeX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:24

Si entiendo la pregunta correctamente, usando Ipython (o Ipython QT o Ipython notebook) le permitiría trabajar interactivamente con el gráfico mientras los cálculos van uno en segundo plano. http://ipython.org /

 0
Author: chrisfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-24 04:18:42

Si desea abrir varias figuras, mientras las mantiene abiertas, este código funcionó para mí:

show(block=False)
draw()
 0
Author: DomDev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-16 15:11:08

Aquí hay una actualización (python 3.6.5 en Windows 10).

Probé todo tipo de combinaciones - la más simple que he encontrado es solo usar pause(0.01) después de cada parcela - no hay necesidad de un show() para las parcelas intermedias - entonces un solo show() al final se asegura de que pueda mirar la parcela final antes de la terminación.

Como ejemplo, aquí hay un poco de código que uso para verificar la velocidad de varios tamaños de matriz: los valores trazados más altos son velocidades más altas... hay 10 parcelas superpuestas...

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
Author: marzetti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-27 01:47:58