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ポイントを個別にプロットすることを期待しています。実際に何が起こるかというと、ウィンドウがポップアップして最初のポイントが表示され(それで問題ありません)、ループが終了するのを待ってから、グラフの残りの部分にデータが入力されます。

ポイントが1つずつ表示されないのはなぜですか?

回答:


313

ここに問題のコードの作業バージョンがあります(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
奇妙なことに、Python 3(バージョン3.4.0)Matplotlib(バージョン1.3.1)Numpy(バージョン1.8.1)Ubuntu Linux 3.13.0 64ビット
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()代わりに、2つのリストxとyを作成し、2を呼び出しますplt.plot(x,y)。ループで、新しいデータ値を追加します2つのリスト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);
Trevor Boyd Smith

76

リアルタイムプロットに興味がある場合は、matplotlibのアニメーションAPIを調べることをお勧めします。特に、blitすべてのフレームで背景を再描画しないように使用すると、速度が大幅に向上します(約10倍)。

#!/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開発者/ブログを持っているなら、それが理由/目的/意図/動機について議論するのは素晴らしいことです。(この新しいblit操作は、Matplotlibをオフラインまたは非常にゆっくりと変化するデータの使用のみから、非常に高速な更新データでMatplotlibを使用できるように変換するようです...ほとんどオシロスコープのようです)。
Trevor Boyd Smith

1
この方法では、プロットウィンドウが応答しなくなることがわかりました。操作できないため、クラッシュする可能性があります。
Ninjakannon、2016

1
「gtk not found」問題が発生する場合は、別のバックエンドでも問題なく機能します(「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_())

試してみてください。このコードをコピーして新しいpythonファイルに貼り付け、実行します。美しく滑らかに動くグラフが得られるはずです。

ここに画像の説明を入力してください


dataSendLoopウィンドウを閉じると、スレッドがバックグラウンドで実行され続けることに気づきました。そこで、daemon = Trueその問題を解決するためのキーワードを追加しました。
K.Mulier 2016

1
このための仮想環境には少し手間がかかりました。最後にconda install pyqt=4、トリックをしました。
Reb.Cabin

1
基本的なコードをたくさんありがとう。コードに基づいて機能を変更および追加することで、いくつかの単純なUIを構築するのに役立ちました。時間を節約できました=]
Isaac Sim

こんにちは@IsaacSim、あなたの親切なメッセージをありがとうございました。このコードがお
役に立て

したがって、このスクリプトを使用して、np.ndarryタイプを使用するようにシグナルスロットメカニズムを変更し、相対タイムスタンプとシグナルのnp.arrayを発行することにより、x軸にタイムスタンプを追加しました。各フレーム描画でxlim()を更新していますが、新しい軸で信号を表示するには問題ありませんが、ウィンドウサイズを変更したときにx-labels / ticksが短時間しか更新されません。@ K.Mulier基本的には、データのようなスライディングxtick軸の後で、このような何かで成功したかどうか疑問に思っていましたか?
nimig18

33

showこれはおそらく最良の選択ではありません。pyplot.draw()代わりに使用します。発生してtime.sleep(0.05)いるプロットを確認できるように、ループに小さな時間遅延(たとえば、)を含めることもできます。私があなたの例にこれらの変更を加えた場合、それは私にとってはうまくいき、各点が一度に1つずつ表示されるのがわかります。


10
私はコードの非常に似た部分を持っています。あなたの解決策(表示と時間遅延の代わりに描画)を試すと、Pythonは図ウィンドウをまったく開かず、ループを通過します...
George Aprilis

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/...
オレン

22

上位(および他の多くの)回答はに基づいていますがplt.pause()、それはmatplotlibでプロットをアニメーション化する古い方法でした。これは遅いだけでなく、更新ごとにフォーカスを取得する原因にもなります(pythonプロセスのプロットを停止するのに苦労しました)。

TL; DR:使用したい場合がありますmatplotlib.animationドキュメントに記載されているように)。

さまざまな答えとコードの一部を掘り下げた後、これは実際、着信データを無限に描画するスムーズな方法であることがわかりました。

これがクイックスタート用の私のコードです。ビューの自動再スケーリングも処理しながら、[0、100)の乱数で200ミリ秒ごとに現在の時刻をプロットします。

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ステートメントで配列を拡大して出力すると、配列から個別に出力できますが、プロットは1つだけです。次のコードを参照してください:gist.github.com/bwanaaa/12252cf36b35fced0eb3c2f64a76cb8a
aquagremlin

15

私はこの質問が古いことを知っていますが、GitHubに "python-drawnow"としてdrawnowと呼ばれるパッケージが利用可能になりました。これにより、MATLABのdrawnowと同様のインターフェイスが提供されます。図を簡単に更新できます

ユースケースの例:

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 2015年

その場合は、より多くのコンテキストgithub.com/scottsievert/python-drawnow/issuesで
Scott

+1これは、matplotlibがフリーズしているときに、opencvからのビデオキャプチャのフレームごとにライブデータをプロットするのに役立ちました。
jj080808 2017

私はこれを試しました、そしてそれは他の方法より遅いようでした。
Dave C

使用しないでください、サーバーを再起動し、matplotlibをフリーズしました
big-vl

6

問題はplt.show()、ウィンドウを表示してから戻ることを期待しているようです。それはしません。プログラムはその時点で停止し、ウィンドウを閉じると再開します。テストできるはずです。ウィンドウを閉じると、別のウィンドウがポップアップします。

この問題を解決するplt.show()には、ループの後で1回だけ呼び出します。次に、完全なプロットを取得します。(しかし、「リアルタイムプロット」ではありません)

次のblockようにキーワード引数を設定してみてください。plt.show(block=False)最初に一度、それから.draw()更新に使用します。


1
リアルタイムのプロットは私が本当に目指していることです。私は何かに対して5時間のテストを実行するつもりであり、物事がどのように進行しているかを確認したいと思います。
Chris

@クリスは5時間のテストを行うことができましたか?私も似たようなものを探しています。plyplot.pause(time_duration)を使用してプロットを更新しています。そうする他の方法はありますか?
Prakhar Mohan Srivastava 2014

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 2018年

1

より多くのポイントが描画されたときにスレッドをフリーズせずに描画したい場合は、time.sleep()ではなくplt.pause()を使用する必要があります

次のコードを使用して一連のxy座標をプロットするim。

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

別のオプションは、ボケと一緒に行くことです。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

ボケはウェブソケット通信を介してウェブブラウザに結果を表示します。これは、リモートヘッドレスサーバープロセスによってデータが生成される場合に特に役立ちます。

ボケサンプルプロット


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.数分後にプログラムはほぼ100 MbのRAMを消費し、劇的にスローダウンし始めます。
pfabri
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.