python可视化----pyqtgraph

pyqtgraph 介绍

官网
基于numpy 、pyqt5、pyside2的纯python图形界面库。大部分绘图比matplotlib性能高。
跨平台性好
展示线、点、图像;
图形数据的快速实时更新;
交互式的平移、缩放
图片导出
画图样例
import pyqtgraph.examples
pyqtgraph.examples.run()

使用pyqtgraph

  1. 查看案例
from pyqtgraph import examples
examples.run()

在弹出的窗口中,双击一个即可查看效果:
在这里插入图片描述
2. 在pyside2中使用pyqtgraph

# __author__ = "laufing"
# class_based_qt
# laufing_qt


# -*- coding: utf-8 -*-
"""
In this example we draw two different kinds of histogram.
"""
from PySide2.QtWidgets import QWidget, QApplication
from PySide2.QtGui import QIcon, QPixmap, QPicture, QFont
from PySide2.QtCore import QSize
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np


## 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_()
    app = QApplication(sys.argv)

    window = QWidget()
    window.resize(800, 600)
    window.move(200, 200)
    window.setWindowTitle("PySide2 案例")
    window.setWindowIcon(QIcon("./imgs/dog.jpg"))

    # ***
    # 实例化一个图形布局控件
    win = pg.GraphicsLayoutWidget(window, show=True)
    win.resize(400, 250)
    print("窗口类型:", win)
    win.setWindowTitle('Histogram')

    # 添加一个图形
    plt1 = win.addPlot()
    plt2 = win.addPlot()
    print("图形对象:", plt1)

    # np.random.normal  正态分布随机采样
    # loc 均值  默认均值为0
    # scale 标准差  默认标准差为1   属于标准正态分布
    # size 采样的shape
    # np.hstack 水平拼接 一维数组
    vals = np.hstack([np.random.normal(size=500), np.random.normal(size=260, loc=4)])

    # 计算频数
    freq, section = np.histogram(vals, bins=np.linspace(-3, 8, 40))  # np.linspace 等差数列
    print("计算的区间:", section, len(section))
    print("计算的频数:", freq, len(freq))

    ## Using stepMode="center" causes the plot to draw two lines for each sample.
    ## notice that len(x) == len(y)+1
    plt1.plot(section, freq, stepMode="center", fillLevel=0, fillOutline=True, brush=(100, 50, 255, 150))
    # x, y
    # stepMode 步进模式
    # fillLevel
    # fillOutline 填充轮廓线
    # brush(r, g, b, a) 填充颜色 a为不透明度

    # 散点图
    y = pg.pseudoScatter(vals, spacing=0.15)
    # spacing  点之间的距离
    print("xxx:", y, len(y))

    # plt2.plot(vals, y, pen=None, symbol='o', symbolSize=5)
    plt2.plot(vals, y, pen=None, symbol='o', symbolSize=5, symbolPen=(0, 0, 0, 200), symbolBrush=(150, 100, 185, 150))
    # symbol  点形状
    # symbolSize  点大小
    # symbolPen  点边缘线 颜色
    # symbolBrush  点的填充颜色

    window.show()


    # 消息循环
    exit_code = app.exec_()
    print("退出的状态码:", exit_code)
    sys.exit(exit_code)

使用pyqtgraph总结

  1. 交互模式(ipython)
    快速展示数据
import pyqtgraph as pg

# 1 plot画图
# pg.plot(data)   # data  list or ndarray (n, ) (n, 2)
# plot x vs y in red line, return PlotWidget obj
pw = pg.plot(xVals, yVals, pen='r') 
# 继续绘制数据
pw.plot(xVals, yVals2, pen='b')
pw.setTitle("标题", color="cyan")
pw.setBackground((x,x,x,x))  # RGBW
# 展示
pg.exec()

# 2 图形布局
win = pg.GraphicsLayoutWidget(parent)  # Automatically generates grids with multiple items
plot1 = win.addPlot(data1, row=0, col=0)  # 不指定row/col时,默认在一行 win.nextRow() 换行
plot2 = win.addPlot(data2, row=0, col=1)
plot3 = win.addPlot(data3, row=1, col=0, colspan=2)
# 展示
pg.exec()

# 图3
import numpy as np
data = np.array([2,1,4,5,4,3]).reshape(2,3)
pg.show(data)  # data must be a numpy array with 2 to 4 dims

