Matplotlib kullanarak bir döngüde gerçek zamanlı olarak nasıl çizim yapabilirim?


233

OpenCV kullanarak gerçek zamanlı olarak bir kameradan bazı verileri çizmeye çalışıyorum. Ancak, gerçek zamanlı çizim (matplotlib kullanarak) işe yaramıyor gibi görünüyor.

Sorunu bu basit örneğe ayırdım:

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

Bu örneğin 1000 puanı tek tek çizmesini beklerim. Aslında olan şey, pencerenin ilk noktayı (bununla ok) göstermesiyle ortaya çıkması, daha sonra grafiğin geri kalanını doldurmadan önce döngünün bitmesini beklemesidir.

Neden teker teker puan toplandığını görmediğim hakkında bir fikrin var mı?

Yanıtlar:


313

Söz konusu kodun çalışan sürümü (en azından 2011-11-14'ten Matplotlib 1.1.0 sürümünü gerektirir):

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

Bazı değişikliklere dikkat edin:

  1. plt.pause(0.05)Her iki yeni veriyi çekmek için çağrı yapın ve GUI'nin olay döngüsünü çalıştırır (fare etkileşimi sağlar).

3
Bu benim için Python2'de çalıştı. Python3'te olmadı. Çizim penceresini oluşturduktan sonra döngüyü duraklatacaktır. Ama plt.show () yöntemini döngüden sonra taşıdıktan sonra ... benim için Python3 için çözdü.
continuousqa

1
Tuhaf, benim için iyi çalıştı Python 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 () ve plt.draw () yerine plt.draw () yerine plt.pause (0.1)
denfromufa

4
Win64 / Anaconda matplotlib .__ version__ 1.5.0 üzerinde çalışmadı. Bir ilk şekil penceresi açıldı, ancak hiçbir şey görüntülemedi, ben kapatana kadar engellenmiş bir durumda kaldı
isti_spl

5
Bu cevap x / y verileri hakkında a priori bilgisi gerektirir ... gerekli değildir: 1. tercih etmiyorum plt.axis()ama bunun yerine iki liste x ve y oluşturun ve döngünüzde plt.plot(x,y)2'yi arayın , yeni veri değerlerini ekleyin iki liste 3. çağrı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

Gerçek zamanlı çizim ile ilgileniyorsanız, matplotlib'in animasyon API'sına bakmanızı tavsiye ederim . Özellikle, blitarka planı her karede yeniden çizmekten kaçınmak, size önemli hız kazanımları sağlayabilir (~ 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)

Çıktı:

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

1
@bejota Orijinal sürüm etkileşimli bir matplotlib oturumunda çalışacak şekilde tasarlanmıştır. Bu tek başına bir komut dosyası olarak çalışmasını sağlamak için, en gerekli 1'e kadar) açıkça matplotlib için bir arka uç seçin ve 2) kullanılarak animasyon döngüsünün girmeden önce şekil gösterilir ve çekilecek zorlamak plt.show()ve plt.draw(). Bu değişiklikleri yukarıdaki koda ekledim.
ali_m

2
Görünüşün niyeti / motivasyonu blit()"gerçek zamanlı çizimi iyileştirmek" gibi görünüyor mu? Neden harika bir neden / amaç / niyet / motivasyon tartışan bir matplotlib geliştirici / blogunuz varsa. (Bu yeni blit işlemi, Matplotlib'i sadece çevrimdışı veya çok yavaş değişen veriler için kullanımdan dönüştürecek gibi görünüyor, Matplotlib'i çok hızlı güncelleme verileriyle kullanabilirsiniz ... neredeyse bir osiloskop gibi).
Trevor Boyd Smith

1
Bu yaklaşımın çizim penceresini yanıt vermediğini fark ettim: Onunla etkileşime giremiyorum ve bunu yapmak çökebilir.
Ninjakannon

1
"Gtk bulunamadı" sorunu elde edenler için, farklı bir arka uç ile iyi çalışıyor ('TKAgg' kullandım). Desteklenen bir destek bulmak için bu çözümü kullandım: stackoverflow.com/questions/3285193/…
James Nelson

1
Bu yanıttaki bağlantı artık çalışmıyor gibi görünüyor. Bu güncel bir bağlantı olabilir: scipy-cookbook.readthedocs.io/items/…
awelkie

35

Bu soruya cevap vermek için biraz geç kaldığımı biliyorum. Yine de, paylaşmak istiyorum ki, canlı grafikler çizmek için bir süre önce bazı kod yaptım:

PyQt4 kodu:

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

''''''

 
Geçenlerde PyQt5 kodunu yeniden yazdım.
PyQt5 için kod:

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

Sadece dene. Bu kodu yeni bir python dosyasına kopyalayıp yapıştırın ve çalıştırın. Güzel ve sorunsuz bir grafik elde etmelisiniz:

resim açıklamasını buraya girin


dataSendLoopPencereyi kapattığınızda iş parçacığının arka planda çalışmaya devam ettiğini fark ettim . Bu daemon = Truesorunu çözmek için anahtar kelimeyi ekledim .
K.Mulier

1
Bunun için sanal ortam biraz iş aldı. Sonunda, conda install pyqt=4hile yaptı.
Reb.Cabin

1
Temel kod için çok teşekkürler. Kodunuza bağlı olarak özellikleri değiştirerek ve ekleyerek basit bir kullanıcı arayüzü oluşturmama yardımcı oldu. Zamanımı kurtardı =]
Isaac Sim

