IT story

계산을 계속할 수 있도록 matplotlib 플롯을 분리하는 방법이 있습니까?

hot-time 2020. 4. 11. 10:12
반응형

계산을 계속할 수 있도록 matplotlib 플롯을 분리하는 방법이 있습니까?


파이썬 인터프리터에서 다음 명령을 수행하면 플롯이있는 창이 나타납니다.

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

불행히도, show()프로그램이 추가 계산을 수행 하는 동안 생성 된 그림을 대화 형으로 계속 탐색하는 방법을 모르겠습니다 .

전혀 가능합니까? 때로는 계산이 길고 중간 결과를 조사하는 동안 진행하면 도움이 될 것입니다.


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파이썬에 포함 된 모듈 을 사용하여 분리 된 프로세스에서 차단하는 것을 실행할 수 있습니다 . 계산은 계속됩니다 :

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블로킹 API 호출 )


시험

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 doesn't bail out
# before you finished examining.

show()문서는 말합니다 :

비 대화식 모드에서는 모든 그림을 표시하고 그림이 닫힐 때까지 차단하십시오. 대화식 모드에서는 비 대화식 모드에서 대화식 모드로 변경하기 전에 그림을 만들지 않는 한 효과가 없습니다 (권장되지 않음). 이 경우 수치는 표시되지만 차단되지는 않습니다.

단일 실험 키워드 인수 인 block은 위에서 설명한 차단 동작을 무시하기 위해 True 또는 False로 설정 될 수 있습니다.


중요 : 그냥 명확하게하기 위해. 나는 명령이 .py스크립트 안에 있고 스크립트 python script.py는 콘솔에서 예를 들어 사용 한다고 가정합니다 .

나를 위해 작동하는 간단한 방법은 다음과 같습니다.

  1. show = inside 내부 블록 = False : plt.show (block = False)
  2. .py 스크립트 끝에 다른 show () 사용하십시오 .

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


이 설명서를 matplotlib설명서에서 다음과 같이 읽을 수 있습니다 .

파이썬 쉘에서 matplotlib 사용


필자의 경우 계산할 때 여러 개의 창이 팝업되도록하고 싶었습니다. 참고로이 방법은 다음과 같습니다.

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

추신. matplotlib의 OO 인터페이스에 대한 매우 유용한 안내서 .


글쎄, 난 큰 문제가 비 차단 명령을 파악했다 ...하지만 마지막으로, 나는 재 작업 관리 " - 요리 책 /하기 matplotlib / 애니메이션을 선택한 플롯 요소 애니메이션 이 스레드 (작동, 그래서 예를 들어," 두 스레드 사이에 데이터를하고 통과Pipe Ubuntu 10.04의 Python 2.6.5에서 전역 변수 또는 다중 프로세스를 통해 )

이 스크립트는 여기에서 찾을 수 있습니다 : 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! 

이것이 누군가에게 도움이
되기를 바랍니다 , 건배!


대부분의 경우 이미지 를 하드 드라이브에 .png 파일로 저장하는 것이 더 편리합니다 . 이유는 다음과 같습니다.

장점 :

  • 프로세스에서 언제든지 열어서 살펴보고 닫을 수 있습니다. 응용 프로그램이 오랫동안 실행될 때 특히 편리합니다.
  • 아무것도 나타나지 않으며 창문을 열지 않아도됩니다. 이것은 많은 인물을 다룰 때 특히 편리합니다.
  • 나중에 참조 할 수 있도록 이미지에 액세스 할 수 있으며 Figure 창을 닫을 때 손실되지 않습니다.

약점:

  • 내가 생각할 수있는 유일한 것은 폴더를 찾아서 직접 찾아 이미지를 열어야한다는 것입니다.

콘솔에서 작업하는 경우 , 다른 답변에서 지적한대로 IPython사용할 수 있습니다 plt.show(block=False). 그러나 게으른 경우 다음을 입력하십시오.

plt.show(0)

어느 것이 동일합니다.


또한 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)

또한 오류가있는 경우에도 플롯이 나머지 코드를 실행하고 표시를 계속 표시하기를 원했습니다 (때로는 디버깅을 위해 플롯을 사용합니다). 이 작은 해킹을 코딩 하여이 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

적절한 "플롯을 열어두고 (오류가 발생하더라도) 새 플롯을 표시 할 수 있도록"구현하는 경우 사용자 간섭이없는 경우 (배치 실행 목적으로) 스크립트가 제대로 종료되기를 원합니다.

시간 초과 질문 "스크립트 끝! \ n 플로팅 출력을 일시 중지하려면 (5 초) p를 누르십시오."from 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

그러나 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)

스크립트가 여전히 실행되었지만.


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

내 의견으로는이 스레드의 답변은 모든 시스템에서 작동하지 않고 애니메이션과 같은보다 복잡한 상황에서 작동하지 않는 방법을 제공합니다. 강력한 방법을 찾은 다음 스레드에서 MiKTeX의 답을 살펴볼 것을 제안합니다. matplotlib 애니메이션이 끝날 때까지 기다리는 방법?


여러 그림을 모두 열어두고 여러 그림을 열려면이 코드가 효과적입니다.

show(block=False)
draw()

OP는 matplotlib플롯 분리 에 대해 묻습니다 . 대부분의 답변은 파이썬 인터프리터 내에서 명령 실행을 가정합니다. 여기에 제시된 유스 케이스는 터미널 file.py이 실행되고 (예 : bash) 코드가 테스트 되고 플롯이 나타나지만 파이썬 스크립트가 완료되고 명령 프롬프트로 돌아 가기를 원합니다.

이 독립형 파일은 multiprocessing로 데이터를 플로팅하기위한 별도의 프로세스를 시작하는 데 사용 됩니다 matplotlib. 에서 os._exit(1)언급 한 내용에 따라 메인 스레드가 종료됩니다 . main 강제로 종료하지만 플롯 창이 닫힐 때까지 자식 프로세스를 활성 상태로 유지합니다. 완전히 별도의 프로세스입니다.os._exit()matplotlib

이 접근 방식은 반응 형 명령 프롬프트가 표시되는 그림 창을 가진 Matlab 개발 세션과 약간 비슷합니다. 이 방법을 사용하면 Figure 창 프로세스와의 모든 연결이 끊어졌지만 개발 및 디버깅에는 적합합니다. 창을 닫고 테스트를 계속하십시오.

multiprocessing파이썬 전용 코드 실행을 위해 설계되었으므로보다 더 적합합니다 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__종료되지만 multiprocessing+ matplotlib그림 창이 독립적 인 프로세스이므로 확대 / 축소, 이동 및 기타 버튼으로 계속 반응합니다.

bash 명령 프롬프트에서 다음을 사용하여 프로세스를 확인하십시오.

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


plt.show(block=False)스크립트 호출이 끝날 때 사용하십시오 plt.show().

이렇게하면 스크립트가 완료 될 때 창이 닫히지 않습니다.

참고 URL : https://stackoverflow.com/questions/458209/is-there-a-way-to-detach-matplotlib-plots-so-that-the-computation-can-continue

반응형