pyqt中使⽤matplotlib绘制动态曲线
⼀、项⽬背景:
看了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_MplMainWin
dow⽂件类似于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 anslate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return anslate(context, text, disambig)
#inheritent from QtGui.QMainWindow
class Ui_MainWindow(QtGui.QMainWindow):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.btnStart = QtGui.alWidget)
self.btnStart.setObjectName(_fromUtf8("btnStart"))
self.horizontalLayout.addWidget(self.btnStart)
self.btnPause = QtGui.alWidget)
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.mplCanvas = alWidget)
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"))
MainWindow.alWidget)
tSlotsByName(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.t(self.startPlot)
self.t(self.pausePlot)
def startPlot(self):
''' begin to plot'''
self.mplCanvas.startPlot()
pass
def pausePlot(self):
matplotlib中subplot''' pause plot '''
self.mplCanvas.pausePlot()
pass
def releasePlot(self):
''' stop and release thread'''
leasePlot()
def closeEvent(self,event):
result = QtGui.QMessageBox.question(self,
"",
"Are you sure you want to exit ?",
QtGui.QMessageBox.Yes| QtGui.QMessageBox.No)
event.ignore()
if result == QtGui.QMessageBox.Yes:
event.accept()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
ui = Code_MainWindow()
ui.show()
<_())
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)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论