Merhaba @IsaacSim, nazik mesajınız için çok teşekkür ederim. Bu kod yardımcı oldu mutluyum :-)
K.Mulier

Bu yüzden bu betiği aldım ve sinyal yuvası mekanizmasını bir np.ndarry türü kullanmak ve göreceli zaman damgası ve sinyalin bir np.array'ı yayarak x eksenine zaman damgaları ekledim. Yeni eksen ile sinyal görüntülemek için iyi her çerçeve çizmek xlim () güncelliyorum ama pencere boyutu değiştirdiğinizde x-etiketleri / keneler sadece kısa bir süre güncelleme. @ K.Mulier Temelde veriler gibi kayan bir xtick ekseni peşindeyim ve böyle bir şeyde başarılı olup olmadığınızı merak ediyor muydunuz?
nimig18

33

showmuhtemelen bunun için en iyi seçim değildir. Bunun pyplot.draw()yerine kullanmak istiyorum . Ayrıca time.sleep(0.05), çizimlerin gerçekleştiğini görebilmeniz için, döngüye küçük bir zaman gecikmesi (ör. ) Eklemek isteyebilirsiniz. Örneğinizde bu değişiklikleri yaparsam benim için işe yarar ve her noktanın birer birer göründüğünü görüyorum.


10
Kodun çok benzer bir parçasına sahibim ve çözümünüzü denediğimde (gösteri ve zaman gecikmesi yerine çizin) python bir şekil penceresi açmıyor, sadece döngüye giriyor ...
George Aprilis

31

Metodların hiçbiri benim için işe yaramadı. Ama bu Gerçek zamanlı matplotlib grafiğinin hala bir döngüdeyken çalışmadığını gördüm

Tek ihtiyacınız olan eklemektir

plt.pause(0.0001)

ve sonra yeni grafikleri görebiliyordunuz.

Yani kodunuz şöyle görünmeli ve çalışacaktır

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
Bu benim için her seferinde yeni bir şekil / çizim penceresi açar Sadece mevcut şekli güncellemenin bir yolu var mı? belki onun imshow kullanıyorum çünkü?
Francisco Vargas

@FranciscoVargas, imshow kullanıyorsanız, set_data kullanmanız gerekiyor, buraya bakın: stackoverflow.com/questions/17835302/…
Oren

22

En iyi (ve diğer birçok) cevaplar üzerine inşa edildi plt.pause(), ancak bu matplotlib'deki arsaları canlandırmanın eski bir yoluydu. Sadece yavaş değil, aynı zamanda her güncellemeye odaklanmaya da neden oluyor (python sürecini durdurmakta zorlandım).

TL; DR: kullanmak isteyebilirsiniz matplotlib.animation( belgelerde belirtildiği gibi ).

Çeşitli cevapları ve kod parçalarını araştırdıktan sonra, bu aslında benim için gelen verileri sonsuz bir şekilde çizmenin düzgün bir yolu olduğunu kanıtladı.

İşte hızlı bir başlangıç ​​için kodum. Geçerli zamanı, her 200 ms'de bir rastgele sayı ile [0, 100) sonsuz olarak çizer ve aynı zamanda görünümün otomatik olarak yeniden ölçeklendirilmesini sağlar:

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

Ayrıca FuncAnimation belgelerinde olduğu gibiblit daha iyi performans için de araştırma yapabilirsiniz .

blitBelgelerden bir örnek :

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

Merhaba, eğer bu bir döngü içinde olsaydı ne olacak. demek for i in range(1000): x,y = some func_func(). Burada , kullanılabilir olduklarında çizmek istediğim some_func()çevrimiçi x,yveri çiftleri oluşturur . Bunu yapmak mümkün mü FuncAnimation? Amacım, veri ile tanımlanan eğriyi her bir yinelemeyle adım adım oluşturmak.
Alexander Cska

@Alexander Cska pyploy.show()engellenmeli. Veri eklemek istiyorsanız, bunları alın ve updateişlevde güncelleyin .
Hai Zhang

Cevabınızı gerçekten anlamadığımdan korkuyorum. Lütfen önerinizi güçlendirir misiniz?
Alexander Cska

