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


258

파이썬 인터프리터에서 이러한 지시를 한 후 플롯이있는 창을 얻습니다.

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

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

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


5
16:52의 nosklo에서 선택한 솔루션이 작동하는지 확인할 수 없습니다. 나를 위해 그리기는 플롯을 표시하는 창을 열지 않으며 끝에 차단 쇼 만 솔루션을 표시합니다. 그러나 17:00의 답변은 정확합니다. 통해 대화식 모드를 ion()켜면 문제가 해결됩니다.
H. Brandsmeier

고급 프로그래머라면 사용할 수 os.fork()있지만 os.fork()이전 프로세스를 복사하여 새 프로세스를 작성하므로 사용 이 까다로울 수 있습니다.
Trevor Boyd Smith

답변:


214

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

28
하기 matplotlib 0.98.3 (가) 오른쪽 가져 오기 matplotlib.pyplot 가져 오기 줄거리입니다, 그려 보여
meteore

112
draw()나를 위해 작동하지 않습니다, 그것은 창을 열지 않습니다. 그러나 show(block=False)대신 대신 사용 draw()하면 matplotlib 1.1에서 트릭을 수행하는 것 같습니다.
rumpel

4
@nosklo, 봤어? 파이썬 튜토리얼
Jan

4
@noskolo 여러 인물이 있으면 배경을 계속하면서 Fig1을 플롯하고 표시하는 방법은 무엇입니까? 다음 그림이 생성 될 때 까지이 그림을 열고 싶습니다. 결국 모든 그림을 열고 코드가 완성되었습니다. 현재 솔루션을 사용하면 Fig1을 닫을 때까지 기다린 다음 코드가 계속 진행됩니다. 감사!!
physiker

9
draw()하나 나를 위해 작동하지 않았다, 단지 pause(0.001)한 : stackoverflow.com/questions/28269157/...
NumesSanguis

133

차단 동작을 무시하려면 키워드 'block'을 사용하십시오. 예 :

from matplotlib.pyplot import show, plot

plot(1)  
show(block=False)

# your code

코드를 계속합니다.


17
그러나 이것은 플롯 창을 즉시 닫고 플롯을 열어 두지 않습니다.
LWZ

8
예, 명령 줄에서 스크립트를 호출하면 사실입니다. Ipython 셸에 있으면 창이 닫히지 않습니다.
1

1
@Nico의 답변을 확인하여 일반적인 경우 창을 열어 두는 트릭을 찾으십시오.
Jan

2
나를 위해, 이것은 스크립트가 완료 될 때만 창을 즉시 닫지 않습니다 (따라서 스크립트를 열어두고 싶다면 수동으로 스크립트를 막을 수 있습니다).
luator

예, 스크립트가 종료되면 차단되지 않은 창이 닫힙니다 . (a) 마지막 플롯에서 차단을 허용하거나 (b) 스크립트를 종료하지 마십시오 (아마도 입력을 요청하십시오 : "<Enter>를 눌러 플롯을 종료하십시오"또는 이와 유사한 것).
Daniel Goldfarb

29

비 블로킹 방식으로 사용을 지원하는 경우 사용중인 라이브러리를 항상 확인하는 것이 좋습니다 .

그러나보다 일반적인 솔루션을 원하거나 다른 방법이 없다면 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 호출 )


감사! 필자는 아직 시스템에 Python 2.6이 없으므로 Threading.Thread를 Process의 대안으로 사용했습니다. 나는 후속 인쇄 진술이 참을 수 없을 정도로 느려지는 것을 관찰했습니다 (세 번째 인쇄, 1 분 대기 후 KeyboardInterrupt를 발행했습니다). 이것이 멀티 프로세싱 대신 스레딩을 사용하는 효과입니까?
meteor

@meteore : 그렇습니다. python <2.6의 멀티 프로세싱은 여기에서 항상 얻을 수 있습니다 : pyprocessing.berlios.de
nosklo

이것은 절대적으로 우수합니다. Emacs (파이썬 모드)에서 플롯 창이 닫힐 때까지 인쇄 명령문이 실행되지 않는 이유를 알고 있습니까?
2013 년

우분투 8.10 (인트 레 피드) 패키지에서 (파이썬 <2.6) 파이썬 처리라고하면 '수입 처리'로 가져
meteore

