matplotlib을 사용하여 while 루프에서 실시간으로 플롯하는 방법은 무엇입니까?


233

OpenCV를 사용하여 카메라의 일부 데이터를 실시간으로 플롯하려고합니다. 그러나 실시간 플로팅 (matplotlib 사용)이 작동하지 않는 것 같습니다.

이 간단한 예제로 문제를 격리했습니다.

fig = plt.figure()
plt.axis([0, 1000, 0, 1])

i = 0
x = list()
y = list()

while i < 1000:
    temp_y = np.random.random()
    x.append(i)
    y.append(temp_y)
    plt.scatter(i, temp_y)
    i += 1
    plt.show()

이 예제는 1000 점을 개별적으로 그릴 것으로 예상합니다. 실제로 발생하는 것은 첫 번째 점이 표시된 상태로 창이 팝업 된 다음 (그래도 괜찮음) 루프가 완료 될 때까지 기다렸다가 나머지 그래프를 채 웁니다.

한 번에 하나씩 포인트가 표시되지 않는 이유가 있습니까?

답변:


312

문제가되는 코드의 작동 버전은 다음과 같습니다 (2011-11-14의 Matplotlib 1.1.0 이상 버전 필요).

import numpy as np
import matplotlib.pyplot as plt

plt.axis([0, 10, 0, 1])

for i in range(10):
    y = np.random.random()
    plt.scatter(i, y)
    plt.pause(0.05)

plt.show()

일부 변경 사항에 유의하십시오.

  1. 전화 plt.pause(0.05)모두에 새 데이터를 그리고 그것은 (마우스 상호 작용을 허용)를 GUI의 이벤트 루프를 실행합니다.

3
이것은 Python2에서 나를 위해 일했습니다. Python3에서는 그렇지 않았습니다. 플롯 창을 렌더링 한 후 루프를 일시 중지합니다. 그러나 plt.show () 메소드를 루프 후로 이동 한 후 Python3에서는 해결되었습니다.
Continuousqa

1
이상한, 파이썬 3 (ver 3.4.0) Matplotlib (ver 1.3.1) Numpy (ver 1.8.1) Ubuntu Linux 3.13.0 64-bit에서 나에게 잘 작동했다
Velimir Mlaker

37
plt.show () 및 plt.draw () 대신 plt.draw ()를 plt.pause (0.1)로 바꾸십시오.
denfromufa

4
Win64 / Anaconda matplotlib .__ version__ 1.5.0에서 작동하지 않았습니다. 초기 도형 창이 열렸지만 아무 것도 표시하지 않았습니다. 닫을 때까지 차단 된 상태로 유지되었습니다
isti_spl

5
이 대답에는 x / y 데이터에 대한 사전 지식이 필요합니다 ... 필요하지 않습니다. 선호하는 것은 1. 전화 plt.axis()하지 않고 대신 두 개의 목록 x와 y를 만들고 2를 호출 plt.plot(x,y)하여 새 데이터 값을 추가하십시오. 두 목록 3. 전화plt.gca().lines[0].set_xdata(x); plt.gca().lines[0].set_ydata(y); plt.gca().relim(); plt.gca().autoscale_view(); plt.pause(0.05);
트레버 보이드 스미스

76

실시간 플로팅에 관심이 있으시면 matplotlib의 애니메이션 API를 살펴 보는 것이 좋습니다 . 특히, blit모든 프레임에서 배경을 다시 그리지 않도록 사용 하면 상당한 속도 향상 (~ 10x)을 얻을 수 있습니다.

#!/usr/bin/env python

import numpy as np
import time
import matplotlib
matplotlib.use('GTKAgg')
from matplotlib import pyplot as plt


def randomwalk(dims=(256, 256), n=20, sigma=5, alpha=0.95, seed=1):
    """ A simple random walk with memory """

    r, c = dims
    gen = np.random.RandomState(seed)
    pos = gen.rand(2, n) * ((r,), (c,))
    old_delta = gen.randn(2, n) * sigma

    while True:
        delta = (1. - alpha) * gen.randn(2, n) * sigma + alpha * old_delta
        pos += delta
        for ii in xrange(n):
            if not (0. <= pos[0, ii] < r):
                pos[0, ii] = abs(pos[0, ii] % r)
            if not (0. <= pos[1, ii] < c):
                pos[1, ii] = abs(pos[1, ii] % c)
        old_delta = delta
        yield pos