# 最后展示
pg.exec()

图3
在这里插入图片描述
 
 

  1. 应用弹窗绘图
    应用程序中数据状态的即时反馈

  2. 嵌入到pyqt 控件,如pyside2/pyqt5
    如果两个库都有安装,先导入哪个库,pyqtgraph就用哪个。

## this will force pyqtgraph to use PySide2 instead of PyQt5
import PySide2  
import pyqtgraph as pg

PlotWidget, ImageView, GraphicsLayoutWidget, and GraphicsView.

 
 

pyqtgraph 画图方式

官网

基本参数

x - x轴数据,可选,未指定时自动生成

y - y轴数据

pen - 指定pen=‘r’ …绘制线;None 不绘制线

symbol - 可选,点形状 如"o"/“s” ; 也可指定每个点的形状[“o”, “s”, “o”]

symbolPen - 点的边缘线颜色 ‘r’

symbolBrush - 点的填充色 (r, g, b, a)

fillLevel - 填充线下区域 1

brush - 填充线下区域的颜色(r, g, b, a)

其他参数

绘图方法

  1. 绘制一个图形窗口
    pyqtgraph.plot(*args, **kargs), 一般用于交互模式
# 导包
from PySide2.QtWidgets import QApplication
import pyqtgraph as pg


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

	# 单独绘制图形,形成一个主窗口
    # 创建并返回一个PlotWidget 对象 (pyqtgraph.PlotWidget)
    plotWidget = pg.plot(title="title666")  # title 为窗口标题
	# 设置宽高   
    plotWidget.resize(400, 400)
    # 绘制图形
    plotWidget.plot([1,2,3], [3,4,5], pen='r')  
    # plotWidget.setBackground()

	# 循环画图
	# for i in range(3)
	# 	 plotWidget.plot(x, y[i], pen=(i, 3)) # 自动生成三种颜色

	# 消息循环
    sys.exit(app.exec_())

 
2. 嵌入pyqt控件中,使用PlotWidget/ GraphicsLayoutWidget
在这里插入图片描述
单个图形:


from PySide2.QtWidgets import QApplication, QWidget
import pyqtgraph as pg


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

    window = QWidget()
    window.resize(800, 600)
    window.setWindowTitle("图形嵌入控件")

    # 创建并返回一个PlotWidget 对象 (pyqtgraph.PlotWidget)
    plotWidget = pg.PlotWidget(window)
    plotWidget.resize(400, 400)
    plotWidget.move(100, 100)

    # 绘制图形
    # pen 画线图 "r"/(i, 3)自动生成三种颜色/QPen()
    # fillLevel 填充线下区域 开始的y值
    # fillBrush 填充的颜色
    plotWidget.plot([1,2,3], [3,4,5], pen='r', fillLevel=2, fillBrush=(100, 200, 150, 100))
    # 画图项
    plotItem = plotWidget.getPlotItem()
    print("plot item:", plotItem)
    print("函数:", dir(plotItem))
    # 设置标题
    plotWidget.setTitle("标题")
    plotWidget.setBackground("w")
    plotWidget.setLabel("left", 'y轴', units="cm", **style)  # 轴的标题
    plotWidget.setXRange(0, 5, spacing=0.5) # 轴的范围
    plotWidget.setLogMode(x=True, y=False) # 设置x轴 等比数列
    plotWidget.addLegend()  # 增加图例
    plotWidget.showGrid(x=True, y=True)
	plotWidget.enableAutoRange('xy', True)  # 坐标轴的值范围 会根据图形自动变化, False 则不变
	# 坐标轴的显示与隐藏
	plotWidget.showAxis("bottom", False)  # plotWidget底层是PlotItem
    window.show()


    sys.exit(app.exec_())

 
多个图形:
在这里插入图片描述


from PySide2.QtWidgets import QApplication, QWidget, QLabel, QPushButton
from PySide2.QtGui import QIcon, QPicture, QPixmap
import pyqtgraph as pg
import numpy as np


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

    window = QWidget()
    window.resize(800, 600)

    # 多个图形
    gl = pg.GraphicsLayoutWidget(window)
    gl.resize(800, 600)

    # 添加图形
    plot1 = gl.addPlot(row=0, col=0)
    plot2 = gl.addPlot(row=0, col=1)
    plot3 = gl.addPlot(row=1, col=0, colspan=2)
	
	# 设置线的样式 颜色、宽度
	myPen = pg.mkPen(color=(255, 0, 0), width=20, style=Qt.DashLine)
    plot1.plot([1,2,3], pen=myPen)
    plot2.plot([1,2,3], pen=None, symbol="s", symbolSize=6, symbolPen=(0, 0, 254, 150))
    plot3.plot([3,4,5], pen="b")

    window.show()
    sys.exit(app.exec_())
  1. 绘制2D、3D图形
    pyqtgraph.image(*args, **kargs)
    Create and return an ImageView Will show 2D or 3D image data. Accepts a title argument to set the title of the window. All other arguments are used to show data. (see ImageView.setImage())
  2. 控制台窗口
    pyqtgraph.dbg(*args, **kwds)
    Create a console window and begin watching for exceptions.

设置线的样式

from PySide2.QtCore import Qt
from pyqtgraph import mkPen
# 定义自己的pen
myPen = mkPen(color=(r, g, b, a), width=16, style=Qt.DashLine)

在这里插入图片描述

综合案例

  1. 设置线的样式
    在这里插入图片描述

from PySide2.QtWidgets import QWidget, QApplication, QPushButton, QDesktopWidget, QVBoxLayout
from PySide2.QtCore import Qt, QTimer, QSize, QDate
from PySide2.QtGui import QIcon, QPixmap, QPen, QPicture, QPalette, QPaintEvent, QDesktopServices, QColor
import pyqtgraph as pg
from pyqtgraph import PlotWidget
from pyqtgraph import mkPen # 生成画笔
from pyqtgraph import mkBrush  # 生成笔刷
from pyqtgraph import mkColor  # 生成颜色对象


