Matplotlib을 사용하여 비 차단 방식으로 플로팅


138

나는 지난 며칠 동안 Numpy와 matplotlib을 가지고 놀았습니다. matplotlib 플롯을 실행 차단하지 않고 함수로 만드는 데 문제가 있습니다. 나는 비슷한 질문을하는 SO에 이미 많은 스레드가 있다는 것을 알고 있으며, 많은 것을 구글 검색했지만이 작업을 수행하지는 못했습니다.

일부 사람들이 제안한대로 show (block = False)을 사용해 보았지만 얻는 것은 고정 된 창입니다. 단순히 show ()를 호출하면 결과가 올바르게 표시되지만 창이 닫힐 때까지 실행이 차단됩니다. 내가 읽은 다른 스레드에서 show (block = False) 작동 여부는 백엔드에 따라 달라집니다. 이 올바른지? 백엔드는 Qt4Agg입니다. 내 코드를보고 문제가 있는지 말해 주시겠습니까? 여기 내 코드가 있습니다. 도움을 주셔서 감사합니다.

from math import *
from matplotlib import pyplot as plt
print plt.get_backend()



def main():
    x = range(-50, 51, 1)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4

        y = [Xi**pow for Xi in x]
        print y

        plt.plot(x, y)
        plt.draw()
        #plt.show()             #this plots correctly, but blocks execution.
        plt.show(block=False)   #this creates an empty frozen window.
        _ = raw_input("Press [enter] to continue.")


if __name__ == '__main__':
    main()

추신. 새 창을 만드는 대신 무언가를 그릴 때마다 기존 창을 업데이트하고 싶다고 말하지 않았습니다.


1
plt.ion()전에 matplotlib 대화식 모드를 사용해 보셨습니까 plt.show()? 그런 다음 각 플롯이 자식 스레드로 생성 될 때 차단되지 않아야합니다.
Anzel

@Anzel 방금 시도했지만 아무런 차이가없는 것 같습니다.
opetroch

3
스크립트를 어떻게 실행하고 있습니까? 터미널 / 명령 프롬프트에서 예제 코드를 실행하면 정상적으로 작동하는 것 같지만 IPython QtConsole 또는 IDE에서 이와 같은 작업을 수행하려고 할 때 과거에 문제가 있다고 생각합니다.
Marius

1
@ 마리우스 아하 !! 네 말이 맞아 실제로 내 IDE (PyCharm)의 콘솔에서 실행 중입니다. cmd 프롬프트에서 plt.show (block = False)를 실행하면 정상적으로 작동합니다! 당신이 그것에 대한 아이디어 / 해결책을 찾았는지 물어 보면 너무 많이 물어볼 것입니까? 고마워요!
opetroch

정말 죄송합니다. matplotlib이 콘솔과 상호 작용하는 방법에 대한 세부 정보를 실제로 이해하지 못하므로 일반적으로이 작업을 수행 해야하는 경우 명령 프롬프트에서 실행으로 전환하십시오 matplotlib.
Marius

답변:


167

나는 해결책을 찾기 위해 오랜 시간을 보냈고이 대답을 찾았습니다 .

당신 (그리고 나)이 원하는 것을 얻으려면 plt.ion(), plt.show()(와 함께 block=False아님)과 가장 중요하게 plt.pause(.001)(또는 원하는 시간 ) 의 조합이 필요합니다 . 일시 정지는 주요 코드는 그림을 포함, 자고있는 동안 GUI의 이벤트가 발생하기 때문에 필요하다. 이것이 수면 스레드에서 시간을 가져옴으로써 구현 될 가능성이 있기 때문에 IDE가 그것을 망칠 수도 있습니다.

다음은 Python 3.5에서 작동하는 구현입니다.

import numpy as np
from matplotlib import pyplot as plt

def main():
    plt.axis([-50,50,0,10000])
    plt.ion()
    plt.show()

    x = np.arange(-50, 51)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4
        y = [Xi**pow for Xi in x]
        plt.plot(x, y)
        plt.draw()
        plt.pause(0.001)
        input("Press [enter] to continue.")

if __name__ == '__main__':
    main()

3
귀하의 답변은 내가 겪었던 비슷한 문제를 해결하는 데 많은 도움이되었습니다. 이전에는 plt.draw따라 plt.show(block = False)왔지만 작동이 멈췄습니다. 그림이 응답하지 않아 iPython이 종료되었습니다. 내 솔루션은의 모든 인스턴스를 제거 plt.draw()하고로 교체했습니다 plt.pause(0.001). 이전 에 plt.show(block = False)like 를 사용하는 대신 plt.draw이전에 plt.ion()and가 plt.show()있었습니다. 나는 지금 가지고 MatplotlibDeprecationWarning있지만 내 그림을 그릴 수있게 해주었 으므로이 솔루션에 만족합니다.
blue_chip