def run(niter=1000, doblit=True):
    """
    Display the simulation using matplotlib, optionally using blit for speed
    """

    fig, ax = plt.subplots(1, 1)
    ax.set_aspect('equal')
    ax.set_xlim(0, 255)
    ax.set_ylim(0, 255)
    ax.hold(True)
    rw = randomwalk()
    x, y = rw.next()

    plt.show(False)
    plt.draw()

    if doblit:
        # cache the background
        background = fig.canvas.copy_from_bbox(ax.bbox)

    points = ax.plot(x, y, 'o')[0]
    tic = time.time()

    for ii in xrange(niter):

        # update the xy data
        x, y = rw.next()
        points.set_data(x, y)

        if doblit:
            # restore background
            fig.canvas.restore_region(background)

            # redraw just the points
            ax.draw_artist(points)

            # fill in the axes rectangle
            fig.canvas.blit(ax.bbox)

        else:
            # redraw everything
            fig.canvas.draw()

    plt.close(fig)
    print "Blit = %s, average FPS: %.2f" % (
        str(doblit), niter / (time.time() - tic))

if __name__ == '__main__':
    run(doblit=False)
    run(doblit=True)

산출:

Blit = False, average FPS: 54.37
Blit = True, average FPS: 438.27

1
@bejota 원래 버전은 대화식 matplotlib 세션 내에서 작동하도록 설계되었습니다. 이 독립형 스크립트로 작동하려면 그것의 필요 1)은 명시 적으로하기 matplotlib를위한 백엔드를 선택하고 2)를 사용하여 애니메이션 루프를 입력하기 전에 그림 표시 그려 질 강제로 plt.show()plt.draw(). 위 코드에 이러한 변경 사항을 추가했습니다.
ali_m

2
의 의도 / 동기 부여 blit()가 "실시간 플로팅 향상"인 것 같습니까? matplotlib 개발자 / 블로그가있는 이유 / 목적 / 의도 / 동기 부여가 좋은 이유에 대해 설명합니다. (이 새로운 블리트 작업은 Matplotlib을 오프라인 또는 매우 느리게 변경되는 데이터로만 사용하도록 변환하는 것으로 보이며 지금은 오실로스코프와 같이 매우 빠른 업데이트 데이터로 Matplotlib를 사용할 수 있습니다).
Trevor Boyd Smith

1
이 접근 방식으로 플롯 창이 응답하지 않습니다. 상호 작용할 수 없으며 충돌 할 수 있습니다.
Ninjakannon

1
"gtk를 찾을 수 없음"문제가 발생하는 경우 다른 백엔드에서 제대로 작동합니다 ( 'TKAgg'를 사용했습니다). 지원되는 백업을 찾으려면이 솔루션을 사용했습니다 : stackoverflow.com/questions/3285193/…
James Nelson

1
이 답변의 링크가 더 이상 작동하지 않는 것 같습니다. 이 링크는 최신 링크 일 수 있습니다. scipy-cookbook.readthedocs.io/items/…
awelkie

35

이 질문에 대답하기에 조금 늦었다는 것을 알고 있습니다. 그럼에도 불구하고, 나는 라이브 그래프를 플롯하기 위해 얼마 전에 코드를 만들었습니다.

PyQt4 코드 :

###################################################################
#                                                                 #
#                    PLOT A LIVE GRAPH (PyQt4)                    #
#                  -----------------------------                  #
#            EMBED A MATPLOTLIB ANIMATION INSIDE YOUR             #
#            OWN GUI!                                             #
#                                                                 #
###################################################################


import sys
import os
from PyQt4 import QtGui
from PyQt4 import QtCore
import functools
import numpy as np
import random as rd
import matplotlib
matplotlib.use("Qt4Agg")
from matplotlib.figure import Figure
from matplotlib.animation import TimedAnimation
from matplotlib.lines import Line2D
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import time
import threading