class MyWindow(QWidget):
    def __init__(self, title="laufing"):
        super(MyWindow, self).__init__()
        # 窗口的尺寸及居中
        self.resize(800, 600)
        desk = QDesktopWidget().geometry()
        width, height = desk.width(), desk.height()
        self.move(width//2 - self.width()//2, height//2 - self.height()//2)

        # 窗口标题
        self.setWindowTitle(title)
        self.setWindowIcon(QIcon("./imgs/dog.jpg"))

        #
        self.setUI()

    def setUI(self):
        # 垂直布局
        vb = QVBoxLayout()
        vb.setContentsMargins(10, 10, 10, 10) # 设置内容边距
        vb.setSpacing(20) # 子控件间隔

        # 实例化 绘图控件
        plotWidget1 = PlotWidget()
        plotWidget2 = PlotWidget()

        # 绘制数据
        import numpy as np
        # 正态分布采样 均值为2 标准差1  采样数据shape
        x = np.random.normal(loc=2, scale=1, size=(2, 5))

        # 生成自己的画笔
        myPen = mkPen(color=(170, 0, 0), width=16, style=Qt.DotLine)

        # 绘制图形
        line1 = plotWidget1.plot(x[0], pen=myPen)
        # 设置图形标题
        plotWidget1.setTitle("图1", color="r", size="10pt")  # size为字符串
        # 设置背景色
        plotWidget1.setBackground("w")  # 单个字母表示颜色

        line2 = plotWidget2.plot(x[1], pen='b', name="图例legend", symbol="+", symbolSize=16, symbolPen=(0, 255, 0, 150),
                         symbolBrush=(254, 0, 0, 100))  # symbol 添加标记
        plotWidget2.setTitle("图2", color="k", size="15pt")  # 15px ,也支持富文本html
        plotWidget2.setBackground((254, 249, 226))  # RGB 表颜色
        # plotWidget2.setBackground(QColor(254, 249, 226))

        # 设置轴的标题
        y_style = {  # css键值对
            "color": "red",
            "font-size": "16px",
            "text-align": "center",
            "font-family": "宋体",
            "font-weight": "bold",
            "font-style": "italic"
        }
        plotWidget2.setLabel("left", "y轴", **y_style)  # 支持富文本
        plotWidget2.setLabel("bottom", "x轴", **y_style)
        # 为曲线增加图例(?)
        plotWidget2.addLegend()
        # 显示网格线
        plotWidget2.showGrid(x=True, y=True)

        # 轴的范围
        plotWidget2.setYRange(0, 4, padding=0)
        plotWidget2.setXRange(0, 5, padding=0)

        # 清除线条
        # plotWidget2.clear()

        # 更新局部数据
        def updateLine():
            nonlocal x  # 外部函数的局部作用域
            print("xxx:", x)
            # 生成数据
            x = np.random.normal(loc=2, scale=1, size=(2, 5))
            # 更新图形中的数据
            line2.setData(x[1])

        self.timer = QTimer(plotWidget2)
        self.timer.timeout.connect(updateLine)
        self.timer.start(500)  # 0.5s 执行一次

        # 布局添加子控件
        vb.addWidget(plotWidget1)
        vb.addWidget(plotWidget2)
        vb.setStretch(0, 1)  # idx, value子控件的伸缩因子
        vb.setStretch(1, 2)


        self.setLayout(vb)


if __name__ == '__main__':
    import sys
    # 创建应用程序
    app = QApplication(sys.argv)

    win = MyWindow("测试可视化")
    win.show()

    # 进入消息循环
    sys.exit(app.exec_())

  1. 设置边界线
    拖动左边的边界线,右图的轴范围变化。
    在这里插入图片描述
# __author__ = "laufing"
# class_based_qt
# laufing_qt


from PySide2.QtWidgets import QWidget, QApplication, QDesktopWidget, QHBoxLayout, QVBoxLayout
from PySide2.QtCore import QTimer
from PySide2.QtGui import QIcon, QPixmap, QPicture, QColor, QFont, QKeyEvent, QMouseEvent, QDesktopServices
import pyqtgraph as pg
from pyqtgraph import mkPen
from pyqtgraph import PlotWidget, PlotItem, GraphicsLayoutWidget
import numpy as np


class MyWindow(QWidget):
    def __init__(self):
        super(MyWindow, self).__init__()

        #
        desk = QDesktopWidget().geometry()
        width, height = desk.width(), desk.height()
        self.resize(800, 600)
        self.move(width//2 - self.width()//2, height//2 - self.height()//2)
        self.setWindowTitle("laufing")
        self.setWindowIcon(QIcon("./imgs/dog.jpg"))
        #
        self.setUi()

    def setUi(self):
        hb= QHBoxLayout()
        hb.setContentsMargins(10, 10, 10, 10)
        hb.setSpacing(6)

        # 生成数据
        x = np.linspace(-100, 100, 1000)
        y = np.sin(x) / x

        graphic = GraphicsLayoutWidget(self)

        # 添加图形, 默认水平排列
        plotItem1 = graphic.addPlot()
        print("plot item:", plotItem1, dir(plotItem1))
        plotItem2 = graphic.addPlot()

        plotItem1.plot(x, y, pen="r")
        # plotItem1.setTitle("graphic1", color="r")
        # plotItem1.setBackground("w") 没有该属性
        # plotItem1.setLabel("left", "y轴", units="cm", color="blue")
        # plotItem1.setLabel("bottom", "x轴", units="cm", color="blue")
        # plotItem1.addLegend()  # 无效
        # plotItem1.showGrid(x=True, y=True)

        # 添加边界线
        lineItem = pg.LinearRegionItem([-50, 50])
        lineItem.setZValue(10)
        plotItem1.addItem(lineItem)

        # 添加事件
        def updatePlotItem2():
            print("xxxx", lineItem.getRegion())
            # 第二个图更新 坐标值
            plotItem2.setXRange(*lineItem.getRegion(), padding=0)

        def updatePlotItem1():
            # 获取图2的XRange & YRange
            print("view box:", plotItem2.getViewBox().viewRange())
            # 重新设置线的范围
            lineItem.setRegion(plotItem2.getViewBox().viewRange()[0])

        # 线的区域发生变化
        lineItem.sigRegionChanged.connect(updatePlotItem2)
        # plotItem2 的坐标轴发生变化
        plotItem2.sigXRangeChanged.connect(updatePlotItem1)

        plotItem2.plot(x, y, pen="g")

        # 布局添加子控件
        hb.addWidget(graphic)
        # 父窗口 添加子控件
        self.setLayout(hb)

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

    win = MyWindow()
    win.show()

    exit_code = app.exec_()
    sys.exit(exit_code)


 
3. 在上图的基础上,实现增加一个频率直方图
写好的窗口,直接作为一个子窗口
在这里插入图片描述

# __author__ = "laufing"
# class_based_qt
# laufing_qt

from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QHBoxLayout, QVBoxLayout
from PySide2.QtCore import QTimer
from PySide2.QtGui import QIcon, QFont, QColor
import pyqtgraph as pg
from pyqtgraph import GraphicsLayoutWidget, PlotWidget
from pyqtgraph_7 import MyWindow

class PWin(QWidget):
    def __init__(self):
        super(PWin, self).__init__()
        self.resize(800, 600)
        self.move(200, 200)
        self.setUI()

    def setUI(self):
        # 实例化布局对象
        vb = QVBoxLayout()

        # 第一个子控件,写好的子窗口
        myWin = MyWindow()

        # 第二个子控件
        pw = PlotWidget()
        # 生成数据
        import numpy as np
        x = np.random.normal(loc=1, scale=2, size=1000)
        freq, section = np.histogram(x, bins=50)
        pw.plot(section, freq, stepMode="center", fillLevel=0, fillBrush=(100, 100, 100), fillOutline="r")

        # 布局添加子控件
        vb.addWidget(myWin)
        vb.addWidget(pw)
        vb.setSpacing(10)
        vb.setStretch(0, 1)
        vb.setStretch(1, 1)
        # 父窗口 设置垂直布局
        self.setLayout(vb)


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

    pwin = PWin()
    pwin.show()

    exit_code = app.exec_()
    sys.exit(exit_code)


 
4. 在已写好的窗口上,扩展功能
一个Qt designer 界面就是一个类, 类名为Ui_创建对象名
在这里插入图片描述


from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
import logging
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(message)s")

class Ui_Lauf(object):
    def setupUi(self, Lauf):
        # Lauf 为父控件
        if not Lauf.objectName():
            Lauf.setObjectName(u"Lauf")
        # 重置父控件的宽高
        Lauf.resize(1086, 692)

        # 创建一个空白窗口,放入父控件
        self.widget = QWidget(Lauf)
        self.widget.setObjectName(u"widget")
        self.widget.setGeometry(QRect(150, 70, 430, 197))

        # 在空白窗口中,实例化网格布局
        self.gridLayout = QGridLayout(self.widget)
        self.gridLayout.setObjectName(u"gridLayout")
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        # 垂直布局
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setObjectName(u"verticalLayout")
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName(u"horizontalLayout")

        #
        self.label = QLabel(self.widget)
        self.label.setObjectName(u"label")

        self.horizontalLayout.addWidget(self.label)

        self.lineEdit = QLineEdit(self.widget)
        self.lineEdit.setObjectName(u"lineEdit")
        # 尺寸策略
        sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        logging.debug(self.lineEdit.sizePolicy().hasHeightForWidth())
        # 设置宽高比
        sizePolicy.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth())
        # 设置尺寸策略
        self.lineEdit.setSizePolicy(sizePolicy)

        self.horizontalLayout.addWidget(self.lineEdit)


        self.verticalLayout.addLayout(self.horizontalLayout)

        self.horizontalLayout_2 = QHBoxLayout()
        self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
        self.label_2 = QLabel(self.widget)
        self.label_2.setObjectName(u"label_2")

        self.horizontalLayout_2.addWidget(self.label_2)

        self.lineEdit_2 = QLineEdit(self.widget)
        self.lineEdit_2.setObjectName(u"lineEdit_2")
        sizePolicy.setHeightForWidth(self.lineEdit_2.sizePolicy().hasHeightForWidth())
        self.lineEdit_2.setSizePolicy(sizePolicy)

        self.horizontalLayout_2.addWidget(self.lineEdit_2)


        self.verticalLayout.addLayout(self.horizontalLayout_2)

        self.pushButton = QPushButton(self.widget)
        self.pushButton.setObjectName(u"pushButton")

        self.verticalLayout.addWidget(self.pushButton)

        # 网格布局 row, col, rowSpan, colSpan
        self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)

        self.lineEdit_5 = QLineEdit(self.widget)
        self.lineEdit_5.setObjectName(u"lineEdit_5")

        self.gridLayout.addWidget(self.lineEdit_5, 0, 1, 1, 1)

        self.formLayout = QFormLayout()
        self.formLayout.setObjectName(u"formLayout")
        self.label_3 = QLabel(self.widget)
        self.label_3.setObjectName(u"label_3")
        # self.formLayout.addRow()
        # 设置第0行的Label  Field
        self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_3)

        self.lineEdit_3 = QLineEdit(self.widget)
        self.lineEdit_3.setObjectName(u"lineEdit_3")

        self.formLayout.setWidget(0, QFormLayout.FieldRole, self.lineEdit_3)

        self.label_4 = QLabel(self.widget)
        self.label_4.setObjectName(u"label_4")

        self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_4)

        self.lineEdit_4 = QLineEdit(self.widget)
        self.lineEdit_4.setObjectName(u"lineEdit_4")

        self.formLayout.setWidget(1, QFormLayout.FieldRole, self.lineEdit_4)

        self.pushButton_2 = QPushButton(self.widget)
        self.pushButton_2.setObjectName(u"pushButton_2")

        self.formLayout.setWidget(2, QFormLayout.SpanningRole, self.pushButton_2)


        self.gridLayout.addLayout(self.formLayout, 1, 0, 1, 1)

        self.lineEdit_6 = QLineEdit(self.widget)
        self.lineEdit_6.setObjectName(u"lineEdit_6")

        self.gridLayout.addWidget(self.lineEdit_6, 1, 1, 1, 1)

        # 自定义方法, 设置标题
        self.retranslateUi(Lauf)

        QMetaObject.connectSlotsByName(Lauf)
    # setupUi

    def retranslateUi(self, Lauf):
    	# 设置标题
        Lauf.setWindowTitle(QCoreApplication.translate("Lauf", u"Form", None))
        self.label.setText(QCoreApplication.translate("Lauf", u"\u7528\u6237\u540d:", None))
        self.label_2.setText(QCoreApplication.translate("Lauf", u"\u7528\u6237\u5bc6\u7801:", None))
        self.pushButton.setText(QCoreApplication.translate("Lauf", u"\u767b\u5f55", None))
        self.lineEdit_5.setText(QCoreApplication.translate("Lauf", u"\u6c34\u5e73 + \u5782\u76f4\u5e03\u5c40", None))
        self.label_3.setText(QCoreApplication.translate("Lauf", u"\u7528\u6237\u540d:", None))
        self.label_4.setText(QCoreApplication.translate("Lauf", u"\u7528\u6237\u5bc6\u7801:", None))
        self.pushButton_2.setText(QCoreApplication.translate("Lauf", u"\u767b\u5f55", None))
        self.lineEdit_6.setText(QCoreApplication.translate("Lauf", u"Form Layout", None))
    # retranslateUi


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

    # 一个Qt designer 界面就是一个类
    win = QWidget()

    # 实例化Qt designer 设计的窗口
    u = Ui_Lauf()
    # 展示在父控件中
    u.setupUi(win)

    win.show()

    sys.exit(app.exec_())

 

