在 GUI 中创建多个曲面图

Create multiple surface plots in GUI

所以我刚开始一个新项目,我需要在 GUI 上展示我收集的数据。为此,我创建了一个测试脚本,它从 .mat 文件中读取数据,然后计算曲面图。到目前为止一切正常。现在我需要从 GUI 开始。我已经设法创建了另一个可以打开 OpenFileName-Dialog 并从文件中读取数据的测试程序。

from PyQt5 import QtCore, QtGui, QtWidgets
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QFileDialog
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as Navi
from matplotlib.figure import Figure
import seaborn as sns
import pandas as pd
import sip
import h5py
import mat73
import numpy as np

class MatplotlibCanvas(FigureCanvasQTAgg):
    def __init__(self, parent=None, width = 5, height = 4, dpi = 120):
        fig = Figure(figsize = (width,height))
        self.axes = fig.add_subplot(111)
        super(MatplotlibCanvas,self).__init__(fig)
        fig.tight_layout()

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1466, 910)
        font = QtGui.QFont()
        font.setFamily("Tahoma")
        MainWindow.setFont(font)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
        self.graphicsView.setGeometry(QtCore.QRect(280, 0, 561, 441))
        self.graphicsView.setObjectName("graphicsView")
        self.graphicsView_2 = QtWidgets.QGraphicsView(self.centralwidget)
        self.graphicsView_2.setGeometry(QtCore.QRect(860, 0, 561, 441))
        self.graphicsView_2.setObjectName("graphicsView_2")
        self.graphicsView_3 = QtWidgets.QGraphicsView(self.centralwidget)
        self.graphicsView_3.setGeometry(QtCore.QRect(280, 440, 561, 441))
        self.graphicsView_3.setObjectName("graphicsView_3")
        self.graphicsView_4 = QtWidgets.QGraphicsView(self.centralwidget)
        self.graphicsView_4.setGeometry(QtCore.QRect(860, 440, 561, 441))
        self.graphicsView_4.setObjectName("graphicsView_4")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(40, 90, 75, 23))
        self.pushButton.setObjectName("pushButton")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.action_Open = QtWidgets.QAction(MainWindow)
        self.action_Open.setObjectName("action_Open")
        self.action_Save = QtWidgets.QAction(MainWindow)
        self.action_Save.setObjectName("action_Save")
        self.action_Export = QtWidgets.QAction(MainWindow)
        self.action_Export.setObjectName("action_Export")
        self.action_Exit = QtWidgets.QAction(MainWindow)
        self.action_Exit.setObjectName("action_Exit")

        self.filename = ''
        self.canv = MatplotlibCanvas(self)
        self.df = []

        self.toolbar = Navi(self.canv, self.centralwidget)

        self.pushButton.clicked.connect(self.getFile)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def getFile(self):
        """ this function will get the adress of the mat file location
            also calls a readData function
        """
        self.filename = QFileDialog.getOpenFileName(filter="mat (*.mat)")[0]
        print("File: ", self.filename)
        self.readData()

    def readData(self):
        self.df = mat73.loadmat(self.filename, use_attrdict=True)
        struct = self.df['DemoData']
        print(struct.Nr.data)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Open "))
        self.action_Open.setText(_translate("MainWindow", "&Open"))
        self.action_Save.setText(_translate("MainWindow", "&Save"))
        self.action_Export.setText(_translate("MainWindow", "&Export"))
        self.action_Exit.setText(_translate("MainWindow", "&Quit"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

既然我可以读取数据,下一步就是创建曲面图并显示数据。我的想法是使用 graphicsView 元素来显示四个需要的图,但我找不到如何 link 数字,我在第一个测试程序(没有 GUI)中使用了 graphicsView 元素。对于该图,我使用了以下代码行:

fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
surf = ax.plot_surface(pArray, rArray, trArray, alpha = 0.5)
surf = ax.plot_surface(pArray, rArray, tArray, cmap=cm.jet, alpha = 1)

谁能给我一个提示,我是怎么做到的?

编辑:我上传了一个 .mat 文件 .mat File

我要注意的是:

  • mat73 无法读取提供的 .mat 所以我使用 scipy.
  • .mat 中包含的数据是一维数组,因此它们无法形成曲面,因为需要二维数组,所以我将只展示如何绘制点。
  • 由于点数较多,绘画需要时间,可能会卡顿

逻辑是使用 FigureCanvas 并创建 3d 图:

from functools import cached_property

from PyQt5.QtWidgets import QApplication, QFileDialog, QMainWindow

from matplotlib.backends.backend_qt5agg import (
    FigureCanvas,
    NavigationToolbar2QT as NavigationToolbar,
)
from matplotlib.figure import Figure
from matplotlib import cm

import scipy.io as sio


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.ax = self.canvas.figure.add_subplot(projection="3d")
        self.setCentralWidget(self.canvas)
        self.addToolBar(self.toolbar)

        file_menu = self.menuBar().addMenu("&File")
        open_action = file_menu.addAction("&Open")

        open_action.triggered.connect(self.handle_open_action_triggered)

    @cached_property
    def canvas(self):
        return FigureCanvas()

    @cached_property
    def toolbar(self):
        return NavigationToolbar(self.canvas, self)

    def handle_open_action_triggered(self):
        filename, _ = QFileDialog.getOpenFileName(self, filter="mat (*.mat)")
        if filename:
            self.load_mat(filename)

    def load_mat(self, filename):
        
        res = sio.loadmat(filename)
        record = res["record"]
        data = record["Data"]
        temp_ref = data[0, 0]["TempRef"][0, 0][0, 0]["data"]
        nr = data[0][0]["Nr"][0, 0][0, 0]["data"]
        temp_act = data[0, 0]["TempAct"][0, 0][0, 0]["data"]
        self.update_plot(temp_ref, nr, temp_act)


    def update_plot(self, x, y, z):
        print(x.shape, y.shape, z.shape)
        self.ax.scatter(x, y, z)
        self.canvas.draw()




if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())