def setCustomSize(x, width, height):
    sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(x.sizePolicy().hasHeightForWidth())
    x.setSizePolicy(sizePolicy)
    x.setMinimumSize(QtCore.QSize(width, height))
    x.setMaximumSize(QtCore.QSize(width, height))

''''''

class CustomMainWindow(QtGui.QMainWindow):

    def __init__(self):

        super(CustomMainWindow, self).__init__()

        # Define the geometry of the main window
        self.setGeometry(300, 300, 800, 400)
        self.setWindowTitle("my first window")

        # Create FRAME_A
        self.FRAME_A = QtGui.QFrame(self)
        self.FRAME_A.setStyleSheet("QWidget { background-color: %s }" % QtGui.QColor(210,210,235,255).name())
        self.LAYOUT_A = QtGui.QGridLayout()
        self.FRAME_A.setLayout(self.LAYOUT_A)
        self.setCentralWidget(self.FRAME_A)

        # Place the zoom button
        self.zoomBtn = QtGui.QPushButton(text = 'zoom')
        setCustomSize(self.zoomBtn, 100, 50)
        self.zoomBtn.clicked.connect(self.zoomBtnAction)
        self.LAYOUT_A.addWidget(self.zoomBtn, *(0,0))

        # Place the matplotlib figure
        self.myFig = CustomFigCanvas()
        self.LAYOUT_A.addWidget(self.myFig, *(0,1))

        # Add the callbackfunc to ..
        myDataLoop = threading.Thread(name = 'myDataLoop', target = dataSendLoop, daemon = True, args = (self.addData_callbackFunc,))
        myDataLoop.start()

        self.show()

    ''''''


    def zoomBtnAction(self):
        print("zoom in")
        self.myFig.zoomIn(5)

    ''''''

    def addData_callbackFunc(self, value):
        # print("Add data: " + str(value))
        self.myFig.addData(value)



''' End Class '''


class CustomFigCanvas(FigureCanvas, TimedAnimation):

    def __init__(self):

        self.addedData = []
        print(matplotlib.__version__)

        # The data
        self.xlim = 200
        self.n = np.linspace(0, self.xlim - 1, self.xlim)
        a = []
        b = []
        a.append(2.0)
        a.append(4.0)
        a.append(2.0)
        b.append(4.0)
        b.append(3.0)
        b.append(4.0)
        self.y = (self.n * 0.0) + 50

        # The window
        self.fig = Figure(figsize=(5,5), dpi=100)
        self.ax1 = self.fig.add_subplot(111)


        # self.ax1 settings
        self.ax1.set_xlabel('time')
        self.ax1.set_ylabel('raw data')
        self.line1 = Line2D([], [], color='blue')
        self.line1_tail = Line2D([], [], color='red', linewidth=2)
        self.line1_head = Line2D([], [], color='red', marker='o', markeredgecolor='r')
        self.ax1.add_line(self.line1)
        self.ax1.add_line(self.line1_tail)
        self.ax1.add_line(self.line1_head)
        self.ax1.set_xlim(0, self.xlim - 1)
        self.ax1.set_ylim(0, 100)


        FigureCanvas.__init__(self, self.fig)
        TimedAnimation.__init__(self, self.fig, interval = 50, blit = True)

    def new_frame_seq(self):
        return iter(range(self.n.size))

    def _init_draw(self):
        lines = [self.line1, self.line1_tail, self.line1_head]
        for l in lines:
            l.set_data([], [])

    def addData(self, value):
        self.addedData.append(value)

    def zoomIn(self, value):
        bottom = self.ax1.get_ylim()[0]
        top = self.ax1.get_ylim()[1]
        bottom += value
        top -= value
        self.ax1.set_ylim(bottom,top)
        self.draw()


    def _step(self, *args):
        # Extends the _step() method for the TimedAnimation class.
        try:
            TimedAnimation._step(self, *args)
        except Exception as e:
            self.abc += 1
            print(str(self.abc))
            TimedAnimation._stop(self)
            pass

    def _draw_frame(self, framedata):
        margin = 2
        while(len(self.addedData) > 0):
            self.y = np.roll(self.y, -1)
            self.y[-1] = self.addedData[0]
            del(self.addedData[0])


        self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ])
        self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin]))
        self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin])
        self._drawn_artists = [self.line1, self.line1_tail, self.line1_head]

