在 GUI 中创建多个曲面图

Posted

技术标签:

【中文标题】在 GUI 中创建多个曲面图【英文标题】:Create multiple surface plots in GUI 【发布时间】:2021-10-25 14:59:41 【问题描述】:

所以我刚刚开始了一个新项目,我需要在其中展示我在 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 元素来显示四个需要的图,但我只是找不到如何链接这些数字,我在第一个测试程序(没有 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

【问题讨论】:

请分享一些.mat @eyllanesc 我将链接添加到 .mat 文件中,我将用于曲面图 如何读取此文件以获取 X、Y 和 Z? 我可以读取数据:TempRef、Nr 和 TempAct,但它们是 1162334x1 数组,但它们不会形成表面,因为为此它们需要是二维数组 【参考方案1】:

我必须注意:

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_())

【讨论】:

感谢您的代码。当我删除一些不允许共享的数据点时,Matlab 似乎更改了 .mat 文件。这一定是 mat73 不起作用的原因。我从录音软件收到的 .mat 文件只需使用 mat73 即可读取。我和你分享的数据,其实就是我用来计算的数据,我只是用三个数组创建了需要的数组。 我只是尝试使用您提供的代码更新我的代码,但我没有得到绘图。我没有得到以下几点:我使用的是'class Ui_MainWindow(object)',但你使用的是'MainWindow(QMainWindow)',有什么区别?我正在使用 QT Desinger 创建代码。另外我该如何设置情节的位置。在我的 GUI 中,我需要同时显示四个曲面图。这就是为什么我创建了这么大的主窗口 @user3794592 阅读***.com/questions/46544780/… 感谢您的链接。我将更新我的代码,以使用 logic.py 和 Design.py 现在更新了我的代码,使图形显示在主窗口中。所以效果很好。但是如何设置绘图的几何形状(图形的大小和位置)?我还想在一个屏幕上显示四个图。为此,我可以创建子图的多个实例并多次调用 update_plot() 方法吗?

以上是关于在 GUI 中创建多个曲面图的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中创建 xyz 高度数据的曲面图

使用 R 绘制带有等高线图叠加的 3D 曲面图

Matlab中的矢量化代码

曲面曲率驱动的斑图传播

曲面曲率驱动的斑图传播

使用 Plotly 绘制动画 3D 曲面图