0

so I just started a new project in which I need to present data I collected on a GUI. For that purpose I created a test script, that reads the data from a .mat file and then calculates the surface plots. So far everything is working. Now I need to start with the GUI. I already managed to create an other test program that can open the OpenFileName-Dialog and reads the data from the file.

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

Since I can read the data, next step would be to create the surface plots and display the data. My idea was to use the graphicsView elements to display the four needed plots, but I just can't find how to link the figures, I used in the first test program (without GUI) to the graphicsView element. For the figure I used the following code line:

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)

Can someone give me a tip, how I could achieve that?

Edit: I uploaded a .mat File .mat File

user3794592
  • 183
  • 2
  • 16

1 Answers1

3

I have to note that:

  • mat73 has trouble reading the provided .mat so I use scipy.
  • The data contained in the .mat are one-dimensional arrays so they could not form a surface since for this two-dimensional arrays are required so I will only show how to draw the points.
  • Due to the large number of dots, painting takes time and may freeze

The logic is to work with the FigureCanvas and create 3d plots:

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

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you for your code. It seems that the .mat file got changed by Matlab, when I deleted some datapoint, which I'm not allowed to share. That must be the reason why mat73 is not working. The .mat files I receive from the recording software can be read just by using mat73. The data I shared with you, is actually the same data I'm using for the calculation, I just create the needed arrays with the three arrays. – user3794592 Oct 25 '21 at 17:04
  • I just tried to update my code with the code you provided, but I do not get a plot. What I don't get are the following points: I'm using 'class Ui_MainWindow(object)', but you are using 'MainWindow(QMainWindow)', what is the differenc? I'm creating the code using the QT Desinger. Also how can I set the position of the plot. In my GUI I need to show four surface plots at the same time. That's why I created such a big main window – user3794592 Oct 25 '21 at 17:10
  • @user3794592 read https://stackoverflow.com/questions/46544780/qtdesigner-changes-will-be-lost-after-redesign-user-interface – eyllanesc Oct 25 '21 at 17:18
  • Thank you for the link. I will update my code, for using a logic.py and Design.py – user3794592 Oct 25 '21 at 17:22
  • now updated my code, so that the figure is shown on the main window. So that works fine. But how can I set the geometry (the size of the figure and the position) of the plot? I also want to show four plots on one screen. For that, can I create multiple instances of the subplot and call multiple times the update_plot() method? – user3794592 Oct 26 '21 at 07:36
  • I already figured it out, thanks for your help. For documentation, I'm using four instances of the subplot command and use the grid location of the subplot – user3794592 Oct 26 '21 at 08:12