绘制多个图形,并网格布局

  1. 绘制九个图形,并实现网格布局;
  2. 九个图形共享x、y坐标轴;
  3. 九个图形中相同颜色的曲线共享同一个图例;
    效果如下:
    在这里插入图片描述

代码:

# __author__ = "laufing"
# class_based_qt
# laufing_qt

import numpy as np
import logging
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)s %(message)s")
from PySide2.QtWidgets import QWidget, QApplication, QPushButton, QDesktopWidget, QVBoxLayout
from PySide2.QtCore import Qt, QTimer, QSize, QDate
from PySide2.QtGui import QIcon, QPixmap, QPen, QPicture, QPalette, QPaintEvent, QDesktopServices
import pyqtgraph as pg


class MyItemSample(pg.ItemSample):
    """ 自定义图例项目子类 """
    pen = None
    items = None
    instance = None

    def __new__(cls, item):
        """ item: PlotDataItem """
        item_pen = item.opts.get("pen")
        if item_pen == cls.pen:
            cls.items.append(item)
            return cls.instance

        cls.pen = item_pen
        cls.instance = pg.ItemSample.__new__(cls)
        cls.items = []
        cls.items.append(item)
        return cls.instance

    def __init__(self, item):
        # 对象具有自己的items
        self.items = self.__class__.items
        if len(self.items) > 1:
            return
        else:
            pg.ItemSample.__init__(self, item)

    def mouseClickEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            for i in self.items:
                i.setVisible(not i.isVisible())

        event.accept()
        self.update()


