国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

pyqt中使用matplotlib繪制動態曲線

2019-11-14 17:39:32
字體:
來源:轉載
供稿:網友

一、項目背景:

看了matplotlib for python developers這本書,基本掌握了在pyqt中顯示曲線的做法,于是自己寫一個。

二、需求描述:

1)X軸顯示時間點,顯示長度為1分鐘,每一秒鐘繪制一個點,X軸長度超過1分鐘,則左移1秒刻度,實現動態效果

2)Y軸顯示隨機變化的數值,1-100

三、準備工作

1環境:python3.3,eric5,pyqt4

四、開始動手

使用Eric創建新項目:

 

 在設計編碼前期主要用到Eric的兩個窗口:源碼和窗體瀏覽器,類似delphi。

  

在窗體瀏覽器中,右鍵,new Form,窗體類型選擇Main Window,如下:

 

保存時,取名為MplMainWindow。

 

在界面上放兩個PushButton,水平布局,然后放一個Widget,修改名稱、水平及垂直策略。

界面設計如下:

 

最后執行網格布局。

為了嵌入Matplotlib在mplCanvas中,需要將mplCanvas升級,右鍵執行PRomote,輸入類名稱為MplCanvasWrapper,這個類就是編寫matplotlib代碼的,文件名稱為mplCanvasWrapper。

 

點擊添加,然后點擊提升。

 

保存當前設計的窗體。

到此就完成了界面設計,qt的界面保存的內容是xml的,需要轉換成python代碼,有兩種方式:

方法1:使用Eric自帶的功能:在窗體瀏覽器中,右鍵窗體ui文件,執行compile form命令,此時會在當前ui文件目錄中生成Ui_MplMainWindow.py文件。

方法2:在cmd中執行命令【pyuic 4 –o 目的文件名 原文件名】,如下:

 

此時在項目文件夾中生成了一個MplMainWindow.py文件。

 

在此文檔中使用方式1,默認生成的文件名稱是Ui_MplMainWindow.py。

打開這個文件,做兩件事情:

1)在最后一行會有這么一句:“from mplCodeWrapper import MplCodeWrapper”,與提升時輸入的類名文件名完全一致,把這句話剪切到文件頂部,要不會報錯的。

2)將窗體的繼承由object改為QtGui.QMainWindow

 

然后我們要創建文件mplCodeWrapper.py

在Eric的源碼瀏覽器中,新建文件,保存為mplCodeWrapper.py,寫上兩句空代碼:

from PyQt4 import QtCore

from PyQt4 import QtGui

from Ui_MplMainWindow import Ui_MainWindow

class Code_MainWindow(Ui_MainWindow):#修改為從Ui_MainWindow繼承

   

    def __init__(self, parent = None):

        super(Code_MainWindow, self).__init__(parent)

        pass

到此為止,整個框架搭起來了,界面文件和繪圖文件都有了。

 

下面為窗體添加事件處理。

本著界面和代碼分離的原則,我們新建一個py文件,用于編寫界面代碼

在當前目錄中新建文件Code_MplMainWindow.py,主要用來綁定按鈕事件及中間邏輯。

上面說了一堆,可能不是很明白為什么要這么改,在此畫出類圖如下:

 

PyQt生成的文件Ui_MplMainWindow屬于純界面文件,類似于C#的designer文件,Code_MplMainWindow文件類似于C#的cs文件,而繪圖的邏輯放在MplCanvasWrapper中,這樣界面和實現就分離了。

如何讓X軸顯示時間并動起來呢?

1)  關于X軸顯示時間,matplotlib提供了plot_date方法

2)  設計一個線程,用于產生數據和繪圖,根據功能單一原則,我們需要將產生數據和繪圖分成兩類來實現,一個數據處理類,一個畫板類。完善后的類圖如下:

 

注意幾點:

1)  窗體關閉時,要有關閉確認提示,通過重寫closeEvent實現

2)  線程要有退出信號

完整代碼如下:

1)  Ui_MplMainWindow.py

# -*- coding: utf-8 -*-

 

# Form implementation generated from reading ui file 'MplMainWindow.ui'

#

# Created: Mon Aug 11 14:18:31 2014

