Есть ли способ отсоединить графики matplotlib, чтобы вычисления могли продолжаться?

После этих инструкций в интерпретаторе Python появляется окно с графиком:

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

К сожалению, я не знаю, как продолжить интерактивное исследование фигуры, созданной show(), в то время как программа выполняет дальнейшие вычисления.

Возможно ли вообще? Иногда расчеты длинные, и это помогло бы, если бы они продолжались при рассмотрении промежуточных результатов.

Ответ 1

Используйте 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()

Ответ 2

Используйте ключевое слово "блок", чтобы переопределить поведение блокировки, например.

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

чтобы продолжить свой код.

Ответ 3

Лучше всегда проверять с библиотекой, которую вы используете, поддерживает ли она неблокирующее использование.

Но если вам нужно более общее решение, или если нет другого пути, вы можете запустить все, что блокирует отдельный процесс, используя 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()

Это накладные расходы на запуск нового процесса, и иногда сложнее отлаживать в сложных сценариях, поэтому я бы предпочел другое решение (с использованием неблокирующих вызовов API matplotlib)

Ответ 4

Попробуйте

import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.show(block=False)
# other code
# [...]

# Put
plt.show()
# at the very end of your script to make sure Python does not bail out
# before you finished examining.

Документация show() гласит:

В неинтерактивном режиме отобразите все фигуры и заблокируйте их, пока фигуры не будут закрыты; в интерактивном режиме это не действует, если рисунки не были созданы до перехода из неинтерактивного в интерактивный режим (не рекомендуется). В этом случае он отображает цифры, но не блокирует их.

Один экспериментальный ключевой аргумент block может иметь значение True или False, чтобы переопределить поведение блокировки, описанное выше.

Ответ 5

ВАЖНО: Просто чтобы прояснить что-то. Я предполагаю, что команды находятся внутри скрипта .py и скрипт вызывается с помощью, например, python script.py из консоли.

Простой способ, который работает для меня:

  1. Используйте block = False внутри show: plt.show(block = False)
  2. Используйте другой show() в конце скрипта .py.

Пример файла 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()

Ответ 7

В моем случае, я хотел, чтобы несколько окон всплывали, когда они вычисляются. Для справки, это способ:

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. Очень полезный справочник по интерфейсу OAP matplotlib.

Ответ 8

Ну, мне было очень сложно разобраться с неблокирующими командами... Но, наконец, мне удалось переработать " Cookbook/Matplotlib/Animations - Animating выбранные элементы графика", поэтому он работает с потоками (и передает данные между потоками либо через глобальные переменные, либо через мультипроцесс Pipe) на Python 2.6.5 на Ubuntu 10.04.

script можно найти здесь: 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! 

Надеюсь, это поможет кому-то,
Ура!

Ответ 9

Во многих случаях он более удобен, чем сохранение изображения в виде файла .png на жестком диске. Вот почему:

<сильные > Преимущества:

  • Вы можете открыть его, посмотреть на него и закрыть его в любое время в процессе. Это особенно удобно, когда ваше приложение работает долго время.
  • Ничего не появляется, и вы не должны открывать окна. Это особенно удобно, когда вы имеете дело со многими цифрами.
  • Ваше изображение доступно для последующего использования и не теряется при закрытии окна рисунка.

Минус:

  • Единственное, что я могу придумать, это то, что вам придется искать и находить папку и открывать изображение самостоятельно.

Ответ 10

Если вы работаете в консоли, т.е. IPython, вы можете использовать plt.show(block=False), как указано в других ответах. Но если вы ленивы, вы можете просто ввести:

plt.show(0)

Что будет одинаково.

Ответ 11

Мне также пришлось добавить 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)

Ответ 12

Я также хотел, чтобы мои графики отображали пробег остальной части кода (а затем продолжали отображать), даже если есть ошибка (иногда я использую графики для отладки). Я закодировал этот маленький хак, чтобы любые графики внутри этого оператора 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

Если/когда я реализую правильное "удерживать графики открытыми (даже если произошла ошибка) и разрешить отображение новых графиков", я бы хотел, чтобы script правильно вышел, если никакие пользовательские помехи не говорят об этом иначе (для пакетное исполнение).

Я могу использовать что-то вроде тайм-аута "Конец script!\nНажмите p, если вы хотите, чтобы вывод графика был приостановлен (у вас есть 5 секунд):" from https://stackoverflow.com/questions/26704840/corner-cases-for-my-wait-for-user-input-interruption-implementation.

Ответ 13

В моей системе show() не блокируется, хотя я хотел, чтобы script ожидал, что пользователь будет взаимодействовать с графиком (и собирать данные с помощью обратных вызовов 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

Обратите внимание, однако, что canvas.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)

хотя script все еще выполнялся.

Ответ 14

plt.figure(1)
plt.imshow(your_first_image)

plt.figure(2)
plt.imshow(your_second_image)

plt.show(block=False) # That 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

Ответ 15

На мой взгляд, ответы в этой теме предоставляют методы, которые не работают для каждой системы и в более сложных ситуациях, таких как анимация. Я предлагаю взглянуть на ответ MiKTeX в следующей ветке, где был найден надежный метод: как дождаться окончания анимации matplotlib?

Ответ 16

Если я правильно понял вопрос, используя Ipython (или Ipython QT или ноутбук Ipython) позволит вам работать в интерактивном режиме с графиком, в то время как вычисления идут один в фоновом режиме. http://ipython.org/

Ответ 17

Если вы хотите открыть несколько рисунков, а при их открытии этот код работал у меня:

show(block=False)
draw()

Ответ 18

Вот обновление (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()

Ответ 19

ОП спрашивает об matplotlib участков matplotlib. Большинство ответов предполагают выполнение команды из интерпретатора Python. Вариант использования, представленный здесь, является моим предпочтением для тестирования кода в терминале (например, bash), где file.py и вы хотите, чтобы file.py но скрипт python завершался и возвращался в командную строку.

Этот автономный файл использует multiprocessing для запуска отдельного процесса для matplotlib данных с помощью matplotlib. Основной поток завершается с использованием os._exit(1) упомянутого в этом посте. os._exit() заставляет main выйти, но оставляет дочерний процесс matplotlib живым и отзывчивым, пока окно графика не закроется. Это отдельный процесс целиком.

Этот подход немного похож на сеанс разработки Matlab с графическими окнами, которые предлагают отзывчивую командную строку. При таком подходе вы потеряли все контакты с процессом окна рисунка, но это нормально для разработки и отладки. Просто закройте окно и продолжайте тестирование.

multiprocessing предназначена для выполнения кода только на Python, что делает его, возможно, более подходящим, чем subprocess. multiprocessing является кросс-платформенной, поэтому она должна хорошо работать в Windows или Mac без каких-либо настроек. Нет необходимости проверять основную операционную систему. Это было проверено на 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

При file.py открывается окно рисунка, затем __main__ matplotlib окно рисунка multiprocessing + matplotlib остается отзывчивым с кнопками масштабирования, панорамирования и других, потому что это независимый процесс.

Проверьте процессы в командной строке bash:

ps ax|grep -v grep |grep file.py

Ответ 20

Используйте plt.show(block=False), и в конце вашего скрипта вызовите plt.show().

Это гарантирует, что окно не будет закрыто после завершения скрипта.