Yani, pyplot.showbir döngü içinde ararsanız , döngü bu çağrı tarafından engellenir ve devam etmez. Verileri eğriye adım adım eklemek istiyorsanız update, her biri çağrılacak olan mantığını girin , intervalböylece adım adım da.
Hai Zhang

Zhang'ın kodu konsoldan çalışır ancak jupyter'da çalışmaz. Orada boş bir arsa alıyorum. Aslında, ben sıralı bir döngü içinde jupyter bir dizi doldurmak ve bir pet.plot deyimi ile büyür gibi dizi yazdırmak, ben tek tek diziler ayrı ayrı bir baskı alabilirsiniz. bu kodu görün: gist.github.com/bwanaaa/12252cf36b35fced0eb3c2f64a76cb8a
aquagremlin

15

Bu sorunun eski olduğunu biliyorum, ama şimdi GitHub'da "python-drawnow" olarak çizilmiş bir paket var . Bu, MATLAB'ın çizimine benzer bir arayüz sağlar - bir şekli kolayca güncelleyebilirsiniz.

Kullanım durumunuz için bir örnek:

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 etrafı ince bir sargıdır, plt.drawancak şekil gösteriminden sonra onaylama (veya hata ayıklama) olanağı sağlar.


Bu tk bir yere asmak yapar
chwi

Öyleyse, daha fazla bağlamla ilgili bir sorun gönderin github.com/scottsievert/python-drawnow/issues
Scott

+1 Bu benim için opencv video yakalama karesi başına canlı veri çizmek için çalıştı, matplotlib dondu.
jj080808

Bunu denedim ve diğer yöntemlerden daha yavaş görünüyordu.
Dave C

kullanmayın, sunucumu yeniden başlatın, matplotlib dondurulmuş
big-vl

6

Sorun plt.show(), pencereyi göstermek ve sonra geri dönmek için bekliyoruz gibi görünüyor . Bunu yapmaz. Program bu noktada durur ve yalnızca pencereyi kapattıktan sonra devam eder. Bunu test edebilmeniz gerekir: Pencereyi kapatırsanız ve başka bir pencere açılırsa.

Bu sorunu çözmek için, plt.show()döngünüzden sonra yalnızca bir kez arayın . Sonra tüm komployu elde edersiniz. (Ama 'gerçek zamanlı çizim' değil)

Anahtar kelime bağımsız değişkenini şu şekilde ayarlamayı deneyebilirsiniz block: plt.show(block=False)başlangıçta bir kez ve ardından .draw()güncellemek için kullanın .


1
gerçek zamanlı çizim gerçekten istediğim şey. Bir şey üzerinde 5 saatlik bir test yapacağım ve işlerin nasıl ilerlediğini görmek istiyorum.
Chris

@Chris 5 saatlik testi yapabildin mi? Ben de benzer bir şey arıyorum. Grafiği güncellemek için plyplot.pause (time_duration) kullanıyorum. Bunu yapmanın başka bir yolu var mı?
Prakhar Mohan Srivastava

4

İşte benim sistemim üzerinde çalışmam gereken bir versiyon.

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)

Çekilen satır (makeFig) satırı bir makeFig () ile değiştirilebilir; plt.draw () dizisi ve hala iyi çalışıyor.


1
Ne kadar duraklatacağını nereden biliyorsun? Planın kendisine bağlı gibi görünüyor.
CMCDragonkai

1

Daha fazla nokta çizildiği gibi ipliğinizi çizmek ve dondurmamak istiyorsanız, time.sleep () yerine plt.pause () kullanmalısınız.

im bir xy koordinatları dizisi çizmek için aşağıdaki kodu kullanarak.

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

Başka bir seçenek bokeh ile gitmek . IMO, en azından gerçek zamanlı grafikler için iyi bir alternatiftir. Sorudaki kodun bokeh versiyonu:

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)

ve çalıştırmak için:

pip3 install bokeh
bokeh serve --show test.py

bokeh sonucu web tarayıcı soketi üzerinden bir web tarayıcısında gösterir. Verilerin uzak başsız sunucu işlemleri tarafından üretilmesi özellikle yararlıdır.

bokeh örnek çizimi


0

CPU kullanımını gerçek zamanlı olarak çizmek için örnek bir kullanım örneği.

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

Yaklaşık 2 dakika sonra gerçekten yavaşlamaya başlar. Sebep ne olabilir? Belki de mevcut görüşün dışında kalan daha önceki noktalar bırakılmalıdır.
pfabri

Bu gerçekten hoş görünüyor, ancak bununla ilgili birkaç sorun var: 1. çıkmak imkansız 2. sadece birkaç dakika sonra program yaklaşık 100 Mb RAM tüketir ve önemli ölçüde yavaşlamaya başlar.
pfabri
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.