''' End Class '''

# You need to setup a signal slot mechanism, to 
# send data to your GUI in a thread-safe way.
# Believe me, if you don't do this right, things
# go very very wrong..
class Communicate(QtCore.QObject):
    data_signal = QtCore.pyqtSignal(float)

''' End Class '''


def dataSendLoop(addData_callbackFunc):
    # Setup the signal-slot mechanism.
    mySrc = Communicate()
    mySrc.data_signal.connect(addData_callbackFunc)

    # Simulate some data
    n = np.linspace(0, 499, 500)
    y = 50 + 25*(np.sin(n / 8.3)) + 10*(np.sin(n / 7.5)) - 5*(np.sin(n / 1.5))
    i = 0

    while(True):
        if(i > 499):
            i = 0
        time.sleep(0.1)
        mySrc.data_signal.emit(y[i]) # <- Here you emit a signal!
        i += 1
    ###
###


if __name__== '__main__':
    app = QtGui.QApplication(sys.argv)
    QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Plastique'))
    myGUI = CustomMainWindow()
    sys.exit(app.exec_())

''''''

 
최근에 PyQt5의 코드를 다시 작성했습니다.
PyQt5 코드 :

###################################################################
#                                                                 #
#                    PLOT A LIVE GRAPH (PyQt5)                    #
#                  -----------------------------                  #
#            EMBED A MATPLOTLIB ANIMATION INSIDE YOUR             #
#            OWN GUI!                                             #
#                                                                 #
###################################################################

import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import functools
import numpy as np
import random as rd
import matplotlib
matplotlib.use("Qt5Agg")
from matplotlib.figure import Figure
from matplotlib.animation import TimedAnimation
from matplotlib.lines import Line2D
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import time
import threading

class CustomMainWindow(QMainWindow):
    def __init__(self):
        super(CustomMainWindow, self).__init__()
        # Define the geometry of the main window
        self.setGeometry(300, 300, 800, 400)
        self.setWindowTitle("my first window")
        # Create FRAME_A
        self.FRAME_A = QFrame(self)
        self.FRAME_A.setStyleSheet("QWidget { background-color: %s }" % QColor(210,210,235,255).name())
        self.LAYOUT_A = QGridLayout()
        self.FRAME_A.setLayout(self.LAYOUT_A)
        self.setCentralWidget(self.FRAME_A)
        # Place the zoom button
        self.zoomBtn = QPushButton(text = 'zoom')
        self.zoomBtn.setFixedSize(100, 50)
        self.zoomBtn.clicked.connect(self.zoomBtnAction)
        self.LAYOUT_A.addWidget(self.zoomBtn, *(0,0))
        # Place the matplotlib figure
        self.myFig = CustomFigCanvas()
        self.LAYOUT_A.addWidget(self.myFig, *(0,1))
        # Add the callbackfunc to ..
        myDataLoop = threading.Thread(name = 'myDataLoop', target = dataSendLoop, daemon = True, args = (self.addData_callbackFunc,))
        myDataLoop.start()
        self.show()
        return

    def zoomBtnAction(self):
        print("zoom in")
        self.myFig.zoomIn(5)
        return

    def addData_callbackFunc(self, value):
        # print("Add data: " + str(value))
        self.myFig.addData(value)
        return

''' End Class '''


