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

나는 지난 며칠 동안 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()

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



답변

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

당신 (그리고 나)이 원하는 것을 얻으려면 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()


답변


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

  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()내 스크립트의 마지막 줄입니다.


답변

플롯을 배열에 쓴 다음 배열을 다른 스레드에 표시하여 실행을 차단하지 않을 수 있습니다. 다음은 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 배열에 플롯 저장


답변

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

원한다면 사용할 수 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의 답변을 사용 하여이 사실을 알 수
있기를 바랍니다. 이는 누군가가 별도의 스레드에서 모든 단일 그림을 시작 하거나이 소설을 읽지 않아도이를 구할 수 있기를 바랍니다.


답변

라이브 플로팅

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, 비 차단


답변

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


답변

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