1. 程式人生 > >pyqt中使用matplotlib繪製動態曲線

pyqt中使用matplotlib繪製動態曲線

原文連結  http://www.th7.cn/Program/Python/201408/260706.shtml

一、專案背景:

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

二、需求描述:

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

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

三、準備工作

1環境:python3.3,eric5,pyqt4

四、開始動手

使用Eric建立新專案:

 

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

 

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

 

儲存時,取名為MplMainWindow。

 

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

介面設計如下:

 

最後執行網格佈局。

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

 

點選新增,然後點選提升。

儲存當前設計的窗體。

到此就完成了

介面設計,qt的介面儲存的內容是xml的,需要轉換成程式碼,有兩種方式:

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

相關推薦

pyqt使用matplotlib繪製動態曲線

原文連結  http://www.th7.cn/Program/Python/201408/260706.shtml 一、專案背景: 看了matplotlib for developers這本書,基本掌握了在pyqt中顯示曲線的做法,於是自己寫一個。 二、需求描述:

MFC繪製動態曲線

https://blog.csdn.net/zang141588761/article/details/50536788 在工控監測領域,經常需要動態繪製曲線,觀察曲線的變化趨勢,繪製波形圖,繪製頻譜等。在前面4講中介紹了MFC經常用的TeeChart控制元件和Hight-Speed C

使用Python matplotlib動態曲線

point clas sin 參考 fig 如何使用 tput 運行圖 href 今天看到“Python實時監控CPU使用率”的教程: https://www.w3cschool.cn/python3/python3-ja3d2z2g.html 自己也學習如何使用Pytho

QLineSeries繪製動態曲線

  本文QLineSeries繪製動態曲線涉及到兩種,一種是曲線動態座標固定,一種是曲線和座標都是動態的。 一、曲線動態座標固定   效果圖: 這種比較簡單,直接計算座標位置,x軸超出範圍之後重新計算儲存的點地資料,替換掉超出範圍之前的所有的點的資料。 二、曲線和座標都

Qt繪製動態曲線

首先*.pro檔案中加一句 QT += charts然後 mainwindow.cpp檔案如下: #include "mainwindow.h" #include "ui_mainwindow.h" #include "QtCharts/QChart" #include "QLineS

Qt學習:QtCharts繪製動態曲線,實時更新資料與座標軸

1.首先是掌握qtchart的基本使用,封裝一個屬於自己的繪圖類: Mychart.h #pragma once #ifndef CHART_H #define CHART_H #include <QtCharts/QChart> #inc

使用matplotlib繪製動態

主要使用animation.FuncAnimation來實現,其中的引數 func是更新圖形的函式,frames是總共更新的次數,intit_func是圖形開始使用的函式, interval是更新的間隔時間(ms),blit決定是更新整張圖的點(Flase)還是隻更新變化的

Matlab繪製動態曲線

j=1; for i=1:max %max為最大時間      hold on;     if(i==t(j)) %t為時間向量           plot(x(j),y(j),'--ro');  

matplotlib繪製平滑的曲線

matplotlib繪製平滑的曲線有2種常用的方法 1.曲線擬合 使用scipy庫可以擬合曲線. 沒擬合的圖: import matplotlib.pyplot as plt import numpy as np T = np.array([6, 7, 8, 9, 10, 11,

CAD繪製曲線

在CAD繪圖中是有許多的形狀可以繪製的,有一些直線、正方體等一下操作,但是小夥伴們知道CAD中能繪製曲線嗎?那又如何在CAD編輯器中進行繪製,那下面小編就通過這篇文章來教教大傢俱體的操作方法,有興趣的小夥伴們可以來看看,以下就是具體操作步驟。 第一步:首先,小夥伴們將電腦進行開啟,如果電腦中沒有安裝CAD編

python Matplotlib 系列教程(九)——如何繪製動態圖(類似實時股票圖=走勢圖)

本章我們討論的是如何繪製實時圖表,用到的知識是Matplotlib的動畫功能。 # -*- coding: utf-8 -*- import matplotlib.pyplot as plt im

【python視覺化一Matplotlib 繪製】視覺化圖片顯示中文

# ----------------------顯示中文----神奇般的存在---------------- from pylab import * mpl.rcParams['font.sans-serif'] = ['SimHei'] # ----------------------

pythonMatplotlib庫顯示介面進行滑鼠互動繪製操作

近期在用Python做醫學影象處理系統製作,逐步跟大家分享我遇到的問題以及解決方案。今天來跟大家說一下在matplotlib庫顯示介面中進行滑鼠互動繪製等操作。 先上圖,下圖為用matplotlib進行顯示的脊柱影象(.dicom格式),後期跟大家介紹.dicom檔

matplotlib繪製sin、cos曲線

import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei']#用來正常顯示中文標籤 plt.rcParams['axes.unicode

pythonmatplotlib使用雙y軸的時候,只能顯示第二個曲線標誌怎麼辦?

       使用雙y軸的時候,只能顯示第二個曲線標誌怎麼辦? 原因:        只顯示右邊一個label,是因為在windows中legend()函式只選取當前活動的ax2。 方法:         在第二個Y 軸之前,即可用ax1.legend()語句把當前軸的標

圖表怎樣實現動態變更分類軸與系列值

數碼 jsb 情況 asi port data- nbsp track tex 在一些特殊的報表中我們加入了圖表元素,可是分類軸與系列值普通情況下都是固定的. 那麽,有沒有什麽方法能夠依據情況變更分類軸與系列值?方法例如以下: 所用報

關於redisSDS簡單動態字符串

target fault per 預測 string com tab 分配 ews 1、SDS 定義 在C語言中,字符串是以’\0’字符結尾(NULL結束符)的字符數組來存儲的,通常表達為字符指針的形式(char *)。它不允許字節0出現在字符串中

pythonmatplotlib的顏色及線條控制

hex 可選 技術 擴展 gen har hot deep for 參考網址: http://stackoverflow.com/questions/22408237/named-colors-in-matplotlib http://stackoverflow.com

Mybatis的update動態SQL語句 <trim></trim> 用法

color 單獨 null 多個 ride 逗號 myba 不用 log Mybatis Mapper中文件中 update時,需要set設置多個字段,有時逗號處理時,會報錯誤,所以會使用到<trim></trim> 使用trim就是為了刪掉最後

Hadoop學習筆記—13.分布式集群節點的動態添加與下架

情況 好的 當前 每次 原因 修改 輸入 task tle 開篇:在本筆記系列的第一篇中,我們介紹了如何搭建偽分布與分布模式的Hadoop集群。現在,我們來了解一下在一個Hadoop分布式集群中,如何動態(不關機且正在運行的情況下)地添加一個Hadoop節點與下架一個Had