class CustomFigCanvas(FigureCanvas, TimedAnimation):
    def __init__(self):
        self.addedData = []
        print(matplotlib.__version__)
        # The data
        self.xlim = 200
        self.n = np.linspace(0, self.xlim - 1, self.xlim)
        a = []
        b = []
        a.append(2.0)
        a.append(4.0)
        a.append(2.0)
        b.append(4.0)
        b.append(3.0)
        b.append(4.0)
        self.y = (self.n * 0.0) + 50
        # The window
        self.fig = Figure(figsize=(5,5), dpi=100)
        self.ax1 = self.fig.add_subplot(111)
        # self.ax1 settings
        self.ax1.set_xlabel('time')
        self.ax1.set_ylabel('raw data')
        self.line1 = Line2D([], [], color='blue')
        self.line1_tail = Line2D([], [], color='red', linewidth=2)
        self.line1_head = Line2D([], [], color='red', marker='o', markeredgecolor='r')
        self.ax1.add_line(self.line1)
        self.ax1.add_line(self.line1_tail)
        self.ax1.add_line(self.line1_head)
        self.ax1.set_xlim(0, self.xlim - 1)
        self.ax1.set_ylim(0, 100)
        FigureCanvas.__init__(self, self.fig)
        TimedAnimation.__init__(self, self.fig, interval = 50, blit = True)
        return

    def new_frame_seq(self):
        return iter(range(self.n.size))

    def _init_draw(self):
        lines = [self.line1, self.line1_tail, self.line1_head]
        for l in lines:
            l.set_data([], [])
        return

    def addData(self, value):
        self.addedData.append(value)
        return

    def zoomIn(self, value):
        bottom = self.ax1.get_ylim()[0]
        top = self.ax1.get_ylim()[1]
        bottom += value
        top -= value
        self.ax1.set_ylim(bottom,top)
        self.draw()
        return

    def _step(self, *args):
        # Extends the _step() method for the TimedAnimation class.
        try:
            TimedAnimation._step(self, *args)
        except Exception as e:
            self.abc += 1
            print(str(self.abc))
            TimedAnimation._stop(self)
            pass
        return

    def _draw_frame(self, framedata):
        margin = 2
        while(len(self.addedData) > 0):
            self.y = np.roll(self.y, -1)
            self.y[-1] = self.addedData[0]
            del(self.addedData[0])

        self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ])
        self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin]))
        self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin])
        self._drawn_artists = [self.line1, self.line1_tail, self.line1_head]
        return

''' End Class '''


# You need to setup a signal slot mechanism, to
# send data to your GUI in a thread-safe way.
# Believe me, if you don't do this right, things
# go very very wrong..
class Communicate(QObject):
    data_signal = pyqtSignal(float)

''' End Class '''



def dataSendLoop(addData_callbackFunc):
    # Setup the signal-slot mechanism.
    mySrc = Communicate()
    mySrc.data_signal.connect(addData_callbackFunc)

    # Simulate some data
    n = np.linspace(0, 499, 500)
    y = 50 + 25*(np.sin(n / 8.3)) + 10*(np.sin(n / 7.5)) - 5*(np.sin(n / 1.5))
    i = 0

    while(True):
        if(i > 499):
            i = 0
        time.sleep(0.1)
        mySrc.data_signal.emit(y[i]) # <- Here you emit a signal!
        i += 1
    ###
###

if __name__== '__main__':
    app = QApplication(sys.argv)
    QApplication.setStyle(QStyleFactory.create('Plastique'))
    myGUI = CustomMainWindow()
    sys.exit(app.exec_())

그냥 사용해보십시오. 이 코드를 새 파이썬 파일에 복사하여 붙여 넣고 실행하십시오. 아름답고 부드럽게 움직이는 그래프가 나타납니다.

여기에 이미지 설명을 입력하십시오


dataSendLoop창을 닫을 때 스레드가 백그라운드에서 계속 실행되는 것으로 나타났습니다 . 그래서 daemon = True그 문제를 해결하기 위해 키워드를 추가했습니다 .
K.Mulier

1
이를위한 가상 환경은 약간의 작업이 필요했습니다. 마지막으로 conda install pyqt=4트릭을 수행했습니다.
Reb. Cabin

1
기본 코드에 감사드립니다. 코드를 기반으로 기능을 수정하고 추가하여 간단한 UI를 구축하는 데 도움이되었습니다. 그것은 내 시간을 구했다 =]
Isaac Sim

