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实现数据可视化教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。
相关信息