class MyLegendItem(pg.LegendItem):
    """ 自定义图例 子类 """
    pen = None
    name = None

    def addItem(self, item, name):
        """ 重写 """

        self.sampleType = MyItemSample
        label = pg.LabelItem(name, color=self.opts['labelTextColor'],
                          justify='left', size=self.opts['labelTextSize'])
        if isinstance(item, self.sampleType):
            sample = item
        else:
            sample = self.sampleType(item)
        self.items.append((sample, label))

        if item.opts.get("pen") != self.pen and name != self.name:
            self.pen = item.opts.get("pen")
            self.name = name
        elif item.opts.get("pen") == self.pen and name == self.name:
            return
        else:
            raise ValueError("同一类曲线图例名称必须相同")
        self._addItemToLayout(sample, label)
        self.updateSize()


class MyWindow(QWidget):
    def __init__(self, title="laufing"):
        super(MyWindow, self).__init__()
        # 窗口的尺寸及居中
        self.resize(800, 600)
        desk = QDesktopWidget().geometry()
        width, height = desk.width(), desk.height()
        self.move(width//2 - self.width()//2, height//2 - self.height()//2)

        # 窗口标题
        self.setWindowTitle(title)
        self.setWindowIcon(QIcon("./imgs/dog.jpg"))

        #
        self.setUI()

    def setUI(self):
        data = np.random.normal(loc=2, scale=1, size=100)

        # 垂直布局
        vb = QVBoxLayout(self)
        graphic_view = pg.GraphicsView()
        graphic_view.setBackground("#eee")
        vb.addWidget(graphic_view)

        # layout 布局
        graphic_layout = pg.GraphicsLayout(border=(255, 0, 0))
        graphic_view.setCentralWidget(graphic_layout)

        # 添加一个标题
        label = graphic_layout.addLabel("首行标题", colspan=3)
        graphic_layout.nextRow()

        # 生成九个图形
        plot_items = []
        plot_data_items = []
        for i in range(9):
            if i == 3:
                legend_layout = graphic_layout.addLayout(rowspan=3)
                legend_layout.setFixedWidth(100)
                legend_item = MyLegendItem(size=(10, 10), offset=(0, 5))
                legend_item.setParentItem(legend_layout)
                # 图例边框色
                legend_item.setPen("b")
                # 填充色
                legend_item.setBrush("cyan")
                legend_item.setLabelTextColor("r")
                legend_item.setLabelTextSize("10pt")

            if i % 3 == 0 and i != 0:
                graphic_layout.nextRow()

            plot_item = graphic_layout.addPlot(title=f"title{i+1}")
            plot_items.append(plot_item)
            r_line = plot_item.plot(data, pen="r", symbol="s", symbolSize=3)
            b_line = plot_item.plot(np.sin(data) + 1, pen="b", symbol="o", symbolSize=3)
            plot_data_items.extend([r_line, b_line])
            # 隐藏坐标轴
            if i % 3 != 0:
                # 隐藏y轴
                plot_item.hideAxis("left")
                plot_item.hideButtons()

            if i / 6 < 1:
                # 隐藏x轴
                plot_item.hideAxis("bottom")
                plot_item.hideButtons()

        # 关联图形
        for i in range(len(plot_items) - 1):
            plot_items[i].setXLink(plot_items[i+1])
            plot_items[i].setYLink(plot_items[i+1])

        # 共享坐标轴后尺寸不一致问题
        graphic_layout.layout.setColumnStretchFactor(0, 100)
        graphic_layout.layout.setColumnStretchFactor(1, 90)
        graphic_layout.layout.setColumnStretchFactor(2, 90)
        graphic_layout.layout.setRowStretchFactor(1, 85)
        graphic_layout.layout.setRowStretchFactor(2, 85)
        graphic_layout.layout.setRowStretchFactor(3, 100)

        # 添加图例
        for i in range(0, len(plot_data_items), 2):
            legend_item.addItem(plot_data_items[i], "图例1")

        for i in range(1, len(plot_data_items), 2):
            legend_item.addItem(plot_data_items[i], "图例2")


if __name__ == '__main__':
    import sys
    # 创建应用程序
    app = QApplication(sys.argv)

    win = MyWindow("测试可视化")
    win.show()

    # 进入消息循环
    sys.exit(app.exec_())

  • 5
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值