안녕하세요 @IsaacSim, 당신의 친절한 메시지에 대단히 감사합니다. 이 코드가 도움이되었다 니 행복합니다 :-)
K.Mulier

그래서이 스크립트를 가져 와서 np.ndarry 유형을 사용하도록 신호 슬롯 메커니즘을 수정하고 상대 타임 스탬프 및 신호의 np.array를 방출하여 x 축에 타임 스탬프를 추가했습니다. 각 프레임 그리기에서 xlim ()을 업데이트하여 새 축으로 신호를 표시하는 데 적합하지만 x-labels / ticks는 창 크기를 변경할 때 간단히 업데이트되지 않습니다. @ K.Mulier 기본적으로 데이터와 같은 슬라이딩 xtick 축을 따라 왔으며 이와 같은 것에 성공했는지 궁금하십니까?
nimig18

33

show아마도 이것이 최선의 선택이 아닙니다. 내가 할 일은 pyplot.draw()대신 사용하는 것입니다. 또한 time.sleep(0.05)플롯에 작은 시간 지연 (예 :)을 포함 시켜 플롯이 발생하는 것을 볼 수 있습니다. 예제를 변경하면 효과가 있으며 각 포인트가 한 번에 하나씩 나타납니다.


10
나는 코드의 매우 유사한 부분을 가지고 있으며, 솔루션을 시도 할 때 (쇼 및 시간 지연 대신 그리기) 파이썬은 그림 창을 전혀 열지 않고 루프를
통과

31

어떤 방법도 나를 위해 일하지 않았습니다. 그러나 루프에서 여전히 실시간 matplotlib 플롯이 작동하지 않는 것을 발견했습니다.

당신이 필요로 추가

plt.pause(0.0001)

새 줄거리를 볼 수 있습니다.

따라서 코드는 다음과 같아야 작동합니다.

import matplotlib.pyplot as plt
import numpy as np
plt.ion() ## Note this correction
fig=plt.figure()
plt.axis([0,1000,0,1])

i=0
x=list()
y=list()

while i <1000:
    temp_y=np.random.random();
    x.append(i);
    y.append(temp_y);
    plt.scatter(i,temp_y);
    i+=1;
    plt.show()
    plt.pause(0.0001) #Note this correction

6
이것은 매번 새로운 그림 / 플롯 창을 열어 기존 그림을 업데이트하는 방법이 있습니까? 어쩌면 imshow를 사용하고 있을까요?
Francisco Vargas

@FranciscoVargas imshow를 사용하는 경우 set_data를 사용해야합니다. 여기를보십시오 : stackoverflow.com/questions/17835302/…
Oren

22

상단 (및 다른 많은) 답변은 위에 작성 plt.pause()되었지만 matplotlib에서 플롯을 애니메이션으로 만드는 오래된 방법이었습니다. 속도가 느릴뿐만 아니라 각 업데이트마다 포커스가 잡히게됩니다 (플로팅 파이썬 프로세스를 중지하는 데 어려움을 겪었습니다).

TL; DR :matplotlib.animation ( 문서에 언급 된대로) 사용하고 싶을 수도 있습니다 .

다양한 답변과 코드 조각을 파고 들었을 때 실제로 이것은 들어오는 데이터를 무한히 그리는 매끄러운 방법으로 판명되었습니다.

다음은 빠른 시작을위한 코드입니다. 뷰의 자동 크기 조정을 처리하면서 200ms마다 [0, 100)의 난수로 현재 시간을 플로팅합니다.

from datetime import datetime
from matplotlib import pyplot
from matplotlib.animation import FuncAnimation
from random import randrange

x_data, y_data = [], []

figure = pyplot.figure()
line, = pyplot.plot_date(x_data, y_data, '-')

def update(frame):
    x_data.append(datetime.now())
    y_data.append(randrange(0, 100))
    line.set_data(x_data, y_data)
    figure.gca().relim()
    figure.gca().autoscale_view()
    return line,

animation = FuncAnimation(figure, update, interval=200)

pyplot.show()

FuncAnimation 문서에서와 같이blit 더 나은 성능 탐색 할 수도 있습니다 .

blit설명서 의 예 :

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')

