使用PyQt PlotWidget进行实时绘图 - 错误消息PlotWidget对象不可调用

时间:2016-07-19 22:38:24

标签: python plot pyqt real-time

我正在尝试使用PyQt绘图小部件创建实时数据图。我读到PyQt是绘制实时图表的最佳选择,但到目前为止我没有任何成功。

我尝试使用followed here方法绘制随机数据,但似乎此方法不适用于PyQt绘图小部件。

我已经编译了以下代码来生成一个GUI,它在x和y轴上绘制随机点;但是我得到了错误:

  

PlotWidget对象无法调用

from PyQt4.QtGui import *
from PyQt4.QtCore import *

import numpy as np
import pyqtgraph as pg 
import sys


class Window(QMainWindow):

    def __init__(self):
        super(Window, self).__init__()
        self.setWindowIcon(QIcon('pythonlogo.png'))
        self.setGeometry(50,50,700,300)
        self.home()

    def home(self):

        #Timer for Plot calls the update function

        self.plot = pg.PlotWidget(self)
        self.timer2 = pg.QtCore.QTimer()
        self.timer2.timeout.connect(self.update)
        self.timer2.start(16)

        #Plot widget postion
        self.plot.move(200,50)
        self.plot.resize(450,200)

        self.show()

    def update(self):
        x = np.random.normal(size=1000)
        y = np.random.normal(size=1000)
        self.plot(x,y,clear=True) 

def run():    
        app=QApplication(sys.argv)
        GUI = Window()
        sys.exit(app.exec_())

run()

2 个答案:

答案 0 :(得分:2)

我遇到过类似的问题。但最后我得到了我的实时情节!

我查看了我的代码,并抛弃了与您无关的所有内容。因此,您将在此处找到显示实时图表所需的基本代码:

###################################################################
#                                                                 #
#                     PLOTTING A LIVE GRAPH                       #
#                  ----------------------------                   #
#            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_())

''''''

试一试。将此代码复制粘贴到新的python文件中,然后运行它。你应该得到一个漂亮的流畅的现场图表:

enter image description here

答案 1 :(得分:0)

好的,所以我能够解决我遇到的错误,并能够实时更新绘图小部件。下面的代码给出了一些基本的例子。我希望能够超时改进这个答案,以展示PyQt中实时绘图的功能。

from PyQt4.QtGui import *
from PyQt4.QtCore import *

import numpy as np
import pyqtgraph as pg
import random
import sys
import datetime


class Window(QMainWindow):

    def __init__(self):
        super(Window, self).__init__()
        self.setWindowIcon(QIcon('pythonlogo.png'))
        self.setGeometry(50,50,700,900)
        self.home()

    def home(self):    

        #Labels

        staticLbl = QLabel("Static Plot",self)
        staticLbl.move(10,50)

        dynamicLbl = QLabel("Random Plot",self)
        dynamicLbl.move(10,300)

        conLbl = QLabel("Continuous Plot",self)
        conLbl.move(10,550)

        #Static plot widget:

        staticPlt = pg.PlotWidget(self)
        x = np.random.normal(size=10)
        y = np.random.normal(size=10)

        staticPlt.plot(x,y,clear=True)

        staticPlt.move(200,50)
        staticPlt.resize(450,200)

        #Code to run to random plot using timer:

        self.dynamicPlt = pg.PlotWidget(self)

        self.dynamicPlt.move(200,300)
        self.dynamicPlt.resize(450,200)

        self.timer2 = pg.QtCore.QTimer()
        self.timer2.timeout.connect(self.update)
        self.timer2.start(200)

        #Code to run to get continous plot using timer:

        self.continuousPlt = pg.PlotWidget(self)

        self.continuousPlt.move(200,550)
        self.continuousPlt.resize(450,200)

        self.timer3 = pg.QtCore.QTimer()
        self.timer3.timeout.connect(self.cUpdate)
        self.timer3.start(200)

        self.show()

    def update(self):
        z = np.random.normal(size=1)
        u = np.random.normal(size=1)
        self.dynamicPlt.plot(z,u,pen=None, symbol='o')

    def cUpdate(self):
        now = datetime.datetime.now()
        s = np.array([now.second])

        self.continuousPlt.plot(s,s,pen=None, symbol='o')


def run():    
        app=QApplication(sys.argv)
        GUI = Window()
        sys.exit(app.exec_())

run()