मैं matplotlib का उपयोग करते हुए थोड़ी देर के लूप में वास्तविक समय में कैसे साजिश रचूं?


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
यह मेरे लिए पायथन 2 में काम किया। पायथन 3 में यह नहीं था। यह प्लॉट विंडो को रेंडर करने के बाद लूप को रोक देगा। लेकिन लूप के बाद plt.show () विधि को स्थानांतरित करने के बाद ... इसने इसे मेरे लिए Python3 के लिए हल किया।
सतत

1
अजीब, पायथन 3 (ver 3.4.0) में मेरे लिए ठीक काम किया, Matplotlib (ver 1.3.1) Numpy (ver 1.8.1) उबंटू लिनक्स 3.13.0 64-बिट
वेलिमल Mlaker

37
plt.show () और plt.draw () के बजाय plt.draw () को plt.pause (0.1) से
बदलें

4
Win64 / Anaconda matplotlib .__ वर्जन__ 1.5.0 पर काम नहीं किया। एक प्रारंभिक आंकड़ा विंडो खुली, लेकिन कुछ भी प्रदर्शित नहीं हुआ, यह एक अवरुद्ध स्थिति में रहा जब तक मैंने इसे बंद नहीं किया
isti_spl

5
इस उत्तर के लिए x / y डेटा का पूर्व-ज्ञान आवश्यक है ... जिसकी आवश्यकता नहीं है: मुझे पसंद है 1. कॉल न करें plt.axis(), बल्कि दो सूचियां x और y बनाएं और कॉल करें 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);
ट्रेवर बॉयड स्मिथ

76

यदि आप रियलटाइम प्लॉटिंग में रुचि रखते हैं, तो मैं आपको matplotlib के एनीमेशन एपीआई में देखने की सलाह दूंगा । विशेष रूप से, 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()। मैंने इन परिवर्तनों को ऊपर दिए गए कोड में जोड़ दिया है।
अली_म

2
क्या blit()"वास्तविक समय में साजिश रचने" में सुधार करने का इरादा / प्रेरणा बहुत अधिक है? यदि आप एक matplotlib डेवलपर / ब्लॉग पर चर्चा कर रहे हैं कि क्यों / उद्देश्य / इरादा / प्रेरणा महान होगा। (ऐसा लगता है कि यह नया ब्लिट ऑपरेशन केवल ऑफ़लाइन या बहुत धीरे-धीरे बदलते डेटा के लिए केवल उपयोग से Matplotlib को बदल देगा। आप बहुत तेजी से अपडेट होने वाले डेटा के साथ Matplotlib का उपयोग कर सकते हैं ... लगभग एक आस्टसीलस्कप की तरह)।
ट्रेवर बॉयड स्मिथ

1
मैंने पाया है कि यह दृष्टिकोण प्लॉट विंडो को गैर-जिम्मेदार बनाता है: मैं इसके साथ बातचीत नहीं कर सकता, और ऐसा करने से यह दुर्घटनाग्रस्त हो सकता है।
निन्जाकन्नन

1
"Gtk नहीं मिला" समस्या वाले लोगों के लिए, यह एक अलग बैक-एंड के साथ ठीक काम करता है (मैंने 'TKAgg' का इस्तेमाल किया)। एक समर्थित समर्थित को खोजने के लिए मैंने इस समाधान का उपयोग किया: stackoverflow.com/questions/3285193/…
जेम्स नेल्सन

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उस मुद्दे को हल करने के लिए कीवर्ड जोड़ा ।
मलियर

1
इसके लिए आभासी वातावरण ने थोड़ा काम लिया। अंत में, conda install pyqt=4चाल चली।
रेब.कबिन

1
बुनियादी कोड के लिए बहुत बहुत धन्यवाद। इसने मुझे आपके कोड के आधार पर कुछ सरल यूआई को संशोधित करने और सुविधाओं को जोड़ने में मदद की। इसने मेरा समय बचाया] =]
आइजैक सिम

हाय @IsaacSim, अपनी तरह के संदेश के लिए बहुत बहुत धन्यवाद। मुझे खुशी है कि यह कोड उपयोगी था :-)
K.Mulier

