1. 程式人生 > 程式設計 >Python3.x+pyqtgraph實現資料視覺化教程

Python3.x+pyqtgraph實現資料視覺化教程

1、pyqtgraph庫資料視覺化效果還不錯,特別是窗體程式中影象互動性較好;安裝也很方便,用 pip 安裝。

2、在Python中新建一個 .py 檔案,然後寫入如下程式碼並執行可以得到官方提供的很多案例(含程式碼),出現如下介面影象:

import pyqtgraph.examples
pyqtgraph.examples.run()

Python3.x+pyqtgraph實現資料視覺化教程

圖1

Python3.x+pyqtgraph實現資料視覺化教程

圖2

Python3.x+pyqtgraph實現資料視覺化教程

圖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,QAction)
from PyQt5.QtCore import Qt,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,20))
  h1_wlayout.addWidget(QLabel("葉片ID"),0)
  h1_wlayout.addWidget(self.h1_combox3,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)
  v4_group_imf.addWidget(self.radio_2,1)
  v4_group_imf.addWidget(self.radio_3,1,0)
  v4_group_imf.addWidget(self.radio_4,1)
  v4_group_imf.addWidget(self.radio_5,2,0)
  v4_group_imf.addWidget(self.radio_6,1)
  v4_group_imf.addWidget(self.radio_7,3,0)
  v4_group_imf.addWidget(self.radio_8,1)
  v4_group_imf.addWidget(self.radio_9,4,0)

  v4_group_prior.addWidget(cb1,0)
  v4_group_prior.addWidget(cb2,0)
  v4_group_prior.addWidget(cb3,0)
  v4_group_prior.addWidget(QLabel("選擇是:"),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,f):
  print("*****執行列印*****")
  print(wind_mach_chooice(a))
  print(a,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",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實現資料視覺化教程就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。