1
당신이 그리워하지 않았다 if __name__ == '__main__':?
Wernight

25

시험

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로 설정 될 수 있습니다.


draw ()를 사용하지 않는 이유; [. 다른 코드]; 보여 주다() ? 내가 아는 한 block = False는 더 이상 사용되지 않습니다
Bogdan

더 이상 사용되지 않는다고 생각하는 이유는 무엇입니까? 여기에 문서화되어 있습니다 .
Nico Schlömer

11

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

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

  1. show = block 내에서 block = 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()



8

필자의 경우 계산할 때 여러 개의 창이 나타나기를 원했습니다. 참고로이 방법은 다음과 같습니다.

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 인터페이스에 대한 유용한 안내서 입니다.


6

글쎄, 난 큰 문제가 비 차단 명령을 파악했다 ...하지만 마지막으로, 나는 재 작업 관리 " - 요리 책 /하기 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! 

이것이 누군가를 돕기를 바랍니다,
건배!


5

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

장점 :

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

약점:

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

많은 이미지를 생성하려고한다면 진심으로 동의합니다.
환상의

6
다시 그리기 png는 대화식이 아닙니다 : \
Inverse

5

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

plt.show(0)

어느 것이 동일합니다.


5

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

이것은 macOS의 matplotlib3에서 작동했습니다. 큰!
Jerry Ma

4

내 시스템에서 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)

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


감사합니다! Spyder는 시작할 때 -pylab을 가져 오며 일반적으로 유용하지만 ioff () 일 때 show ()가 차단되지 않음을 의미합니다. 이렇게하면이 동작을 해결할 수 있습니다!
잃었다

3

또한 오류가있는 경우에도 플롯이 나머지 코드를 실행하고 (표시를 계속 표시) 표시하기를 원했습니다 (때로는 디버깅을 위해 플롯을 사용합니다). 나는이 작은 해킹을 코딩 하여이 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 플로팅 출력을 일시 중지하려면 p를 누르십시오 (5 초) :"from /programming/26704840/corner -cases-for-my-wait-for-user-input-interruption-implementation .


2
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

16
하나의 프레스가 기존에 어떻게 들어가기 시작 했습니까?
grovina 2016 년

2

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


귀하의 솔루션을 사용하려고했지만 효과가없는 것처럼 보이며 이유를 알아 내려고 노력 중입니다. 터미널을 통해 코드를 실행하지 않고 Pycharm IDE에서 코드를 실행하고 있지만 차이는 없지만 그렇게해서는 안됩니다.
ttsesm

1
좋아, 마침내 나를 위해 일한 .daemon=False것은 여기에 설명 된대로 자식 프로세스를 설정하는 것이 었습니다. 그러나 stackoverflow.com/a/49607287/1476932 그러나 sys.exit()자식 창을 닫을 때까지 부모 프로세스를 종료하지 않았습니다. 반면에 os._exit(0)위의 예제를 사용하여 작동했습니다.
ttsesm


0

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

show(block=False)
draw()

show (block = False)는 더 이상 사용되지 않으며 더 이상 작동하지 않습니다
Bogdan

0

OP 요청에 직접 응답하지는 않지만이 해결 방법을 게시하면 다음과 같은 상황에서 누군가에게 도움이 될 수 있습니다.

  • 플롯을 생성 해야하는 곳에 파이썬을 설치할 수 없기 때문에 pyinstaller로 .exe를 생성하고 있습니다. 그래서 플롯을 생성하고 .png로 저장하고 닫고 다음 플롯을 계속하기 위해 파이썬 스크립트가 필요합니다. 루프 또는 함수 사용.

이 메신저를 사용하여 :

import matplotlib.pyplot as plt
#code generating the plot in a loop or function
#saving the plot
plt.savefig(var+'_plot.png',bbox_inches='tight', dpi=250) 
#you can allways reopen the plot using
os.system(var+'_plot.png') # unfortunately .png allows no interaction.
#the following avoids plot blocking the execution while in non-interactive mode
plt.show(block=False) 
#and the following closes the plot while next iteration will generate new instance.
plt.close() 

여기서 "var"은 루프에서 플롯을 식별하므로 덮어 쓰지 않습니다.


-1

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

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


@ nico-schlömer의 답변
Josh Wolff
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.