इसलिए मैंने इस स्क्रिप्ट को लिया है और एक np.ndarry प्रकार और रिश्तेदार टाइमस्टैम्प और सिग्नल के np.array का उपयोग करने के लिए सिग्नल स्लॉट तंत्र को संशोधित करके एक्स-अक्ष में टाइमस्टैम्प जोड़ा है। मैं प्रत्येक फ्रेम ड्रॉ पर xlim () को अपडेट कर रहा हूं जो सिग्नल को नए एक्सिस के साथ प्रदर्शित करने के लिए ठीक है लेकिन जब मैं विंडो का आकार बदलता हूं तो केवल एक्स-लेबल / टिक केवल अपडेट नहीं करता है। @ 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 का उपयोग कर रहा हूँ?
फ्रांसिस्को वर्गास

@FranciscoVargas यदि आप imshow का उपयोग कर रहे हैं, तो आपको set_data का उपयोग करने की आवश्यकता है, यहां देखें: stackoverflow.com/questions/17835302/…
Oren

22

शीर्ष (और कई अन्य) उत्तरों का निर्माण किया गया था plt.pause(), लेकिन यह मैटलपोटलिब में प्लॉट को एनिमेट करने का एक पुराना तरीका था। यह न केवल धीमा है, बल्कि प्रत्येक अद्यतन पर ध्यान केंद्रित करने का कारण बनता है (मुझे प्लॉटिंग पाइथ प्रक्रिया को रोकना कठिन समय था)।

TL; DR: आप उपयोग करना चाहते हैं matplotlib.animation( जैसा कि प्रलेखन में उल्लेख किया गया है )।

विभिन्न उत्तरों और कोड के टुकड़ों के आसपास खुदाई करने के बाद, यह वास्तव में मेरे लिए आने वाले डेटा को ड्राइंग करने का एक आसान तरीका साबित हुआ।

यहाँ एक त्वरित शुरुआत के लिए मेरा कोड है। यह वर्तमान समय में एक यादृच्छिक संख्या के साथ प्लॉट करता है [0, 100) प्रत्येक 200ms में असीम रूप से, जबकि दृश्य के ऑटो rescaling को भी संभालते हुए:

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। मेरा लक्ष्य प्रत्येक पुनरावृत्ति के साथ कदम से कदम डेटा द्वारा परिभाषित वक्र का निर्माण करना है।
अलेक्जेंडर सेस्का

@ अलेक्सेंडर Cska pyploy.show()को ब्लॉक करना चाहिए। यदि आप डेटा को जोड़ना चाहते हैं, तो उन्हें पुनः प्राप्त करें और updateफ़ंक्शन में अपडेट करें ।
हाई जांग

मुझे डर है कि मैं वास्तव में आपके उत्तर को नहीं समझता। क्या आप कृपया अपने सुझाव को बढ़ाएँगे।
अलेक्जेंडर सेस्का

मेरा मतलब है, यदि आप pyplot.showएक लूप में कॉल करते हैं , तो लूप इस कॉल से अवरुद्ध हो जाएगा और जारी नहीं रहेगा। यदि आप चरण दर चरण कर्व्ड डेटा को जोड़ना चाहते हैं, तो अपने तर्क को रखें update, जिसे प्रत्येक कहा जाएगा, intervalइसलिए यह चरण-दर-चरण भी है।
हाई झांग

झांग का कोड कंसोल से काम करता है लेकिन ज्यूपिटर में नहीं। मुझे बस एक खाली प्लॉट मिलता है। वास्तव में, जब मैं एक अनुक्रमिक लूप में ज्यूपिटर में एक सरणी को पॉप्युलेट करता हूं और सरणी को प्रिंट करता हूं क्योंकि यह एक पालतू.प्लॉट स्टेटमेंट के साथ बढ़ता है, मैं व्यक्तिगत रूप से केवल एक प्लॉट से सरणियों का प्रिंट आउट प्राप्त कर सकता हूं। इस कोड को देखें: gist.github.com/bwanaaa/12252cf36b35fced0eb3c2f64a76cb8a
aquagremlin

15

मैं जानता हूँ कि इस सवाल पुराना है, लेकिन अब एक पैकेज उपलब्ध नामक drawnow के रूप में "अजगर-drawnow" GitHub पर। यह MATLAB के ड्रॉवेयर के समान इंटरफ़ेस प्रदान करता है - आप आसानी से एक आंकड़ा अपडेट कर सकते हैं

आपके उपयोग के मामले के लिए एक उदाहरण:

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)

अजगर-ड्रावॉर्न एक पतला आवरण है, plt.drawलेकिन आकृति प्रदर्शन के बाद पुष्टि (या डिबग) करने की क्षमता प्रदान करता है।


इससे tk हैंग हो जाता है
chwi

यदि ऐसा है, तो अधिक संदर्भ के साथ एक समस्या दर्ज करें github.com/scottsievert/python-drawnow/issues
Scott

+1 यह मेरे लिए opencv से वीडियो कैप्चर के फ्रेम प्रति लाइव डेटा की साजिश रचने के लिए काम आया, जबकि मैटलोट्लिब फ्रॉज़।
jj080808

मैंने यह कोशिश की और यह अन्य विधियों की तुलना में धीमा लग रहा था।
डेव सी

उपयोग न करें, मेरा सर्वर रिबूट, मैटप्लोटिब फ्रोजन
बिग-वीएल

6

समस्या यह प्रतीत होती है कि आप plt.show()खिड़की दिखाने और फिर वापस लौटने की उम्मीद करते हैं। यह ऐसा नहीं करता है। प्रोग्राम उस बिंदु पर बंद हो जाएगा और केवल एक बार विंडो बंद करने के बाद फिर से शुरू होगा। आपको इसका परीक्षण करने में सक्षम होना चाहिए: यदि आप विंडो बंद करते हैं और फिर दूसरी विंडो पॉप अप करनी चाहिए।

उस समस्या को हल करने के लिए बस plt.show()अपने लूप के बाद एक बार कॉल करें । फिर आपको पूरा प्लॉट मिलता है। (लेकिन 'रियल-टाइम प्लॉटिंग' नहीं)

आप कीवर्ड-तर्क blockको इस तरह सेट करने का प्रयास कर सकते हैं : plt.show(block=False)शुरुआत में एक बार और फिर .draw()अपडेट करने के लिए उपयोग करें।


1
वास्तविक समय की साजिश रचने वास्तव में मैं क्या करने जा रहा हूँ। मैं किसी चीज पर 5 घंटे का परीक्षण करने जा रहा हूं और यह देखना चाहता हूं कि चीजें कैसे आगे बढ़ रही हैं।
क्रिस

@ क्रिस क्या आप 5 घंटे की परीक्षा देने में सक्षम थे? मैं भी कुछ इसी तरह की तलाश में हूं। प्लॉट को अपडेट करने के लिए मैं plyplot.pause (time_duration) का उपयोग कर रहा हूं। क्या ऐसा करने का कोई और तरीका है?
प्रखर मोहन श्रीवास्तव

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)

ड्रावर (मेकफ़िग) लाइन को मेक फ़िग () के साथ बदला जा सकता है; plt.draw () अनुक्रम और यह अभी भी ठीक काम करता है।


1
आपको कैसे पता चलेगा कि कब तक रुकना है? यह भूखंड पर ही निर्भर प्रतीत होता है।
CMCDragonkai

1

यदि आप ड्रा चाहते हैं और अपने धागे को फ्रीज नहीं करना चाहते हैं, तो अधिक बिंदु खींचे जाने पर आपको plt.pause () नहीं समय का उपयोग करना चाहिए। ()

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

एक अन्य विकल्प बोकेह के साथ जाना है । 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

वास्तविक समय में सीपीयू उपयोग को प्लॉट करने के लिए एक उदाहरण उपयोग-केस।

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 एमबी रैम की खपत करता है और नाटकीय रूप से धीमा करना शुरू कर देता है।
pfabri
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.