Python3.x+pyqtgraph實現數據可視化教程
1、pyqtgraph庫數據可視化效果還不錯,特別是窗體程序中圖像交互性較好;安裝也很方便,用 pip 安裝。
2、在Python中新建一個 .py 文件,然后寫入如下代碼并執行可以得到官方提供的很多案例(含代碼),出現如下界面圖像:
import pyqtgraph.examplespyqtgraph.examples.run()
圖1
圖2
圖3
4、程序默認是黑色背景,這個是可以修改的。比如,在程序的開頭部分寫入如下代碼就可以修改背景:
pg.setConfigOption(’background’, ’w’)pg.setConfigOption(’foreground’, ’k’)
更多說明,見 pyqtgraph 官網:http://www.pyqtgraph.org/documentation/style.html,“Line, Fill, and Color”部分的“Default Background and Foreground Colors”部分。
5、一個修改背景顏色的完整案例如下,可以直接運行程序:
import numpy as npimport pyqtgraph as pgfrom pyqtgraph.Qt import QtGui, QtCore # 如下2行代碼是我自己加入的,目的是修改默認的黑色背景為其它顏色背景pg.setConfigOption(’background’, ’w’)pg.setConfigOption(’foreground’, ’k’) from pyqtgraph.Point import Point #generate layoutapp = QtGui.QApplication([])win = pg.GraphicsWindow()win.setWindowTitle(’pyqtgraph example: crosshair’)label = pg.LabelItem(justify=’right’)win.addItem(label)p1 = win.addPlot(row=1, col=0)p2 = win.addPlot(row=2, col=0) region = pg.LinearRegionItem()region.setZValue(10)# Add the LinearRegionItem to the ViewBox, but tell the ViewBox to exclude this# item when doing auto-range calculations.p2.addItem(region, ignoreBounds=True) #pg.dbg()p1.setAutoVisible(y=True) #create numpy arrays#make the numbers large to show that the xrange shows data from 10000 to all the way 0data1 = 10000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)data2 = 15000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000) p1.plot(data1, pen='r')p1.plot(data2, pen='g') p2.plot(data1, pen='w') def update(): region.setZValue(10) minX, maxX = region.getRegion() p1.setXRange(minX, maxX, padding=0) region.sigRegionChanged.connect(update) def updateRegion(window, viewRange): rgn = viewRange[0] region.setRegion(rgn) p1.sigRangeChanged.connect(updateRegion) region.setRegion([1000, 2000]) #cross hairvLine = pg.InfiniteLine(angle=90, movable=False)hLine = pg.InfiniteLine(angle=0, movable=False)p1.addItem(vLine, ignoreBounds=True)p1.addItem(hLine, ignoreBounds=True) vb = p1.vbdef mouseMoved(evt): pos = evt[0] ## using signal proxy turns original arguments into a tuple if p1.sceneBoundingRect().contains(pos): mousePoint = vb.mapSceneToView(pos) index = int(mousePoint.x()) if index > 0 and index < len(data1): label.setText('<span style=’font-size: 12pt’>x=%0.1f, <span style=’color: red’>y1=%0.1f</span>, <span style=’color: green’>y2=%0.1f</span>' % (mousePoint.x(), data1[index], data2[index])) vLine.setPos(mousePoint.x()) hLine.setPos(mousePoint.y()) proxy = pg.SignalProxy(p1.scene().sigMouseMoved, rateLimit=60, slot=mouseMoved)#p1.scene().sigMouseMoved.connect(mouseMoved) ## Start Qt event loop unless running in interactive mode or using pyside.if __name__ == ’__main__’: import sys if (sys.flags.interactive != 1) or not hasattr(QtCore, ’PYQT_VERSION’): QtGui.QApplication.instance().exec_()
知識補充:python圖形化實例分享--pyqt5與pyqtgraph嵌入繪圖
序言
之前也寫過一些圖形化界面的程序,基本上都是用wxPython寫的,確實簡單粗暴易上手。這次的任務是要寫一個繪圖的程序,wx模塊就顯得不太友好了,我就去網上找了一些資料,發現PyQtGraph畫這種K線圖、波形圖等圖形真是太簡單了,更多的關于wx、qt等模塊的細節學習可以看我后面的參考資料,我這里就分享一下我本程序的心得,和對有些方法使用上自己的理解
項目開始
引用頭文件
pyqt5_draw_1 這是主程序文件,負責主窗口圖形化界面
import sys # 與PyQt5配合使用from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout,QHBoxLayout, QVBoxLayout,QLabel, QComboBox,QPushButton,QDateEdit, QSpacerItem,QFrame, QSizePolicy, QSplitter,QRadioButton, QGroupBox,QCheckBox,QLineEdit, QAction)# 上面是QT圖形化要引用的所有包from PyQt5.QtCore import Qt, QDate, QRect # 對齊、時間等from PyQt5.QtCore import QThread, pyqtSignal # 多線程管理import pyqtgraph as pg # 繪圖包from Tmp_Data import * # 自定義文件,下面有介紹from Mythreading import * # 自定義文件,下面有介紹from pyqt5_graph import * # 自定義文件,下面有介紹
如果PyQt5、pyqtgraph未安裝的,最簡單的安裝方式就用python自帶的pip工具安裝,如果沒有pip的或不會安裝可直接百度
c:> pip install PyQt5 pyqtgraph
圖形化主界面搭建
# pyqt5_draw_1.py 文件名import sysimport cgitbfrom PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout,QHBoxLayout, QVBoxLayout,QLabel, QComboBox,QPushButton,QDateEdit, QSpacerItem,QFrame, QSizePolicy, QSplitter,QRadioButton, QGroupBox,QCheckBox,QLineEdit, QAction)from PyQt5.QtCore import Qt, QDate, QRectfrom TmpData import *from Mythreading import *from pyqt5_graph import *class Qt_Test_Frame(QMainWindow): Items = [] def __init__(self): #super(Qt_Test_Frame, self).__init__(*args, **kw) super().__init__() # 初始化界面 self._initUI() self.show() def _initUI(self): self.setWindowTitle('QT圖形界面測試') self.resize(800, 600) wwg = QWidget() # 全局布局 wlayout = QVBoxLayout() h1_wlayout = QHBoxLayout() h2_wlayout = QHBoxLayout() h3_wlayout = QHBoxLayout() v4_wlayout = QVBoxLayout() v5_wlayout = QVBoxLayout() self.statusBar().showMessage('狀態欄') # 第一層 self._frist_story(h1_wlayout) # 第二層 self._second_story(h2_wlayout) # 第三層 左 self._third_left(v4_wlayout, v5_wlayout) # 第三層 右 self._fouth_right(v5_wlayout) # 加載 splt = self._my_line() splt2 = self._my_line(False) wlayout.addSpacing(10) # 增加布局間距 wlayout.addLayout(h1_wlayout) wlayout.addSpacing(10) # 增加布局間距 wlayout.addLayout(h2_wlayout) wlayout.addSpacing(10) # 增加布局間距 wlayout.addWidget(splt) wlayout.addLayout(h3_wlayout) wlayout.addWidget(self.statusBar()) h3_wlayout.addLayout(v4_wlayout, 0) h3_wlayout.addWidget(splt2) h3_wlayout.addLayout(v5_wlayout, 2) #wlayout.setAlignment(Qt.AlignTop) wwg.setLayout(wlayout) self.setCentralWidget(wwg) def _frist_story(self, h1_wlayout): # 第一層布局 self.h1_combox1 = QComboBox(minimumWidth=100) self.h1_combox1.addItems(wind_field) self.h1_combox2 = QComboBox(minimumWidth=100) self.h1_combox2.addItems(wind_mach_chooice(self.h1_combox1.currentText())) self.h1_combox3 = QComboBox(minimumWidth=100) self.h1_combox3.addItems(wind_blade) self.h1_combox4 = QComboBox(minimumWidth=100) self.h1_combox4.addItems(signal_type) # 行為測試 暫時無法使用 h1_cb1_action = QAction('風場選擇', self) h1_cb1_action.setStatusTip('請選擇風場') self.h1_combox1.addAction(h1_cb1_action) h1_wlayout.addItem(QSpacerItem(20, 20)) h1_wlayout.addWidget(QLabel('風場'),0) h1_wlayout.addWidget(self.h1_combox1,0) h1_wlayout.addItem(QSpacerItem(40, 20)) h1_wlayout.addWidget(QLabel('風機'), 0) h1_wlayout.addWidget(self.h1_combox2, 0) h1_wlayout.addItem(QSpacerItem(40, 20)) h1_wlayout.addWidget(QLabel('葉片ID'), 0) h1_wlayout.addWidget(self.h1_combox3, 0) h1_wlayout.addItem(QSpacerItem(40, 20)) h1_wlayout.addWidget(QLabel('信號類型'), 0) h1_wlayout.addWidget(self.h1_combox4, 0) h1_wlayout.setAlignment(Qt.AlignLeft) # 事件綁定 self.h1_combox1.currentIndexChanged.connect(self._wind_chooice) def _second_story(self, h2_wlayout): # 第二層布局 self.h2_date1 = QDateEdit(QDate.currentDate()) self.h2_date1.setCalendarPopup(True) self.h2_date2 = QDateEdit(QDate.currentDate()) self.h2_date2.setCalendarPopup(True) self.h2_button = QPushButton('運行') self.h2_button2 = QPushButton('停止') h2_wlayout.addItem(QSpacerItem(20, 20)) h2_wlayout.addWidget(QLabel('起始'),0) h2_wlayout.addWidget(self.h2_date1) h2_wlayout.addItem(QSpacerItem(50, 20)) h2_wlayout.addWidget(QLabel('結束'), 0) h2_wlayout.addWidget(self.h2_date2) h2_wlayout.addItem(QSpacerItem(70, 20)) h2_wlayout.addWidget(self.h2_button) h2_wlayout.addWidget(self.h2_button2) h2_wlayout.setAlignment(Qt.AlignLeft) # 事件綁定 self.h2_button.clicked.connect(lambda: self._start_func()) self.h2_button2.clicked.connect(lambda: self._stop_func()) def _third_left(self, v4_wlayout, v5_wlayout): # 第三層布局 # 分量布局 v4_group_imf = QGridLayout() vbox1 = QGroupBox('分量值') self.radio_1 = QRadioButton('分量1') self.radio_2 = QRadioButton('分量2') self.radio_3 = QRadioButton('分量3') self.radio_4 = QRadioButton('分量4') self.radio_5 = QRadioButton('分量5') self.radio_6 = QRadioButton('分量6') self.radio_7 = QRadioButton('分量7') self.radio_8 = QRadioButton('分量8') self.radio_9 = QRadioButton('分量9') self.radio_1.setChecked(True) self.radio_val = self.radio_1.text() # 優先級布局 v4_group_prior = QGridLayout() vbox2 = QGroupBox('優先級') cb1 = QCheckBox('葉片1') cb2 = QCheckBox('葉片2') cb3 = QCheckBox('葉片3') self.v4_lineEdit = QLineEdit() # 時間布局 v4_group_time = QGridLayout() vbox3 = QGroupBox('時間選擇') self.v4_combox1 = QComboBox(minimumWidth=100) self.v4_combox1.addItem('空') # 按鍵 v4_button = QPushButton('顯示圖形') # 寫入網格格布局 v4_group_imf.addWidget(self.radio_1, 0, 0) v4_group_imf.addWidget(self.radio_2, 0, 1) v4_group_imf.addWidget(self.radio_3, 1, 0) v4_group_imf.addWidget(self.radio_4, 1, 1) v4_group_imf.addWidget(self.radio_5, 2, 0) v4_group_imf.addWidget(self.radio_6, 2, 1) v4_group_imf.addWidget(self.radio_7, 3, 0) v4_group_imf.addWidget(self.radio_8, 3, 1) v4_group_imf.addWidget(self.radio_9, 4, 0) v4_group_prior.addWidget(cb1, 1, 0) v4_group_prior.addWidget(cb2, 2, 0) v4_group_prior.addWidget(cb3, 3, 0) v4_group_prior.addWidget(QLabel('選擇是:'),4,0) v4_group_prior.addWidget(self.v4_lineEdit, 5, 0) v4_group_time.addWidget(self.v4_combox1) # 寫入左側布局 vbox1.setLayout(v4_group_imf) vbox2.setLayout(v4_group_prior) vbox3.setLayout(v4_group_time) v4_wlayout.addItem(QSpacerItem(50, 20)) v4_wlayout.addWidget(vbox1) v4_wlayout.addItem(QSpacerItem(50, 20)) v4_wlayout.addWidget(vbox2) v4_wlayout.addItem(QSpacerItem(50, 20)) v4_wlayout.addWidget(vbox3) v4_wlayout.addItem(QSpacerItem(50, 20)) v4_wlayout.addWidget(v4_button) v4_wlayout.addItem(QSpacerItem(50, 20)) # 事件綁定 self.radio_1.toggled.connect(lambda: self._changestyle(self.radio_1)) self.radio_2.toggled.connect(lambda: self._changestyle(self.radio_2)) self.radio_3.toggled.connect(lambda: self._changestyle(self.radio_3)) self.radio_4.toggled.connect(lambda: self._changestyle(self.radio_4)) self.radio_5.toggled.connect(lambda: self._changestyle(self.radio_5)) self.radio_6.toggled.connect(lambda: self._changestyle(self.radio_6)) self.radio_7.toggled.connect(lambda: self._changestyle(self.radio_7)) self.radio_8.toggled.connect(lambda: self._changestyle(self.radio_8)) self.radio_9.toggled.connect(lambda: self._changestyle(self.radio_9)) cb1.stateChanged.connect(lambda: self._prior_func(cb1)) cb2.stateChanged.connect(lambda: self._prior_func(cb2)) cb3.stateChanged.connect(lambda: self._prior_func(cb3)) v4_button.clicked.connect(lambda: self._show_func(v5_wlayout)) def _fouth_right(self, v5_wlayout): # 加載波形圖 self.tmp_plt = plt_init() v5_wlayout.addWidget(self.tmp_plt) def _my_line(self, var=True): # var 為True時,為橫線,否則為豎線 line = QFrame(self) line_var = QFrame.HLine sp_var = Qt.Horizontal if not var: line_var = QFrame.VLine sp_var = Qt.Vertical line.setFrameShape(line_var) line.setFrameShadow(QFrame.Sunken) splitter = QSplitter(sp_var) splitter.addWidget(line) return splitter def _wind_chooice(self): tmp_list = wind_mach_chooice(self.h1_combox1.currentText()) self.h1_combox2.clear() self.h1_combox2.addItems(tmp_list) def _start_func(self): a = self.h1_combox1.currentText() b = self.h1_combox2.currentText() c = self.h1_combox3.currentText() d = self.h1_combox4.currentText() e = self.h2_date1.dateTime().toString('yy-MM-dd') f = self.h2_date2.dateTime().toString('yy-MM-dd') # 多線程的引用 self.start_func = RunThread(target=self._start_thread, args=(a, b, c, d, e, f)) # 多線程啟動 self.start_func.start() def _stop_func(self): # 線程停止 self.start_func.stop() print('運行結束') def _start_thread(self, a, b, c, d, e, f): print('*****運行打印*****') print(wind_mach_chooice(a)) print(a,b,c,d) print(e) print(f) print('%s' % (time.strftime(’<%H:%M:%S>’, time.localtime()))) self.v4_combox1.clear() self.v4_combox1.addItems(tmp_time_list) print('*****運行打印*****') def _changestyle(self, btn): # 單選項的判斷函數 if btn.isChecked(): self.radio_val = btn.text() #print('%s'%(time.strftime(’<%H:%M:%S>’, time.localtime()))) def _prior_func(self, cb): # 復選框內容添加 if cb.isChecked(): if cb.text()[-1] not in self.Items: self.Items.append(cb.text()[-1]) shop_cart= ','.join(self.Items) self.v4_lineEdit.setText(shop_cart) else: if cb.text()[-1] in self.Items: self.Items.remove(cb.text()[-1]) shop_cart = ','.join(self.Items) self.v4_lineEdit.setText(shop_cart) def _show_func(self, v5_wlayout): print('*****顯示打印*****') print(self.radio_val) num = self.v4_lineEdit.text() print(self.v4_combox1.currentText()) v5_wlayout.removeWidget(self.tmp_plt) self.tmp_plt = plt_show(num) v5_wlayout.addWidget(self.tmp_plt) print('*****顯示打印*****')if __name__ == ’__main__’:cgitb.enable(format='text') app = QApplication(sys.argv) win = Qt_Test_Frame() sys.exit(app.exec_())
處理把列表文件轉成字典與繪圖
# pyqt5_graph.py 文件名 import pyqtgraph as pgfrom TmpData import _read_data, wind_mach_chooicecolour = ['r', 'g', 'b']yp_list = ['葉片1', '葉片2', '葉片3']def _data_to_dict(): mydict = {} for my_vars, i in zip(_read_data(), range(len(_read_data()))): tmp_dict = {} for var, j in zip(my_vars, range(len(my_vars))): tmp_dict[var[0]] =var[1] mydict[i] = tmp_dict return mydictdef plt_init():# 繪圖初始化 pg.setConfigOption('background', 'w') plt = pg.PlotWidget() plt.addLegend(size=(150, 80)) plt.showGrid(x=True, y=True, alpha=0.5) return pltdef plt_show(num):# 傳繪制的新圖 mydict = _data_to_dict() pg.setConfigOption('background', 'w') plt = pg.PlotWidget() plt.addLegend(size=(150, 80)) plt.showGrid(x=True, y=True, alpha=0.5) for i in num.split(','): i = int(i)-1 plt.plot(x=list(mydict[i].keys()), y=list(mydict[i].values()), pen=colour[i], name=yp_list[i]) return pltif __name__ == ’__main__’: _data_to_dict() pass
模擬給其它文件傳指定數據
# TmpData.py 文件名import osimport numpy as npfile_path = os.path.join(os.getcwd(), '風機采集信號數據')wind_field = ['風場1', '風場2', '風場3']wind_machine = {'風場1':['大別山', '天目山'], '風場2':['昆侖山', '三清山'], '風場3':['五指山', '火焰山']}wind_blade = ['X-20Hz', 'X-1K', 'Y-20Hz', 'Y-1K']signal_type = ['包絡', '振動']tmp_time_list = ['20190501', '20190502', '20190504', '20190508', '20190515']def wind_mach_chooice(val): return wind_machine[val]def _read_data(): file_list = os.listdir(file_path) file_list = [var for var in file_list if var.split('.')[1] == 'csv'] a = [] for var in file_list: tmp = os.path.join(file_path, var) rd_file = np.loadtxt(tmp, delimiter=',', usecols=(0, 1)) a.append(rd_file) return a[0], a[1], a[2]
多線程管理
因為程序運行時間久,主界面就會出現假死的狀態,要引用多線程
# Mythreading.py 文件名from PyQt5.QtCore import QThread, pyqtSignalclass RunThread(QThread): counter_value = pyqtSignal(int) def __init__(self, target, args, name=''): QThread.__init__(self) self.target = target self.args = args self.is_running = True def run(self): #print('starting',self.name, 'at:',ctime()) self.res = self.target(*self.args) def stop(self): # 負責停止線程 self.terminate()
關于QT異常直接退出沒有報錯的情況,查bug比較麻煩
import cgitb# 這句放在所有程序開始前,這樣就可以正常打印異常了cgitb.enable(format='text')
這些天本人身體不舒服,但還是把做完的這個分享出來,有些細節沒有具體說明,下次身體好點,再單獨拿出來分享,累了,晚安!
以上這篇Python3.x+pyqtgraph實現數據可視化教程就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。
相關文章: