Есть ли способ отсоединить графики matplotlib, чтобы вычисление могло продолжаться?
после этих инструкций в интерпретаторе Python появляется окно с графиком:
from matplotlib.pyplot import *
plot([1,2,3])
show()
# other code
к сожалению, я не знаю, как продолжить интерактивное изучение фигуры, созданной show()
пока программа выполняет дальнейшие вычисления.
возможно ли это вообще? Иногда расчеты бывают длинными, и было бы полезно, если бы они продолжались во время изучения промежуточных результатов.
18 ответов
использовать matplotlib
С вызовы, которые не будут блокировать:
используя 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()
использование интерактивного режима:
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()
используйте ключевое слово "block", чтобы переопределить поведение блокировки, например
from matplotlib.pyplot import show, plot
plot(1)
show(block=False)
# your code
для продолжения кода.
лучше всегда проверять с библиотекой, которую вы используете, если она поддерживает использование в неблокирующий путь.
но если вы хотите более общее решение, или если нет другого способа, вы можете запустить все, что блокирует в отдельном процессе, используя multprocessing
модуль, включенный в Python. Вычисления продолжатся:
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()
это накладные расходы на запуск нового процесса, и иногда сложнее отлаживать в сложных сценариях, поэтому я бы предпочел другое решение (используя matplotlib
' s неблокирующие вызовы API)
попробовать
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.
на show()
документация говорит:
в неинтерактивном режиме отображать все фигуры и блок, пока фигуры не будут закрыты; в интерактивном режиме это не имеет никакого эффекта, если только фигуры не были созданы до перехода из неинтерактивного в интерактивный режим (не рекомендуется). В этом случае он отображает цифры, но не блокирует.
один экспериментальный аргумент ключевого слова
block
, может быть установлено вTrue
илиFalse
чтобы переопределить поведение блокировки, описанное выше.
в моем случае я хотел, чтобы при вычислении появилось несколько окон. Для справки, это так:
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. Весьма полезный руководство по интерфейсу OO matplotlib.
Ну, у меня были большие проблемы с выяснением неблокирующих команд... Но, наконец, мне удалось переработать "Поваренная книга / Matplotlib / анимация-анимация выбранных элементов сюжета" пример, поэтому он работает с потоками (и передает данные между потоками, либо через глобальные переменные, либо через многопроцессным Pipe
) на Python 2.6.5 на Ubuntu 10.04.
скрипт можно найти здесь:Animating_selected_plot_elements-thread.py - в противном случае вставлено ниже (С меньшим количеством комментариев) для справки:
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!
надеюсь, это поможет кому-то,
Ура!
Если вы работаете в консоли, то есть IPython
можно использовать plt.show(block=False)
как указано в других ответах. Но если вы ленивы, вы можете просто ввести:
plt.show(0)
что будет то же самое.
важно: просто чтобы прояснить кое-что. Я предполагаю, что команды находятся внутри .py
скрипт и скрипт вызывается с помощью, например,python script.py
из консоли.
простой способ, который работает для меня:
- используйте block = False внутри show:plt.show (block = False)
- использовать другое show ()в конце of the .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
# the next is the last line of my script
plt.show()
во многих случаях это более удобно, пока Сохранить Изображение как a .png-файл на жестком диске. Вот почему:
плюсы:
- вы можете открыть его, взглянуть на него и закрыть его в любое время в процессе. Это особенно удобно, когда приложение работает в течение длительного время.
- ничего не появляется, и вы не вынуждены открывать окна. Это особенно удобно, когда вы имеете дело с многие деятели.
- ваше изображение доступно для последующего использования и не теряется при закрытии окна рисунка.
недостаток:
- единственное, что я могу придумать, это то, что вам придется пойти и найти папку и открыть изображение самостоятельно.
Я также хотел, чтобы мои графики отображали запуск остальной части кода (а затем продолжали отображать), даже если есть ошибка (Я иногда использую графики для отладки). Я закодировал этот маленький хак, чтобы любые сюжеты внутри этого with
оператор ведет себя как таковой.
это, вероятно, слишком нестандартно и не рекомендуется для производственного кода. В этом коде, вероятно, много скрытых "gotchas".
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
Если / когда я реализую правильный " держать графики открытыми (даже если возникает ошибка) и разрешить показ новых графиков", я хотел бы, чтобы скрипт правильно выходил, если никакое вмешательство пользователя не говорит ему иначе (для целей пакетного выполнения).
Я могу использовать что-то вроде тайм-аута "конец сценария! \nPress p если вы хотите приостановить вывод графика (у вас есть 5 секунд): "от https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interruption-implementation.
в моей системе show () не блокируется, хотя я хотел, чтобы скрипт ждал, пока пользователь будет взаимодействовать с графиком (и собирать данные с помощью обратных вызовов 'pick_event'), прежде чем продолжить.
чтобы заблокировать выполнение до закрытия окна графика, я использовал следующее:
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
обратите внимание, однако, что холст.start_event_loop_default () выдал следующее предупреждение:
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)
хотя скрипт все еще работал.
Я также должен был добавить plt.pause(0.001)
моему коду, чтобы он действительно работал внутри цикла for (иначе он показывал бы только первый и последний сюжет):
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)
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
на мой взгляд, ответы в этом потоке предоставляют методы, которые не работают для всех систем и в более сложных ситуациях, таких как анимация. Я предлагаю взглянуть на ответ MikeTex в следующем потоке, где был найден надежный метод: Как дождаться окончания анимации matplotlib?
Если я правильно понимаю вопрос, используя Ipython (или IPython QT или IPython notebook) позволит вам работать в интерактивном режиме с диаграммой, в то время как вычисления идут в фоновом режиме. http://ipython.org/
Если вы хотите открыть несколько фигур, сохраняя их все открыл, этот код работал для меня:
show(block=False)
draw()
вот обновление (python 3.6.5 в Windows 10).
Я пробовал всевозможные комбинации-самый простой, который я нашел, - это просто использовать pause(0.01)
после каждого сюжета - не нужен show()
для промежуточных участков - то один show()
в конце гарантирует, что вы можете посмотреть на окончательный участок перед завершением.
в качестве примера, вот немного кода, который я использую для проверки скорости для различных размеров массива-более высокие построенные значения-более высокие скорости... есть 10 обложил график...
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()