def init():
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)
    return ln,

def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    ln.set_data(xdata, ydata)
    return ln,

ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
                    init_func=init, blit=True)
plt.show()

안녕하세요, 이것이 모두 반복되면 어떻게 될까요? 말한다 for i in range(1000): x,y = some func_func(). 여기 some_func()에 온라인 x,y데이터 쌍이 생성 됩니다. 그것은 가능한이 작업을 수행하는 것입니다 FuncAnimation. 내 목표는 각 반복마다 단계별로 데이터로 정의 된 곡선을 만드는 것입니다.
Alexander Cska

@Alexander Cska 님 pyploy.show()을 차단해야합니다. 데이터를 추가하려면 데이터를 검색하고 update함수 에서 업데이트하십시오 .
Hai Zhang

나는 당신의 대답을 정말로 이해하지 못할 것이라 걱정합니다. 당신의 제안을 증폭 시키시겠습니까?
Alexander Cska

pyplot.show루프 를 호출하면이 호출 에 의해 루프가 차단되고 계속되지 않습니다. 단계별로 데이터를 곡선에 추가하려면 논리를에 넣으십시오. 이 또한 update매번 호출 interval되므로 단계별로 수행됩니다.
Hai Zhang

Zhang의 코드는 콘솔에서 작동하지만 jupyter에서는 작동하지 않습니다. 나는 단지 빈 줄거리를 얻는다. 사실, 순차 루프에서 jupyter로 배열을 채우고 pet.plot 문으로 자라면서 배열을 인쇄하면 배열에서 개별적으로 인쇄 할 수 있지만 하나의 플롯 만 얻을 수 있습니다. 이 코드를 참조하십시오 : gist.github.com/bwanaaa/12252cf36b35fced0eb3c2f64a76cb8a
aquagremlin

15

나는이 질문이 오래 되었다는 것을 알고 있지만 GitHub에 drawnow 라는 패키지 가 "python-drawnow"로 제공됩니다. 이것은 MATLAB의 drawow와 유사한 인터페이스를 제공합니다 . 그림을 쉽게 업데이트 할 수 있습니다 .

사용 사례의 예 :

import matplotlib.pyplot as plt
from drawnow import drawnow

def make_fig():
    plt.scatter(x, y)  # I think you meant this

plt.ion()  # enable interactivity
fig = plt.figure()  # make a figure

x = list()
y = list()

for i in range(1000):
    temp_y = np.random.random()
    x.append(i)
    y.append(temp_y)  # or any arbitrary update to your figure's data
    i += 1
    drawnow(make_fig)

python-drawnow는 얇은 래퍼 plt.draw이지만 그림 표시 후 확인 (또는 디버그) 기능을 제공합니다.


이것은 tk를 어딘가에 매달리게한다
chwi

그렇다면 더 많은 컨텍스트 github.com/scottsievert/python-drawnow/issues
Scott

+1 이것은 matplotlib가 얼어 붙은 동안 opencv에서 비디오 캡처 프레임 당 라이브 데이터를 플로팅하는 데 효과적이었습니다.
jj080808

나는 이것을 시도했고 다른 방법보다 느리게 보였다.
Dave C

사용하지 않음, 내 서버 재부팅, matplotlib 고정
big-vl

6

문제 plt.show()는 창을 표시 한 다음 돌아올 것으로 예상 되는 것 같습니다 . 그렇게하지 않습니다. 해당 시점에서 프로그램이 중지되고 창을 닫으면 다시 시작됩니다. 다음을 테스트 할 수 있어야합니다. 창을 닫으면 다른 창이 나타납니다.

이 문제를 해결하려면 plt.show()루프 후 한 번만 호출 하십시오. 그런 다음 완전한 음모를 얻습니다. (그러나 '실시간 플로팅'은 아님)

키워드 인수를 다음 block과 같이 설정해 볼 수 있습니다 plt.show(block=False). 처음에 한 번 .draw()업데이트 한 후 사용하십시오 .


1
실시간 플로팅은 내가 원하는 것입니다. 나는 무언가에 대해 5 시간 동안 테스트를 진행하고 상황이 어떻게 진행되고 있는지보고 싶습니다.
크리스

