2016-07-19 2 views
1

PyQt 플롯 위젯을 사용하여 실시간 데이터 플롯을 만들려고합니다. 필자는 PyQt가 실시간 그래프를 그릴 때 가장 좋은 옵션이라고 읽었지만 아직까지 성공하지 못했습니다.PyQt PlotWidget으로 실시간 작도 - 오류 메시지 PlotWidget 객체를 호출 할 수 없습니다.

나는 followed here 메서드를 사용하여 임의의 데이터를 플롯하려했지만이 방법은 PyQt 플롯 위젯에는 적용되지 않는 것으로 보입니다.

다음 코드를 컴파일하여 x 축과 y 축의 임의의 점을 그려주는 GUI를 생성했습니다. 나는 오류가 발생하지만 :

PlotWidget object is not callable

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

답변

1

나는 유사한 문제에 직면하고있다. 그러나 결국 나는 나의 실시간 음모가 작동했다!

나는 내 코드를 살펴보고 관련없는 모든 것을 버렸습니다. 따라서 여기에서 알 수있는 것은 라이브 그래프를 표시하는 데 필요한 기본 코드입니다.

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

'''''' 

그냥 시도해보십시오. 이 코드를 복사하여 새로운 파이썬 파일에 붙여넣고 실행하십시오. 당신은 아름다운 부드러운 라이브 그래프를 얻어야한다 :

enter image description here

+0

정말 고마워. 정말 깔끔한 응용 프로그램을 만들었습니다 :) PyQt4 플롯 위젯보다 Matplotlib 캔버스를 사용하는 것으로 나타났습니다. 당신이 PyQt4에 성공하지 못했기 때문입니까? 필자는 PyQt4의 주된 특징 중 하나가 실시간 데이터를 플롯 할 수 있다는 인상을 받았지만 위젯에서는 그렇지 않다. 나는 또한 당신의 코드에서 스레드 안전 방법을 사용하지 않는다면 일이 매우 잘못 될 것이라고 말했습니까? 위험은 무엇입니까? 나는 Rpi에 연결된 온도 센서로부터 데이터 신호를받을 것이다. 이 답변을 주셔서 감사합니다, 그것은 매우 유용합니다 :) – alkey

+0

안녕 앨런 키. matplotlib 라이브러리는 모든 종류의 애니메이션 제작에 대한 놀라운 지원을 제공합니다. 그리고 그 코드는 그래프가 매끄럽도록 최적화되어 있습니다. 나를 위해, 그것은 중요합니다 :-). 글쎄, 스레드 안전하지 않은 방법에 대해, 나는 "스레드 안전"내 코드를 만들기 전에 한 번 이상한 오류 메시지가있었습니다. 관심이 있다면 나는 너를 찾아 볼 수있다. 어쨌든 내가 제시 한 코드는 100 % 스레드로부터 안전합니다. 0.1 초마다 새로운 데이터 포인트가 그래프로 보내지는 것을 보셨습니까? 신호 슬롯 메커니즘을 통해 '방출'됩니다. 온도 데이터를 보내면 (대신에 .. –

+0

.. 내가 생성하는 부비동 기능), 온도 그래프를 볼 수 있습니다! 저를 믿으십시오, 나는 마이크로 제어기에서 동시에 오는 12 개의 신호로 그것을했다. 원자력 발전소의 제어판을 보는 것처럼 모든 12 개의 신호가 부드럽게 움직입니다 ;-) –

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() 
관련 문제