Y a-t-il un moyen de détacher les tracés de matplotlib pour que le calcul puisse continuer?

après ces instructions dans l'interpréteur Python on obtient une fenêtre avec un tracé:

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

malheureusement, je ne sais pas comment continuer à explorer de façon interactive le chiffre créé par show() pendant que le programme fait d'autres calculs.

est-ce possible? Les calculs sont parfois longs et il serait utile qu'ils soient effectués au cours de l'examen des résultats intermédiaires.

200
demandé sur Anton Protopopov 2009-01-19 19:30:57

18 réponses

utilisez matplotlib les appels qui ne bloqueront pas:

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

utilisant le mode interactif:

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
répondu nosklo 2015-10-26 23:09:47

utilisez le mot-clé 'block' pour outrepasser le comportement de blocage, par exemple

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

pour continuer votre code.

113
répondu Jan 2013-11-26 16:35:45

il est préférable de toujours vérifier avec la bibliothèque que vous utilisez si elle supporte l'utilisation d'une manière non-bloquante .

mais si vous voulez une solution plus générique, ou s'il n'y a pas d'autre moyen, vous pouvez exécuter tout ce qui bloque dans un processus séparé en utilisant le module multprocessing inclus dans python. Le calcul se poursuivra:

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

qui a la charge de lancer un nouveau processus, et est parfois plus difficile à déboguer sur des scénarios complexes, donc je préférerais l'autre solution (en utilisant matplotlib 's appels API non bloquants )

26
répondu nosklo 2017-05-23 12:26:38

Essayer

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.

Le show() documentation dit:

en mode non interactif, afficher toutes les figures et les bloquer jusqu'à ce que les figures aient été fermées; en mode interactif, cela n'a d'effet que si les figures ont été créées avant le passage du mode non interactif au mode interactif (non recommandé). Dans ce cas, il affiche les chiffres, mais ne bloque pas.

A un seul argument expérimental, block , peut être défini à True ou False pour outrepasser le comportement de blocage décrit ci-dessus.

20
répondu Nico Schlömer 2015-12-02 10:29:47

vous pouvez lire ce document dans la documentation de matplotlib , intitulé:

utilisant matplotlib dans un shell python

10
répondu nosklo 2009-01-19 17:00:04

dans mon cas, je voulais avoir plusieurs fenêtres pop up comme ils sont calculés. Pour référence, c'est le chemin:

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. Un guide très utile pour l'interface OO de matplotlib .

7
répondu meteore 2015-05-11 22:13:17

J'ai eu beaucoup de mal à trouver les commandes non bloquantes... Mais finalement, j'ai réussi à retravailler le " Cookbook/Matplotlib/Animations - animation des éléments de parcelle sélectionnés " exemple, il fonctionne avec des threads ( et passe des données entre les threads soit via des variables globales, ou par un multiprocess Pipe ) sur Python 2.6.5 sur Ubuntu 10.04.

le script peut être trouvé ici: Animating_selected_plot_elements-thread.py - autrement collé ci-dessous ( avec moins de commentaires ) pour référence:

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! 

Espérons que cela aide quelqu'un,

Acclamations!

6
répondu sdaau 2010-11-10 21:55:48

si vous travaillez en console, c.-à-d. IPython vous pouvez utiliser plt.show(block=False) comme indiqué dans les autres réponses. Mais si vous êtes paresseux, vous pouvez taper:

plt.show(0)

Qui sera le même.

5
répondu Anton Protopopov 2016-01-18 11:11:44

IMPORTANT : juste pour clarifier quelque chose. Je suppose que les commandes sont dans un script .py et que le script est appelé en utilisant par exemple python script.py de la console.

une façon simple qui fonctionne pour moi est:

  1. utilisez le bloc = False inside show: plt.show(bloc = False)
  2. Utiliser l'autre show() à la fin de la .py script.

exemple de script.py fichier:

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
répondu seralouk 2018-05-12 23:08:20

Dans de nombreux cas, il est plus pratique til enregistrer l'image comme une .png fichier sur le disque dur. Voici pourquoi:

avantages:

  • vous pouvez l'ouvrir, y jeter un oeil et le fermer à tout moment du processus. Ceci est particulièrement pratique lorsque votre application est en cours d'exécution pendant une longue temps.
  • rien n'apparaît et vous n'êtes pas forcé d'avoir les fenêtres ouvertes. Cela est particulièrement pratique lorsque vous avez affaire à de nombreux chiffres.
  • votre image est accessible pour consultation ultérieure et n'est pas perdue lors de la fermeture de la fenêtre de figure.

Inconvénient:

  • la seule chose à laquelle je pense, c'est que vous devez aller trouver le dossier et ouvrir l'image vous-même.
4
répondu elgehelge 2013-12-18 18:21:54

j'ai aussi voulu que mes tracés s'affichent, exécutent le reste du code (et continuent ensuite à s'afficher) même s'il y a une erreur (j'utilise parfois des tracés pour le débogage). J'ai codé ce petit piratage pour que toutes les intrigues à l'intérieur de cette déclaration with se comportent comme telles.

c'est probablement un peu trop non standard et déconseillé pour le code de production. Il y a probablement beaucoup de "gotchas" cachés dans ce 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 __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

Si/quand-je mettre en œuvre un proprement "garder les placettes ouvertes (même si une erreur se produit) et permettre l'affichage de nouvelles placettes", je voudrais que le script se termine correctement si aucune interférence de l'utilisateur ne lui dit le contraire (à des fins d'exécution par lots).

je peux utiliser quelque chose comme un time-out-question" fin du script! \nPress p Si vous voulez que la sortie de pointage soit interrompue (vous avez 5 secondes): "from https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interruption-implementation .

3
répondu Simon Streicher 2017-05-23 11:47:32

sur mon show système() ne bloque pas, bien que je voulais que le script attende que l'utilisateur interagisse avec le graphe (et collecte des données en utilisant les callbacks 'pick_event') avant de continuer.

afin de bloquer l'exécution jusqu'à ce que la fenêtre de la parcelle soit fermée, j'ai utilisé ce qui suit:

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

notez cependant cette toile.start_event_loop_default () a produit l'avertissement suivant:

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)

bien que le script encore couru.

2
répondu Andrew 2011-03-17 05:06:56

j'ai dû aussi ajouter plt.pause(0.001) à mon code pour le faire fonctionner vraiment à l'intérieur d'une boucle for (sinon il ne montrerait que la première et la dernière parcelle):

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
répondu Martin Pecka 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
répondu thanhtang 2017-03-06 14:49:02

à mon avis, les réponses dans ce fil fournissent des méthodes qui ne fonctionnent pas pour tous les systèmes et dans des situations plus complexes comme les animations. Je suggère de jeter un oeil à la réponse de MikeTex dans le fil suivant, où une méthode robuste a été trouvé: comment attendre la fin de l'animation matplotlib?

1
répondu MikeTeX 2017-05-23 12:18:24

si je comprends bien la question, en utilisant Ipython (ou Ipython QT ou IPython notebook) vous permet de travailler de façon interactive avec le graphique tandis que les calculs vont un dans l'arrière-plan. http://ipython.org/

0
répondu chrisfs 2012-05-24 04:18:42

si vous voulez ouvrir plusieurs chiffres, tout en les gardant ouverts, ce code a fonctionné pour moi:

show(block=False)
draw()
0
répondu DomDev 2016-09-16 15:11:08

Voici une mise à jour (Python 3.6.5 sous Windows 10).

j'ai essayé toutes sortes de combinaisons - le plus simple que j'ai trouvé est juste d'utiliser pause(0.01) après chaque parcelle - pas besoin d'un show() pour les parcelles intermédiaires - puis un seul show() à la fin garantit que vous pouvez regarder la parcelle finale avant la fin.

à titre d'exemple, voici un peu de code que j'utilise pour vérifier la vitesse pour diverses tailles de tableaux - les valeurs tracées plus élevées sont plus élevées vitesse... il y a 10 placettes superposées...

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
répondu marzetti 2018-06-27 01:47:58