#      by: PyQt4 UI code generator 4.10.3

#

# WARNING! All changes made in this file will be lost!

 

from PyQt4 import QtCore, QtGui

from mplCanvasWrapper import MplCanvasWrapper

 

try:

    _fromUtf8 = QtCore.QString.fromUtf8

except AttributeError:

    def _fromUtf8(s):

        return s

 

try:

    _encoding = QtGui.Qapplication.UnicodeUTF8

    def _translate(context, text, disambig):

        return QtGui.QApplication.translate(context, text, disambig, _encoding)

except AttributeError:

    def _translate(context, text, disambig):

        return QtGui.QApplication.translate(context, text, disambig)

       

#inheritent from QtGui.QMainWindow

class Ui_MainWindow(QtGui.QMainWindow):

    def setupUi(self, MainWindow):

        MainWindow.setObjectName(_fromUtf8("MainWindow"))

        MainWindow.resize(690, 427)

        self.centralWidget = QtGui.QWidget(MainWindow)

        self.centralWidget.setObjectName(_fromUtf8("centralWidget"))

        self.gridLayout = QtGui.QGridLayout(self.centralWidget)

        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))

        self.horizontalLayout = QtGui.QHBoxLayout()

        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))

        self.btnStart = QtGui.QPushButton(self.centralWidget)

        self.btnStart.setObjectName(_fromUtf8("btnStart"))

        self.horizontalLayout.addWidget(self.btnStart)

        self.btnPause = QtGui.QPushButton(self.centralWidget)

        self.btnPause.setObjectName(_fromUtf8("btnPause"))

        self.horizontalLayout.addWidget(self.btnPause)

        spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)

        self.horizontalLayout.addItem(spacerItem)

        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)

        self.mplCanvas = MplCanvasWrapper(self.centralWidget)

        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)

        sizePolicy.setHorizontalStretch(0)

        sizePolicy.setVerticalStretch(0)

        sizePolicy.setHeightForWidth(self.mplCanvas.sizePolicy().hasHeightForWidth())

        self.mplCanvas.setSizePolicy(sizePolicy)

        self.mplCanvas.setObjectName(_fromUtf8("mplCanvas"))

        self.gridLayout.addWidget(self.mplCanvas, 1, 0, 1, 1)

        MainWindow.setCentralWidget(self.centralWidget)

 

        self.retranslateUi(MainWindow)

        QtCore.QMetaObject.connectSlotsByName(MainWindow)

 

    def retranslateUi(self, MainWindow):

        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))

        self.btnStart.setText(_translate("MainWindow", "開始", None))

        self.btnPause.setText(_translate("MainWindow", "暫停", None))

  

2)Code_MplMainWindow.py

from PyQt4 import QtGui, QtCore

from Ui_MplMainWindow import Ui_MainWindow

class Code_MainWindow(Ui_MainWindow):

   

    def __init__(self, parent = None):

        super(Code_MainWindow, self).__init__(parent)

   

        self.setupUi(self)

        self.btnStart.clicked.connect(self.startPlot)

        self.btnPause.clicked.connect(self.pausePlot)

  

    def startPlot(self):

        ''' begin to plot'''

        self.mplCanvas.startPlot()       

        pass

       

    def pausePlot(self):

        ''' pause plot '''

        self.mplCanvas.pausePlot()       

        pass

       

    def releasePlot(self):

        ''' stop and release thread'''

        self.mplCanvas.releasePlot()

 

    def closeEvent(self,event):

        result = QtGui.QMessageBox.question(self,

                      "Confirm Exit...",

                      "Are you sure you want to exit ?",

                      QtGui.QMessageBox.Yes| QtGui.QMessageBox.No)

        event.ignore()

 

        if result == QtGui.QMessageBox.Yes:

            self.releasePlot()#release thread's resouce

            event.accept()

 

if __name__ == "__main__":

    import sys

    app = QtGui.QApplication(sys.argv)

    ui = Code_MainWindow()

    ui.show()

sys.exit(app.exec_())

 

3)mplCanvasWrapper.py

from PyQt4 import  QtGui

