Python3.x+pyqtgraph實現數據可視化教程
時間:2020-03-14來源:電腦系統城作者:電腦系統城
1、pyqtgraph庫數據可視化效果還不錯,特別是窗體程序中圖像交互性較好;安裝也很方便,用 pip 安裝。
2、在Python中新建一個 .py 文件,然后寫入如下代碼并執行可以得到官方提供的很多案例(含代碼),出現如下界面圖像:
import pyqtgraph.examples
pyqtgraph.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 np
- import pyqtgraph as pg
- from pyqtgraph.Qt import QtGui, QtCore
-
- # 如下2行代碼是我自己加入的,目的是修改默認的黑色背景為其它顏色背景
- pg.setConfigOption('background', 'w')
- pg.setConfigOption('foreground', 'k')
-
- from pyqtgraph.Point import Point
-
- #generate layout
- app = 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 0
- data1 = 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 hair
- vLine = 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.vb
- def 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 sys
- import cgitb
- from 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, QRect
- from 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 pg
- from TmpData import _read_data, wind_mach_chooice
-
- colour = ["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 mydict
-
- def plt_init():
- # 繪圖初始化
- pg.setConfigOption("background", "w")
- plt = pg.PlotWidget()
- plt.addLegend(size=(150, 80))
- plt.showGrid(x=True, y=True, alpha=0.5)
- return plt
-
- def 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 plt
-
- if __name__ == '__main__':
- _data_to_dict()
- pass
模擬給其它文件傳指定數據
- # TmpData.py 文件名
- import os
- import numpy as np
-
- file_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, pyqtSignal
-
- class 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實現數據可視化教程就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持我們。
相關信息
-
PyTorch兩種安裝方法
PyTorch兩種安裝方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值...
2021-03-29
-