How do I plot in real-time in a while loop using matplotlib? How do I plot in real-time in a while loop using matplotlib? python python

How do I plot in real-time in a while loop using matplotlib?


Here's the working version of the code in question (requires at least version Matplotlib 1.1.0 from 2011-11-14):

import numpy as npimport matplotlib.pyplot as pltplt.axis([0, 10, 0, 1])for i in range(10):    y = np.random.random()    plt.scatter(i, y)    plt.pause(0.05)plt.show()

Note the call to plt.pause(0.05), which both draws the new data and runs the GUI's event loop (allowing for mouse interaction).


If you're interested in realtime plotting, I'd recommend looking into matplotlib's animation API. In particular, using blit to avoid redrawing the background on every frame can give you substantial speed gains (~10x):

#!/usr/bin/env pythonimport numpy as npimport timeimport matplotlibmatplotlib.use('GTKAgg')from matplotlib import pyplot as pltdef 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 posdef 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)

Output:

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


I know I'm a bit late to answer this question. Nevertheless, I've made some code a while ago to plot live graphs, that I would like to share:

Code for PyQt4:

####################################################################                                                                 ##                    PLOT A LIVE GRAPH (PyQt4)                    ##                  -----------------------------                  ##            EMBED A MATPLOTLIB ANIMATION INSIDE YOUR             ##            OWN GUI!                                             ##                                                                 ####################################################################import sysimport osfrom PyQt4 import QtGuifrom PyQt4 import QtCoreimport functoolsimport numpy as npimport random as rdimport matplotlibmatplotlib.use("Qt4Agg")from matplotlib.figure import Figurefrom matplotlib.animation import TimedAnimationfrom matplotlib.lines import Line2Dfrom matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvasimport timeimport threadingdef 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_())''''''

 
I recently rewrote the code for PyQt5.
Code for PyQt5:

####################################################################                                                                 ##                    PLOT A LIVE GRAPH (PyQt5)                    ##                  -----------------------------                  ##            EMBED A MATPLOTLIB ANIMATION INSIDE YOUR             ##            OWN GUI!                                             ##                                                                 ####################################################################import sysimport osfrom PyQt5.QtWidgets import *from PyQt5.QtCore import *from PyQt5.QtGui import *import functoolsimport numpy as npimport random as rdimport matplotlibmatplotlib.use("Qt5Agg")from matplotlib.figure import Figurefrom matplotlib.animation import TimedAnimationfrom matplotlib.lines import Line2Dfrom matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvasimport timeimport threadingclass 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_())

Just try it out. Copy-paste this code in a new python-file, and run it. You should get a beautiful, smoothly moving graph:

enter image description here