3
파이썬 2.7에서는 raw_inputnot 을 사용해야 input합니다. 참조 여기에
크리스

반응성 "애니메이션"접근이 불가능할 때 실제로 유용한 해결 방법! 사용 중단 경고를 제거하는 방법을 아는 사람이 있습니까?
Frederic Fortier

plt.show 전에 plt.ion을 추가하려고 할 때 왜 freezen 명령 프롬프트가 표시되는지 알려주십시오.
가브리엘 아우 구스토

@GabrielAugusto 나는 그것이 무엇을 일으킬 수 있는지 잘 모르겠으며, 당신이 무엇을 의미하는지 잘 모르겠습니다. 방금 Python 3.6 에서이 예제를 테스트했지만 여전히 작동합니다. 동일한 패턴을 사용하여 고정 된 경우 설치에 문제가있을 수 있습니다. 일반 플로팅이 먼저 작동하는지 확인해야합니다. 다른 것을 시도했다면 의견에 대해 할 일이별로 없습니다. 두 경우 모두 별도의 질문을 고려할 수 있습니다.
krs013

23

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

  1. show 내부 에서 block = False 인수를 사용하십시오 . plt.show (block = False)
  2. .py 스크립트 끝에 다른 plt.show () 사용하십시오 .

:

import matplotlib.pyplot as plt

plt.imshow(add_something)
plt.xlabel("x")
plt.ylabel("y")

plt.show(block=False)

#more code here (e.g. do calculations and use print to see them on the screen

plt.show()

참고 : plt.show()내 스크립트의 마지막 줄입니다.


7
이렇게하면 (Linux의 경우 Anaconda, Python 2.7, 기본 백엔드) 창이 생성되어 실행이 끝날 때까지 빈 채로 유지됩니다. :-(
sh37211

@ sh37211 목표가 확실하지 않습니다. 일부를 플롯하려고 시도하지만 plot 명령 뒤에 다른 명령이 있으면 다른 명령을 플롯하고 실행할 수 있으므로 유용합니다. 이에 대한 자세한 내용은이 게시물을 참조 stackoverflow.com/questions/458209/... . 플롯을 업데이트하려면 다른 방법이어야합니다.
seralouk

17

플롯을 배열에 쓴 다음 배열을 다른 스레드에 표시하여 실행을 차단하지 않을 수 있습니다. 다음은 pyformulas 0.2.8의 pf.screen을 사용하여 플롯을 동시에 생성하고 표시하는 예입니다 .

import pyformulas as pf
import matplotlib.pyplot as plt
import numpy as np
import time

fig = plt.figure()

canvas = np.zeros((480,640))
screen = pf.screen(canvas, 'Sinusoid')

start = time.time()
while True:
    now = time.time() - start

    x = np.linspace(now-2, now, 100)
    y = np.sin(2*np.pi*x) + np.sin(3*np.pi*x)
    plt.xlim(now-2,now+1)
    plt.ylim(-3,3)
    plt.plot(x, y, c='black')

    # If we haven't already shown or saved the plot, then we need to draw the figure first...
    fig.canvas.draw()

    image = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
    image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))

    screen.update(image)

#screen.close()

결과:

사인 애니메이션

면책 조항 : 저는 pyformulas의 관리자입니다.

참조 : Matplotlib : numpy 배열에 플롯 저장


9

이 답변 중 많은 부분이 초조 해져 있으며 내가 찾을 수있는 것만으로도 답을 이해하기가 어렵지는 않습니다.

원한다면 사용할 수 plt.ion()있지만plt.draw() 효과적인만큼 했습니다.

내 특정 프로젝트를 위해 나는 이미지를하려 해요,하지만 당신은 사용할 수 있습니다 plot()또는 scatter()또는 대신 무엇이든 figimage(), 그것은 중요하지 않습니다.

plt.figimage(image_to_show)
plt.draw()
plt.pause(0.001)

또는

fig = plt.figure()
...
fig.figimage(image_to_show)
fig.canvas.draw()
plt.pause(0.001)