from matplotlib.backends.backend_qt4agg import  FigureCanvasQTAgg as FigureCanvas

from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar

from matplotlib.figure import Figure

import numpy as np

from array import array

import time

import random

import threading

from datetime import datetime

from matplotlib.dates import  date2num, MinuteLocator, SecondLocator, DateFormatter

 

X_MINUTES = 1

Y_MAX = 100

Y_MIN = 1

INTERVAL = 1

MAXCOUNTER = int(X_MINUTES * 60/ INTERVAL)

class MplCanvas(FigureCanvas):

    def __init__(self):

        self.fig = Figure()

        self.ax = self.fig.add_subplot(111)

        FigureCanvas.__init__(self, self.fig)

        FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)

        FigureCanvas.updateGeometry(self)

        self.ax.set_xlabel("time of data generator")

        self.ax.set_ylabel('random data value')

        self.ax.legend()

        self.ax.set_ylim(Y_MIN,Y_MAX)

        self.ax.xaxis.set_major_locator(MinuteLocator())  # every minute is a major locator

        self.ax.xaxis.set_minor_locator(SecondLocator([10,20,30,40,50])) # every 10 second is a minor locator

        self.ax.xaxis.set_major_formatter( DateFormatter('%H:%M:%S') ) #tick label formatter

        self.curveObj = None # draw object

    def plot(self, datax, datay):

        if self.curveObj is None:

            #create draw object once

            self.curveObj, = self.ax.plot_date(np.array(datax), np.array(datay),'bo-')

        else:

            #update data of draw object

            self.curveObj.set_data(np.array(datax), np.array(datay))

            #update limit of X axis,to make sure it can move

            self.ax.set_xlim(datax[0],datax[-1])

        ticklabels = self.ax.xaxis.get_ticklabels()

        for tick in ticklabels:

            tick.set_rotation(25)

        self.draw()

       

class  MplCanvasWrapper(QtGui.QWidget):

   

    def __init__(self , parent =None):

        QtGui.QWidget.__init__(self, parent)

        self.canvas = MplCanvas()

        self.vbl = QtGui.QVBoxLayout()

        self.ntb = NavigationToolbar(self.canvas, parent)

        self.vbl.addWidget(self.ntb)

        self.vbl.addWidget(self.canvas)

        self.setLayout(self.vbl)

        self.dataX= []

        self.dataY= []

        self.initDataGenerator()

       

    def startPlot(self):

        self.__generating = True

       

    def pausePlot(self):

        self.__generating = False

        pass

   

    def initDataGenerator(self):

        self.__generating=False

        self.__exit = False

       

        self.tData = threading.Thread(name = "dataGenerator",target = self.generateData)

        self.tData.start()

    def releasePlot(self):

         self.__exit  = True

         self.tData.join()

    def generateData(self):

        counter=0

        while(True):

            if self.__exit:

                break

            if self.__generating:

                newData = random.randint(Y_MIN, Y_MAX)

                newTime= date2num(datetime.now())

          

                self.dataX.append(newTime)

                self.dataY.append(newData)

            

                self.canvas.plot(self.dataX, self.dataY)    

               

                if counter >= MAXCOUNTER:

                    self.dataX.pop(0)

                    self.dataY.pop(0) 

                else:

                    counter+=1

            time.sleep(INTERVAL)

 

效果圖:

 

總結:

通過該程序,主要熟悉了以下幾點:

1)  Eric、QtDesigner使用,界面與邏輯分離

2)  重寫窗體事件

3)  綁定信號和槽

4)  使用線程

5)  面向對象的matplotlib的使用

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 原平市| 新昌县| 八宿县| 望都县| 兴宁市| 商丘市| 南溪县| 灵石县| 通山县| 米脂县| 务川| 双辽市| 海盐县| 汉寿县| 南岸区| 民丰县| 赫章县| 沂南县| 湘阴县| 莒南县| 绿春县| 雷山县| 磐石市| 承德县| 桃江县| 横山县| 玉树县| 浙江省| 许昌县| 阜康市| 清水河县| 德钦县| 柘城县| 大洼县| 体育| 正安县| 神木县| 黄冈市| 南华县| 城口县| 庄河市|