From 2697acddfe03c9d1e6bc8eb02facc8e67b116d47 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Tue, 11 Mar 2025 09:34:04 +0100 Subject: [PATCH] Sample data: Refactoring some functions. --- View/sample_data_tab.py | 261 ++++++++++++++++++++++++++-------------- 1 file changed, 172 insertions(+), 89 deletions(-) diff --git a/View/sample_data_tab.py b/View/sample_data_tab.py index 7d714e6..4eec985 100644 --- a/View/sample_data_tab.py +++ b/View/sample_data_tab.py @@ -20,12 +20,8 @@ # -*- coding: utf-8 -*- - -from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, QLabel, QSpacerItem, QSizePolicy, - QTableWidget, QPushButton, QLineEdit, - QTableWidgetItem, QComboBox, QFileDialog, QGridLayout, QMessageBox) -from PyQt5.QtGui import QIcon -from PyQt5.QtCore import Qt, QCoreApplication, pyqtSignal +import os +import logging import numpy as np import pandas as pd @@ -36,7 +32,13 @@ from matplotlib.colors import LogNorm, BASE_COLORS from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolBar -from os import path +from PyQt5.QtWidgets import ( + QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, QLabel, + QSpacerItem, QSizePolicy, QTableWidget, QPushButton, QLineEdit, + QTableWidgetItem, QComboBox, QFileDialog, QGridLayout, QMessageBox +) +from PyQt5.QtGui import QIcon +from PyQt5.QtCore import Qt, QCoreApplication, pyqtSignal from Model.granulo_loader import GranuloLoader @@ -48,6 +50,7 @@ import settings as stg _translate = QCoreApplication.translate +logger = logging.getLogger() class SampleDataTab(QWidget): @@ -57,8 +60,7 @@ class SampleDataTab(QWidget): def __init__(self, widget_tab): super().__init__() - path_icon = "./icons/" - icon_folder = QIcon(path_icon + "folder.png") + icon_folder = QIcon(os.path.join("icons", "folder.png")) ### --- General layout of widgets --- @@ -269,20 +271,36 @@ class SampleDataTab(QWidget): self.groupbox_plot_PSD.setTitle(_translate("CONSTANT_STRING", cs.DISTRIBUTION_PLOT)) - # ------------------------------------------------------------------------------------------------------------------ - # --- Function to select directory and file name of fine sediments sample data --- - def open_dialog_box_fine_sediment(self): + def last_opened_file_path(self, priority="sand"): + lst = [] + + if priority == "sand": + lst += [stg.path_sand] + lst += [stg.path_fine] + else: + lst += [stg.path_fine] + lst += [stg.path_sand] + + lst += stg.path_BS_raw_data + + for path in lst: + if path != "": + return path + + return "" + + def open_dialog_box_fine_sediment(self): filename_fine_sediment = QFileDialog.getOpenFileName( self, "Fine sediment file", - [stg.path_fine if stg.path_fine else stg.path_sand if stg.path_sand - else stg.path_BS_raw_data[-1] if self.combobox_acoustic_data.count() > 0 else ""][0], + self.last_opened_file_path(priority="fine"), "Fine sediment file (*.xlsx, *xls, *.ods)", - options=QFileDialog.DontUseNativeDialog) + options=QFileDialog.DontUseNativeDialog + ) try: - stg.path_fine = path.dirname(filename_fine_sediment[0]) - stg.filename_fine = path.basename(filename_fine_sediment[0]) + stg.path_fine = os.path.dirname(filename_fine_sediment[0]) + stg.filename_fine = os.path.basename(filename_fine_sediment[0]) self.load_fine_sediment_data() except IsADirectoryError: msgBox = QMessageBox() @@ -291,25 +309,24 @@ class SampleDataTab(QWidget): msgBox.setText("Please select a file") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() + except Exception as e: + logger.error(e) else: self.lineEdit_fine_sediment.clear() self.lineEdit_fine_sediment.setText(stg.filename_fine) self.lineEdit_fine_sediment.setToolTip(stg.path_fine) self.fill_table_fine() - # --- Function to select directory and file name of sand sediments sample data --- def open_dialog_box_sand_sediment(self): - filename_sand_sediment = QFileDialog.getOpenFileName( self, "Sand sediment file", - [stg.path_sand if stg.path_sand else stg.path_fine if stg.path_fine - else stg.path_BS_raw_data[-1] if self.combobox_acoustic_data.count() > 0 else ""][0], + self.last_opened_file_path(priority="sand"), "Sand sediment file (*.xlsx, *xls, *.ods)", options=QFileDialog.DontUseNativeDialog) try: - stg.path_sand = path.dirname(filename_sand_sediment[0]) - stg.filename_sand = path.basename(filename_sand_sediment[0]) + stg.path_sand = os.path.dirname(filename_sand_sediment[0]) + stg.filename_sand = os.path.basename(filename_sand_sediment[0]) self.load_sand_sediment_data() except IsADirectoryError: msgBox = QMessageBox() @@ -318,13 +335,17 @@ class SampleDataTab(QWidget): msgBox.setText("Please select a file") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() + except Exception as e: + logger.error(e) else: self.lineEdit_sand_sediment.setText(stg.filename_sand) self.lineEdit_sand_sediment.setToolTip(stg.path_sand) self.fill_table_sand() def load_fine_sediment_data(self): - fine_granulo_data = GranuloLoader(stg.path_fine + "/" + stg.filename_fine) + fine_granulo_data = GranuloLoader( + os.path.join(stg.path_fine, stg.filename_fine) + ) stg.columns_fine = fine_granulo_data._data.columns stg.time_fine = fine_granulo_data._time stg.distance_from_bank_fine = fine_granulo_data._y @@ -336,7 +357,9 @@ class SampleDataTab(QWidget): stg.frac_vol_fine_cumul = fine_granulo_data._frac_vol_cumul def load_sand_sediment_data(self): - sand_granulo_data = GranuloLoader(stg.path_sand + "/" + stg.filename_sand) + sand_granulo_data = GranuloLoader( + os.path.join(stg.path_sand, stg.filename_sand) + ) stg.columns_sand = sand_granulo_data._data.columns stg.time_sand = sand_granulo_data._time stg.distance_from_bank_sand = sand_granulo_data._y @@ -360,35 +383,54 @@ class SampleDataTab(QWidget): # --- Function to fill table of values --- def fill_table_fine(self): if self.lineEdit_fine_sediment.text(): - - self.row_fine = self.tableWidget_fine.setRowCount(len(stg.depth_fine)) - self.column_fine = self.tableWidget_fine.setColumnCount(6 + stg.radius_grain_fine.shape[0]) + self.row_fine = self.tableWidget_fine.setRowCount( + len(stg.depth_fine) + ) + self.column_fine = self.tableWidget_fine.setColumnCount( + 6 + stg.radius_grain_fine.shape[0] + ) # --- Set horizontal header --- - - horizontal_header = list(itertools.chain(["Color", "Sample"], - list(map(str, stg.columns_fine[[0, 2]])), - list(map(str, stg.columns_fine[3:])))) + horizontal_header = list( + itertools.chain( + ["Color", "Sample"], + list(map(str, stg.columns_fine[[0, 2]])), + list(map(str, stg.columns_fine[3:])) + ) + ) for horizontal_header_text in horizontal_header: self.horizontal_header_item_fine = QTableWidgetItem() - self.tableWidget_fine.setHorizontalHeaderItem(horizontal_header.index(horizontal_header_text), - self.horizontal_header_item_fine) + self.tableWidget_fine.setHorizontalHeaderItem( + horizontal_header.index(horizontal_header_text), + self.horizontal_header_item_fine + ) self.horizontal_header_item_fine.setText(horizontal_header_text) # --- Set vertical header (color) --- self.tableWidget_fine.verticalHeader().setVisible(False) color_list = BASE_COLORS + + self.comboBox_sample_table_fine = [] for i in range(self.tableWidget_fine.rowCount()): - exec("self.comboBox_sample_table_fine" + str(i) + "= QComboBox()") - exec("self.comboBox_sample_table_fine" + str(i) + ".addItems(color_list)") - eval(f"self.tableWidget_fine.setCellWidget(i, 0, self.comboBox_sample_table_fine{i})") - eval(f"self.comboBox_sample_table_fine{i}.currentTextChanged." - f"connect(self.plot_total_concentration)") - eval(f"self.comboBox_sample_table_fine{i}.currentTextChanged." - f"connect(self.plot_PSD_fine_and_sand_sediments)") - eval(f"self.comboBox_sample_table_fine{i}.currentTextChanged." - f"connect(self.update_plot_sample_position_on_transect)") + self.comboBox_sample_table_fine.append( + QComboBox() + ) + + self.comboBox_sample_table_fine[i].addItems(color_list) + self.tableWidget_fine.setCellWidget( + i, 0, self.comboBox_sample_table_fine[i] + ) + + self.comboBox_sample_table_fine[i]\ + .currentTextChanged\ + .connect(self.plot_total_concentration) + self.comboBox_sample_table_fine[i]\ + .currentTextChanged\ + .connect(self.plot_PSD_fine_and_sand_sediments) + self.comboBox_sample_table_fine[i]\ + .currentTextChanged\ + .connect(self.update_plot_sample_position_on_transect) # --- Fill Sample column with checkbox --- for i in range(self.tableWidget_fine.rowCount()): @@ -401,12 +443,21 @@ class SampleDataTab(QWidget): # --- Fill table with data --- for i in range(stg.frac_vol_fine.shape[0]): for j in range(stg.frac_vol_fine.shape[1]): - self.tableWidget_fine.setItem(i, 2, QTableWidgetItem(str(stg.time_fine[i]))) - self.tableWidget_fine.setItem(i, 3, QTableWidgetItem(str(stg.depth_fine[i]))) - - self.tableWidget_fine.setItem(i, 4, QTableWidgetItem(str(stg.Ctot_fine[i]))) - self.tableWidget_fine.setItem(i, 5, QTableWidgetItem(str(stg.D50_fine[i]))) - self.tableWidget_fine.setItem(i, j + 6, QTableWidgetItem(str(stg.frac_vol_fine[i, j]))) + self.tableWidget_fine.setItem( + i, 2, QTableWidgetItem(str(stg.time_fine[i])) + ) + self.tableWidget_fine.setItem( + i, 3, QTableWidgetItem(str(stg.depth_fine[i])) + ) + self.tableWidget_fine.setItem( + i, 4, QTableWidgetItem(str(stg.Ctot_fine[i])) + ) + self.tableWidget_fine.setItem( + i, 5, QTableWidgetItem(str(stg.D50_fine[i])) + ) + self.tableWidget_fine.setItem( + i, j + 6, QTableWidgetItem(str(stg.frac_vol_fine[i, j])) + ) # --- Connect checkbox to all checkboxes of tableWidget --- # self.allChkBox.stateChanged.connect(self.check_allChkBox) @@ -422,7 +473,6 @@ class SampleDataTab(QWidget): self.plot_sample_position_on_transect() self.plot_total_concentration() self.plot_PSD_fine_and_sand_sediments() - else: msgBox = QMessageBox() msgBox.setWindowTitle("Fill table Error") @@ -433,35 +483,47 @@ class SampleDataTab(QWidget): def fill_table_sand(self): if self.lineEdit_sand_sediment.text(): - self.row_sand = self.tableWidget_sand.setRowCount(len(stg.depth_sand)) self.column_sand = self.tableWidget_sand.setColumnCount(6 + stg.radius_grain_sand.shape[0]) - # --- Set horizontal header --- - - horizontal_header = list(itertools.chain(["Color", "Sample"], - list(map(str, stg.columns_sand[[0, 2]])), - list(map(str, stg.columns_sand[3:])))) + horizontal_header = list( + itertools.chain( + ["Color", "Sample"], + list(map(str, stg.columns_sand[[0, 2]])), + list(map(str, stg.columns_sand[3:])) + ) + ) for horizontal_header_text in horizontal_header: self.horizontal_header_item_sand = QTableWidgetItem() - self.tableWidget_sand.setHorizontalHeaderItem(horizontal_header.index(horizontal_header_text), - self.horizontal_header_item_sand) + self.tableWidget_sand.setHorizontalHeaderItem( + horizontal_header.index(horizontal_header_text), + self.horizontal_header_item_sand + ) self.horizontal_header_item_sand.setText(horizontal_header_text) # --- Set vertical header (color) --- self.tableWidget_sand.verticalHeader().setVisible(False) color_list = BASE_COLORS + + self.comboBox_sample_table_sand = [] for i in range(self.tableWidget_sand.rowCount()): - exec("self.comboBox_sample_table_sand" + str(i) + "= QComboBox()") - exec("self.comboBox_sample_table_sand" + str(i) + ".addItems(color_list)") - eval(f"self.tableWidget_sand.setCellWidget(i, 0, self.comboBox_sample_table_sand{i})") - eval(f"self.comboBox_sample_table_sand{i}.currentTextChanged." - f"connect(self.plot_total_concentration)") - eval(f"self.comboBox_sample_table_sand{i}.currentTextChanged." - f"connect(self.plot_PSD_fine_and_sand_sediments)") - eval(f"self.comboBox_sample_table_sand{i}.currentTextChanged." - f"connect(self.update_plot_sample_position_on_transect)") + self.comboBox_sample_table_sand.append(QComboBox()) + + self.comboBox_sample_table_sand[i].addItems(color_list) + self.tableWidget_sand.setCellWidget( + i, 0, self.comboBox_sample_table_sand[i] + ) + + self.comboBox_sample_table_sand[i]\ + .currentTextChanged\ + .connect(self.plot_total_concentration) + self.comboBox_sample_table_sand[i]\ + .currentTextChanged\ + .connect(self.plot_PSD_fine_and_sand_sediments) + self.comboBox_sample_table_sand[i]\ + .currentTextChanged\ + .connect(self.update_plot_sample_position_on_transect) # --- Fill Sample column with checkbox --- for i in range(self.tableWidget_sand.rowCount()): @@ -474,20 +536,37 @@ class SampleDataTab(QWidget): # --- Fill table with data --- for i in range(stg.frac_vol_sand.shape[0]): for j in range(stg.frac_vol_sand.shape[1]): - self.tableWidget_sand.setItem(i, 2, QTableWidgetItem(str(stg.time_sand[i]))) - self.tableWidget_sand.setItem(i, 3, QTableWidgetItem(str(stg.depth_sand[i]))) - - self.tableWidget_sand.setItem(i, 4, QTableWidgetItem(str(stg.Ctot_sand[i]))) - self.tableWidget_sand.setItem(i, 5, QTableWidgetItem(str(stg.D50_sand[i]))) - self.tableWidget_sand.setItem(i, j + 6, QTableWidgetItem(str(stg.frac_vol_sand[i, j]))) + self.tableWidget_sand.setItem( + i, 2, QTableWidgetItem(str(stg.time_sand[i])) + ) + self.tableWidget_sand.setItem( + i, 3, QTableWidgetItem(str(stg.depth_sand[i])) + ) + self.tableWidget_sand.setItem( + i, 4, QTableWidgetItem(str(stg.Ctot_sand[i])) + ) + self.tableWidget_sand.setItem( + i, 5, QTableWidgetItem(str(stg.D50_sand[i])) + ) + self.tableWidget_sand.setItem( + i, j + 6, QTableWidgetItem(str(stg.frac_vol_sand[i, j])) + ) # --- Connect checkbox items of tableWidget to update plots --- - self.tableWidget_sand.itemChanged.connect(self.update_plot_sample_position_on_transect) - self.tableWidget_sand.itemChanged.connect(self.plot_total_concentration) - self.tableWidget_sand.itemChanged.connect(self.plot_PSD_fine_and_sand_sediments) + self.tableWidget_sand\ + .itemChanged\ + .connect(self.update_plot_sample_position_on_transect) + self.tableWidget_sand\ + .itemChanged\ + .connect(self.plot_total_concentration) + self.tableWidget_sand\ + .itemChanged\ + .connect(self.plot_PSD_fine_and_sand_sediments) - self.combobox_x_axis.currentIndexChanged.connect(self.plot_total_concentration) - self.combobox_y_axis.currentIndexChanged.connect(self.plot_total_concentration) + self.combobox_x_axis.currentIndexChanged\ + .connect(self.plot_total_concentration) + self.combobox_y_axis.currentIndexChanged\ + .connect(self.plot_total_concentration) self.plot_sample_position_on_transect() self.plot_total_concentration() @@ -502,7 +581,7 @@ class SampleDataTab(QWidget): if self.tableWidget_fine.item(i, 1).checkState() == 2: if self.tableWidget_fine.item(i, 1).checkState() == Qt.Checked: position.append(i) - eval(f"color_list.append(self.comboBox_sample_table_fine{i}.currentText())") + color_list.append(self.comboBox_sample_table_fine[i].currentText()) sample_checkbox[0, i] = 2 return position, color_list @@ -570,7 +649,9 @@ class SampleDataTab(QWidget): if self.tableWidget_sand.item(i, 1).checkState() == 2: if self.tableWidget_sand.item(i, 1).checkState() == Qt.Checked: position.append(i) - eval(f"color_list.append(self.comboBox_sample_table_sand{i}.currentText())") + color_list.append( + self.comboBox_sample_table_sand[i].currentText() + ) sample_checkbox[0, i] = 2 return position, color_list @@ -646,7 +727,6 @@ class SampleDataTab(QWidget): self.combobox_acoustic_data.showPopup() def fill_comboboxes_and_plot_transect(self): - self.combobox_acoustic_data.clear() for n, m in enumerate(stg.noise_method): if stg.noise_method[n] == 0: @@ -659,19 +739,23 @@ class SampleDataTab(QWidget): self.combobox_frequencies.currentIndexChanged.connect(self.update_plot_sample_position_on_transect) def plot_sample_position_on_transect(self): + self.verticalLayout_groupbox_plot_transect\ + .removeWidget(self.canvas_plot_sample_position_on_transect) - self.verticalLayout_groupbox_plot_transect.removeWidget(self.canvas_plot_sample_position_on_transect) + fig, axis = plt.subplots(nrows=1, ncols=1, layout="constrained") - self.figure_plot_sample_position_on_transect, self.axis_plot_sample_position_on_transect = \ - plt.subplots(nrows=1, ncols=1, layout="constrained") - self.canvas_plot_sample_position_on_transect = FigureCanvas(self.figure_plot_sample_position_on_transect) + self.figure_plot_sample_position_on_transect = fig + self.axis_plot_sample_position_on_transect = axis - self.verticalLayout_groupbox_plot_transect.addWidget(self.canvas_plot_sample_position_on_transect) + self.canvas_plot_sample_position_on_transect = FigureCanvas( + self.figure_plot_sample_position_on_transect + ) + + self.verticalLayout_groupbox_plot_transect\ + .addWidget(self.canvas_plot_sample_position_on_transect) if self.combobox_acoustic_data.count() == 0: - if self.tableWidget_fine.columnCount() > 10: - position_list_fine, color_list_fine = self.extract_position_list_and_color_list_from_table_checkboxes_fine() self.axis_plot_sample_position_on_transect.scatter( @@ -1696,4 +1780,3 @@ class SampleDataTab(QWidget): self.axis_plot_PSD[1].set_ylabel('Cumulative size volume fraction') self.figure_plot_PSD.canvas.draw_idle() -