실제 수치를 사용하는 경우.
@ krs013을 사용하여 @Default Picture의 답변을 사용 하여이 사실을 알 수
있기를 바랍니다. 이는 누군가가 별도의 스레드에서 모든 단일 그림을 시작 하거나이 소설을 읽지 않아도이를 구할 수 있기를 바랍니다.


3

라이브 플로팅

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 100)
# plt.axis([x[0], x[-1], -1, 1])      # disable autoscaling
for point in x:
    plt.plot(point, np.sin(2 * point), '.', color='b')
    plt.draw()
    plt.pause(0.01)
# plt.clf()                           # clear the current figure

데이터 양이 너무 많으면 간단한 카운터로 업데이트 속도를 낮출 수 있습니다

cnt += 1
if (cnt == 10):       # update plot each 10 points
    plt.draw()
    plt.pause(0.01)
    cnt = 0

프로그램 종료 후 플롯 유지

이것은 만족스러운 답변을 찾을 수 없었던 실제 문제였습니다. MATLAB과 같이 스크립트가 끝난 후에 닫히지 않는 음모를 꾸미고 싶었습니다.

그것에 대해 생각하면 스크립트가 완료된 후 프로그램이 종료되고 플롯을 이런 식으로 유지할 논리적 인 방법이 없으므로 두 가지 옵션이 있습니다.

  1. 스크립트가 종료되는 것을 차단하십시오 (필자가 아닌 plt.show ()입니다)
  2. 별도의 스레드에서 플롯을 실행하십시오 (너무 복잡함)

이것은 나에게 만족스럽지 않았으므로 상자 밖에서 다른 해결책을 찾았습니다.

SaveToFile 및 외부 뷰어에서보기

이를 위해 저장 및보기가 빨라야하고 뷰어가 파일을 잠그지 않아야하며 컨텐츠를 자동으로 업데이트해야합니다.

저장할 형식 선택

벡터 기반 형식은 작고 빠릅니다.

  • SVG 는 훌륭하지만 기본적으로 수동 새로 고침이 필요한 웹 브라우저를 제외하고는 좋은 뷰어를 찾지 못했습니다.
  • PDF 는 벡터 형식을 지원할 수 있으며 실시간 업데이트를 지원하는 경량 뷰어가 있습니다

라이브 업데이트가 포함 된 빠른 경량 뷰어

들어 PDF 여러 가지 좋은 옵션이 있습니다

  • Windows 에서는 무료로 빠르고 가벼운 SumatraPDF 를 사용합니다 (필자의 경우 1.8MB RAM 만 사용함)

  • Linux에는 Evince (GNOME) 및 Ocular (KDE) 와 같은 몇 가지 옵션이 있습니다.

샘플 코드 및 결과

플롯을 파일로 출력하기위한 샘플 코드

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(2 * x)
plt.plot(x, y)
plt.savefig("fig.pdf")

처음 실행 한 후에는 위에서 언급 한 뷰어 중 하나에서 출력 파일을 열고 즐기십시오.

여기 SumatraPDF와 함께 VSCode의 스크린 샷이 있으며 프로세스는 반 라이브 업데이트 속도를 얻을 수있을 정도로 빠릅니다 ( time.sleep()간격을 사용하면 설정에서 약 10Hz를 얻을 수 있습니다 ) pyPlot, 비 차단


2

Iggy의 대답 은 내가 따라 가기 가장 쉬운 것이지만, 내가 할 때 subplot없었던 후속 명령을 수행 할 때 다음 오류가 발생했습니다 show.

MatplotlibDeprecationWarning : 이전 축과 동일한 인수를 사용하여 축을 추가하면 현재 이전 인스턴스가 재사용됩니다. 이후 버전에서는 항상 새 인스턴스가 만들어지고 반환됩니다. 한편, 각 축 인스턴스에 고유 한 레이블을 전달하여이 경고를 억제하고 향후 동작을 보장 할 수 있습니다.

이 오류를 피하기 위해 사용자가 Enter 키를 누른 후 줄거리 를 닫거나 지우는 데 도움이됩니다 .

나를 위해 일한 코드는 다음과 같습니다.

def plt_show():
    '''Text-blocking version of plt.show()
    Use this instead of plt.show()'''
    plt.draw()
    plt.pause(0.001)
    input("Press enter to continue...")
    plt.close()

0

그려진 Python 패키지를 사용하면 비 차단 방식으로 플롯을 실시간으로 업데이트 할 수 있습니다.
또한 웹캠 및 OpenCV와 함께 작동하여 각 프레임에 대한 측정 값을 플롯합니다. 원본 게시물을
참조하십시오 .

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