@Chris는 5 시간 동안 테스트를 수행 할 수 있었습니까? 나는 또한 비슷한 것을 찾고 있습니다. 플롯을 업데이트하기 위해 plyplot.pause (time_duration)를 사용하고 있습니다. 다른 방법이 있습니까?
Prakhar Mohan Srivastava

4

다음은 시스템에서 작동해야하는 버전입니다.

import matplotlib.pyplot as plt
from drawnow import drawnow
import numpy as np

def makeFig():
    plt.scatter(xList,yList) # I think you meant this

plt.ion() # enable interactivity
fig=plt.figure() # make a figure

xList=list()
yList=list()

for i in np.arange(50):
    y=np.random.random()
    xList.append(i)
    yList.append(y)
    drawnow(makeFig)
    #makeFig()      The drawnow(makeFig) command can be replaced
    #plt.draw()     with makeFig(); plt.draw()
    plt.pause(0.001)

drawnow (makeFig) 줄을 makeFig ()로 바꿀 수 있습니다. plt.draw () 순서와 여전히 작동합니다.


1
일시 정지 시간을 어떻게 알 수 있습니까? 플롯 자체에 의존하는 것으로 보입니다.
CMCDragonkai

1

더 많은 점이 그려 질 때 스레드를 그리지 않고 고정시키지 않으려면 time.sleep ()이 아닌 plt.pause ()를 사용해야합니다

im은 다음 코드를 사용하여 일련의 xy 좌표를 플로팅합니다.

import matplotlib.pyplot as plt 
import math


pi = 3.14159

fig, ax = plt.subplots()

x = []
y = []

def PointsInCircum(r,n=20):
    circle = [(math.cos(2*pi/n*x)*r,math.sin(2*pi/n*x)*r) for x in xrange(0,n+1)]
    return circle

circle_list = PointsInCircum(3, 50)

for t in range(len(circle_list)):
    if t == 0:
        points, = ax.plot(x, y, marker='o', linestyle='--')
        ax.set_xlim(-4, 4) 
        ax.set_ylim(-4, 4) 
    else:
        x_coord, y_coord = circle_list.pop()
        x.append(x_coord)
        y.append(y_coord)
        points.set_data(x, y)
    plt.pause(0.01)

1

또 다른 옵션은 bokeh 와 함께하는 것입니다 . IMO는 최소한 실시간 플롯에 대한 좋은 대안입니다. 문제의 코드 보케 버전은 다음과 같습니다.

from bokeh.plotting import curdoc, figure
import random
import time

def update():
    global i
    temp_y = random.random()
    r.data_source.stream({'x': [i], 'y': [temp_y]})
    i += 1

i = 0
p = figure()
r = p.circle([], [])
curdoc().add_root(p)
curdoc().add_periodic_callback(update, 100)

그리고 그것을 실행하기 위해 :

pip3 install bokeh
bokeh serve --show test.py

bokeh는 웹 소켓 통신을 통한 웹 브라우저의 결과를 보여줍니다. 원격 헤드리스 서버 프로세스에서 데이터를 생성 할 때 특히 유용합니다.

보케 샘플 플롯


0

CPU 사용을 실시간으로 표시하는 사용 사례의 예입니다.

import time
import psutil
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

i = 0
x, y = [], []

while True:
    x.append(i)
    y.append(psutil.cpu_percent())

    ax.plot(x, y, color='b')

    fig.canvas.draw()

    ax.set_xlim(left=max(0, i - 50), right=i + 50)
    fig.show()
    plt.pause(0.05)
    i += 1

약 2 분 후에 속도가 느려지기 시작합니다. 이유는 무엇입니까? 현재보기를 벗어나는 이전 지점은 삭제해야합니다.
pfabri

이것은 정말 좋아 보이지만 몇 가지 문제가 있습니다. 1. 종료 할 수 없습니다 2. 몇 분 후 프로그램은 거의 100Mb의 RAM을 소비하고 속도가 크게 느려지기 시작합니다.
pfabri
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.