Existe uma maneira de separar parcelas matplotlib para que a computação pode continuar?
-
19-08-2019 - |
Pergunta
Depois destas instruções no Python intérprete obtém-se uma janela com um enredo:
from matplotlib.pyplot import *
plot([1,2,3])
show()
# other code
Infelizmente, eu não sei como continuar a explorar de forma interativa a figura criada por show()
enquanto o programa faz outros cálculos.
É possível em tudo? Às vezes, os cálculos são longos e seria bom se eles iriam continuar durante o exame dos resultados intermediários.
Solução
chamadas de Uso matplotlib
que não vai bloquear:
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 o modo interativo:
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()
Outras dicas
Use a palavra-chave 'block' para substituir o comportamento de bloqueio, por exemplo,
from matplotlib.pyplot import show, plot
plot(1)
show(block=False)
# your code
para continuar seu código.
É melhor verificar sempre com a biblioteca que você está usando se ele suporta o uso de non-blocking forma.
Mas se você quiser uma solução mais genérica, ou se não houver nenhuma outra maneira, você pode executar qualquer coisa que bloqueia em um processo separado usando o multprocessing
módulo incluído no python. Computação 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()
Isso tem a sobrecarga de lançamento de um novo processo, e às vezes é mais difícil de depuração em cenários complexos, então eu prefiro a outra solução (usando de matplotlib
bloqueante chamadas de API )
Tente
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.
O show()
documentação diz:
No modo não interactivo, exibir todas as figuras e bloquear até que os valores foram fechadas; no modo interativo não tem efeito a menos que figuras foram criadas antes de uma mudança de não-interativo para modo interativo (não recomendado). Nesse caso, ele exibe os números, mas não bloqueia.
Uma única palavra-chave argumento experimental,
block
, pode ser definido paraTrue
ouFalse
para substituir o comportamento de bloqueio descrito acima.
Você pode querer ler este documento na documentação do matplotlib
, intitulado:
IMPORTANTE : Só para deixar algo bem claro. Presumo que os comandos estão dentro de um script .py
eo script é chamado usando por exemplo python script.py
do console.
Uma simples maneira que funciona para mim é:
- Use o bloco = False dentro show: plt.show (bloco = False)
- Use outra show () no final do script py.
Exemplo de arquivo script.py
:
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()
No meu caso, eu queria ter várias janelas pop-up como eles estão sendo calculado. Para referência, este é o caminho:
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. Um bastante útil guia para OO do matplotlib interface de .
Bem, eu tinha grande dificuldade para descobrir os comandos sem bloqueio ... Mas, finalmente, consegui refazer o " Cookbook / Matplotlib / animações - animando selecionado elementos do enredo " exemplo, assim que trabalha com fios ( e passa dados entre threads, quer através de variáveis ??globais, ou através de um Pipe
multiprocess ) em Python 2.6.5 no Ubuntu 10.04.
O script pode ser encontrada aqui: Animating_selected_plot_elements-thread.py - caso contrário colado abaixo ( com menos comentários ) para referência:
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 isso ajude alguém,
Felicidades!
Em muitos casos, é mais conveniente até salvar a imagem como um arquivo .png no disco rígido. Aqui está o porquê:
Vantagens:
- Você pode abri-lo, ter um olhar para ele e fechá-lo a qualquer momento durante o processo. Isto é particularmente conveniente quando o seu aplicativo está sendo executado por um longo tempo.
- Nada aparece e você não é obrigado a ter as janelas abertas. Isto é particularmente útil quando você está lidando com muitas figuras.
- A sua imagem está acessível para consulta posterior e não são perdidos quando fechar a janela da figura.
Drawback:
- A única coisa que posso pensar é que você terá que ir e localizador da pasta e abra a imagem si mesmo.
Se você estiver trabalhando no console, ou seja IPython
você poderia usar plt.show(block=False)
como fora apontado em outras respostas. Mas se você é preguiçoso você poderia simplesmente digitar:
plt.show(0)
Qual será o mesmo.
Eu tive que adicionar também plt.pause(0.001)
ao meu código para torná-la realmente trabalhando dentro de um loop for (caso contrário, seria apenas mostrar a primeira e última parcela):
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)
Eu também queria que meus planos para exibir executar o resto do código (e, em seguida, continuar a visualizar), mesmo se houver um erro (eu às vezes uso parcelas para depuração). I codificado-se este pequeno truque para que quaisquer parcelas dentro deste comportam declaração with
como tal.
Este é provavelmente um pouco fora do padrão e não aconselhável para código de produção. Há provavelmente um monte de escondidas "pegadinhas" neste 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
Se / quando eu implementar uma adequada "manter as parcelas aberta (mesmo se ocorrer um erro) e permitir que novas parcelas para ser mostrado", eu gostaria que o script corretamente Sair se nenhuma interferência do usuário diz o contrário (para execução em lote fins).
Eu posso usar algo como um time-out-pergunta "End of script \ nPrima p se você deseja que a saída conspirar para ser pausado (você tem 5 segundos):" a partir de https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait- for-user-input-interrupção-implementação .
No meu show system () não bloqueia, embora eu queria o script para aguardar o usuário interagir com o gráfico (e dados de coleta usando 'pick_event' callbacks) antes de continuar.
Para a execução do bloco até que a janela do enredo está fechada, eu usei o seguinte:
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
Note, no entanto, que canvas.start_event_loop_default () produziu o seguinte aviso:
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)
Embora o roteiro ainda corria.
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
Na minha opinião, as respostas neste segmento fornecer métodos que não funcionam para todos os sistemas e em situações mais complexas como animações. Sugiro ter um olhar para a resposta de MiKTeX na seguinte discussão, onde um método robusto foi encontrado: Como esperar até fins de animação matplotlib?
Se você quiser abrir várias figuras, mantendo-os abertos, este código funcionou para mim:
show(block=False)
draw()
O OP pergunta sobre detatching parcelas matplotlib
. A maioria das respostas assumir a execução de comandos a partir de um interpretador Python. O caso de uso apresentado aqui é a minha preferência para testar o código em um terminal (por exemplo, bash) onde um file.py
é executado e você quer (s) o enredo para chegar, mas o script Python para preencher e devolver a um prompt de comando.
Esta usos de arquivo multiprocessing
stand-alone para lançar um processo separado para plotagem de dados com matplotlib
. As principais saídas de rosca usando o os._exit(1)
mencionado na este pós . As forças os._exit()
principal para sair, mas deixa o processo filho matplotlib
vivos e sensíveis até que a janela do enredo está fechado. É um processo separado completamente.
Esta abordagem é um pouco como uma sessão de desenvolvimento Matlab com figura janelas que surgem com um prompt de comando responsivo. Com esta abordagem, você perdeu todo o contato com o processo janela figura, mas, que é ok para o desenvolvimento e depuração. Basta fechar a janela e manter o teste.
multiprocessing
é projetado para a execução de código só de python que torna talvez mais adequado do que subprocess
. multiprocessing
é multi-plataforma de modo que este deve funcionar bem no Windows ou Mac com pouco ou nenhum ajuste. Não há necessidade de verificar o sistema operacional subjacente. Este foi testado em Linux, Ubuntu 18.04LTS.
#!/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
Running file.py
abre uma janela figura, sai então __main__
mas a janela do multiprocessing
+ figura matplotlib
continua a responder com zoom, pan, e outros botões, porque é um processo independente.
Verifique os processos no comando bash tempo com:
ps ax|grep -v grep |grep file.py
Use plt.show(block=False)
, e no final do seu plt.show()
chamada de script.
Isto irá assegurar que a janela não será fechada quando o script for concluído.