# ============================================================================== # # acoustic_data_tab.py - AcouSed # # Copyright (C) 2024-2025 INRAE # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # by Brahim MOUDJED # # ============================================================================== # # -*- coding: utf-8 -*- import os import locale import logging import numpy as np import pandas as pd from re import findall from copy import deepcopy from scipy.signal import savgol_filter import matplotlib.pyplot as plt from matplotlib.colors import LogNorm, CSS4_COLORS, BoundaryNorm from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolBar from PyQt5.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, QPushButton, QComboBox, QLineEdit, QLabel, QGridLayout, QTableView, QSpacerItem, QSizePolicy, QFileDialog, QMessageBox, QScrollArea, QSlider, QMenu, QCheckBox, QAbstractItemView ) from PyQt5.QtGui import QPixmap, QIcon from PyQt5.QtCore import ( Qt, QCoreApplication, pyqtSignal, QEvent, QSize, QPropertyAnimation ) from pyqt_file_list_widget.fileListWidget import FileListWidget import settings as stg import Translation.constant_string as cs from Model.TableModel import TableModel from Model.acoustic_data_loader import AcousticDataLoader from Model.acoustic_data_loader_UBSediFlow import AcousticDataLoaderUBSediFlow from Model.calibration_constant_kt import CalibrationConstantKt from tools import trace locale.setlocale(locale.LC_ALL, '') _translate = QCoreApplication.translate logger = logging.getLogger("acoused") class AcousticDataTab(QWidget): COMPTEUR = 1 """ This class generates the Acoustic Data Tab """ fileAdded = pyqtSignal(list) fileRemoved = pyqtSignal(list) newValueChanged = pyqtSignal(float) def __init__(self, tab_widget): super().__init__() self._setup_icons() self._setup_attrs() self.calib_kt = CalibrationConstantKt() ### --- General layout of widgets --- self.verticalLayoutMain = QVBoxLayout(tab_widget) self.horizontalLayoutTop = QHBoxLayout() self.verticalLayoutMain.addLayout(self.horizontalLayoutTop, 5) # 1O units is 100% , 1 units is 10% self.horizontalLayoutBottom = QHBoxLayout() self.verticalLayoutMain.addLayout(self.horizontalLayoutBottom, 5) ### --- Layout of groupbox in the Top horizontal layout box # Download | Table of values | GPS file # Measurement information | | Display options self.groupbox_download = QGroupBox() self.horizontalLayoutTop.addWidget(self.groupbox_download, 3) self.groupbox_table = QGroupBox() self.horizontalLayoutTop.addWidget(self.groupbox_table, 3) self.groupbox_display_option = QGroupBox() self.horizontalLayoutTop.addWidget(self.groupbox_display_option, 4) ### --- Layout of groupbox in the Bottom horizontal layout box # 2D field of raw acoustic backscatter data | 2D field of Signal to Noise ratio self.groupbox_transect_2Dplot_raw_BS_data = QGroupBox() self.horizontalLayoutBottom.addWidget(self.groupbox_transect_2Dplot_raw_BS_data, 6) self.groupbox_plot_the_vertical_profile_for_a_frequency = QGroupBox() self.horizontalLayoutBottom.addWidget(self.groupbox_plot_the_vertical_profile_for_a_frequency, 4) # ===================================================== # TOP HORIZONTAL BOX LAYOUT # ===================================================== self.groupbox_download.setTitle("Acoustic recording") self.verticalLayout_groupbox_download = QVBoxLayout(self.groupbox_download) self.groupbox_acoustic_file = QGroupBox() self.groupbox_acoustic_file.setTitle("Download file") self.verticalLayout_groupbox_download.addWidget(self.groupbox_acoustic_file, 5) self.groupbox_info = QGroupBox() self.scrollbar_measurement_information = QScrollArea() self.verticalLayout_groupbox_download.addWidget(self.scrollbar_measurement_information, 5) # +++++++++++++++++++++++++++ # | Group box Download file | # +++++++++++++++++++++++++++ self.gridLayout_groupbox_acoustic_file = QGridLayout(self.groupbox_acoustic_file) self.combobox_ABS_system_choice = QComboBox() self.combobox_ABS_system_choice.addItems([" ", "AQUAscat", "UBSediFlow"]) self.gridLayout_groupbox_acoustic_file.addWidget(self.combobox_ABS_system_choice, 0, 0, 1, 1) self.spacerItem_FileList = QSpacerItem(5, 10, QSizePolicy.Expanding, QSizePolicy.Minimum) self.gridLayout_groupbox_acoustic_file.addItem(self.spacerItem_FileList, 0, 1, 1, 1) self.addBtn = QPushButton() self.addBtn.setIcon(self.icon_add) self.delBtn = QPushButton() self.delBtn.setIcon(self.icon_delete) self.clearBtn = QPushButton() self.clearBtn.setIcon(self.icon_clear) self.gridLayout_groupbox_acoustic_file.addWidget(self.addBtn, 0, 2, 1, 1) self.gridLayout_groupbox_acoustic_file.addWidget(self.delBtn, 0, 3, 1, 1) self.gridLayout_groupbox_acoustic_file.addWidget(self.clearBtn, 0, 4, 1, 1) self.fileListWidget = FileListWidget() self.fileListWidget.setSelectionMode(QAbstractItemView.SingleSelection) self.gridLayout_groupbox_acoustic_file.addWidget(self.fileListWidget, 1, 0, 1, 5) # ++++++++++++++++++++++++++++++++++++++ # | Group Box Measurements information | # ++++++++++++++++++++++++++++++++++++++ self.scrollbar_measurement_information.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.scrollbar_measurement_information.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.scrollbar_measurement_information.setWidgetResizable(True) self.gridLayout_groupbox_info = QGridLayout(self.scrollbar_measurement_information) self.groupbox_info.setLayout(self.gridLayout_groupbox_info) self.scrollbar_measurement_information.setWidget(self.groupbox_info) self.label_ABS_name = QLabel() self.combobox_ABS_name = QComboBox() self.combobox_ABS_name.addItems(self.calib_kt.data_ABS.keys()) self.label_date_acoustic_file = QLabel() self.label_hour_acoustic_file = QLabel() self.label_distance_from_ABS_to_free_surface = QLabel() self.label_distance_from_ABS_to_free_surface.setText("Distance from ABS to free surface") self.lineEdit_distance_from_ABS_to_free_surface = QLineEdit() self.lineEdit_distance_from_ABS_to_free_surface.setText("0.00") self.lineEdit_distance_from_ABS_to_free_surface.setMaximumWidth(100) self.label_distance_from_ABS_to_free_surface_unit = QLabel() self.label_distance_from_ABS_to_free_surface_unit.setText("m") self.pushbutton_distance_from_ABS_to_free_surface = QPushButton() self.pushbutton_distance_from_ABS_to_free_surface.setIcon(self.icon_refresh) self.label_temperature = QLabel("Temperature : ") self.lineEdit_temperature = QLineEdit() self.lineEdit_temperature.setText("0.00") self.lineEdit_temperature.setMaximumWidth(100) self.label_temperature_unit = QLabel() self.label_temperature_unit.setText("°C") self.label_speed_of_sound = QLabel("Speed of sound : ") self.lineEdit_speed_of_sound = QLineEdit() self.lineEdit_speed_of_sound.setMaximumWidth(100) self.label_speed_of_sound_unit = QLabel() self.label_speed_of_sound_unit.setText("m/s") self.label_freq = QLabel() self.combobox_frequency_information = QComboBox() self.combobox_frequency_information.setMaximumWidth(100) self.label_kt = QLabel() self.lineEdit_kt = QLineEdit() self.lineEdit_kt.setMaximumWidth(100) self.label_kt_unit = QLabel() self.label_kt_unit.setText("

V.m1.5

") self.checkbox_kt = QCheckBox() self.checkbox_kt.setChecked(True) self.checkbox_kt.setToolTip("Checkbox checked : calibration is computed with kt value from the file (see File -> Settings -> ABS constant calibration kt) \n" "Checkbox unchecked : calibration is computed from kt values read from the ABS") self.label_sound_attenuation = QLabel("Sound attenuation : ") self.lineEdit_sound_attenuation = QLineEdit() self.lineEdit_sound_attenuation.setMaximumWidth(100) self.label_sound_attenuation_unit = QLabel() self.label_sound_attenuation_unit.setText("

m-1

") self.label_profiles = QLabel() self.label_profiles_value = QLabel() self.label_profiles_per_sec = QLabel() self.label_profiles_per_sec_value = QLabel() self.label_cells = QLabel() # n_cell in UBSediFlow parameters self.label_cells_value = QLabel() self.label_cell_size = QLabel() # r_em in UBSediFlow parameters self.label_cell_size_value = QLabel() self.label_pulse_length = QLabel() # n_p / PRF with n_p = n_ech, nb of pulses to calculate one instantaneous profile self.label_pulse_length_value = QLabel() self.label_pings_per_sec = QLabel() # PRF in UBSediFlow parameters self.label_pings_per_sec_value = QLabel() self.label_pings_per_profile = QLabel() # n_profile/n_avg in UBSediFlow parameters self.label_pings_per_profile_value = QLabel() self.label_rx = QLabel() # a0 in UBSediFlow parameters self.lineEdit_rx = QLineEdit() self.lineEdit_rx.setMaximumWidth(100) self.checkbox_rx = QCheckBox() self.label_tx = QLabel() # a1 in UBSediFlow parameters self.lineEdit_tx = QLineEdit() self.lineEdit_tx.setMaximumWidth(100) self.checkbox_tx = QCheckBox() # +++++++++++++++++++++++++++++ # | Group Box Table of values | # +++++++++++++++++++++++++++++ self.groupbox_table.setTitle("Table of values") self.verticalLayout_groupbox_table = QVBoxLayout(self.groupbox_table) self.tableView = QTableView() data = pd.DataFrame(np.zeros((10, 10))) self.tableModel = TableModel(data) self.tableView.setModel(self.tableModel) self.verticalLayout_groupbox_table.addWidget(self.tableView) # ++++++++++++++++++++++++++++ # | Group Box Display option | # ++++++++++++++++++++++++++++ self.groupbox_display_option.setTitle("Display option") self.verticalLayout_groupbox_display_option = QVBoxLayout(self.groupbox_display_option) # o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o # --- Group box GPS file --- self.groupbox_gps = QGroupBox() self.groupbox_gps.setTitle("Convert recording time to distance from bank") self.horizontal_gps_input_data = QHBoxLayout(self.groupbox_gps) self.groupbox_gps.setEnabled(False) self.verticalLayout_groupbox_display_option.addWidget(self.groupbox_gps) self.groupbox_gps_value = QGroupBox() self.groupbox_gps_value.setTitle("Value") self.groupbox_gps_value.setCheckable(True) self.groupbox_gps_value.setChecked(True) self.horizontal_gps_input_data.addWidget(self.groupbox_gps_value) self.gridLayout_gps_value = QGridLayout(self.groupbox_gps_value) self.label_distance_value = QLabel() self.label_distance_value.setText("Distance : ") self.gridLayout_gps_value.addWidget(self.label_distance_value, 0, 0, 1, 1) self.lineEdit_gps_value = QLineEdit() self.lineEdit_gps_value.setMaximumWidth(80) self.gridLayout_gps_value.addWidget(self.lineEdit_gps_value, 0, 1, 1, 1) self.label_m_per_record = QLabel("m / record") self.gridLayout_gps_value.addWidget(self.label_m_per_record, 0, 2, 1, 1) self.groupbox_gps_file = QGroupBox() self.groupbox_gps_file.setCheckable(True) self.groupbox_gps_file.setChecked(False) self.groupbox_gps_file.setTitle("GPS file") self.horizontal_gps_input_data.addWidget(self.groupbox_gps_file) self.gridLayout_groupbox_gps_file = QGridLayout(self.groupbox_gps_file) self.pushbutton_gps_file = QPushButton() self.pushbutton_gps_file.setIcon(self.icon_folder) self.gridLayout_groupbox_gps_file.addWidget(self.pushbutton_gps_file, 0, 0, 1, 1) self.lineEdit_gps_file = QLineEdit() self.gridLayout_groupbox_gps_file.addWidget(self.lineEdit_gps_file, 0, 1, 1, 1) # --- Time offset line between ABS system time and GPS time --- self.label_acoustic_gps_time = QLabel() self.label_acoustic_gps_time.setText( "Tacoustic =" + " Tgps") self.gridLayout_groupbox_gps_file.addWidget(self.label_acoustic_gps_time, 0, 2, 1, 1) self.combobox_plus_minus = QComboBox() self.combobox_plus_minus.addItem("+") self.combobox_plus_minus.addItem("-") self.gridLayout_groupbox_gps_file.addWidget(self.combobox_plus_minus, 0, 3, 1, 1) self.lineEdit_time_offset_value = QLineEdit() self.lineEdit_time_offset_value.setMaximumWidth(80) self.gridLayout_groupbox_gps_file.addWidget(self.lineEdit_time_offset_value, 0, 4, 1, 1) self.label_seconds = QLabel() self.label_seconds.setText("sec") self.gridLayout_groupbox_gps_file.addWidget(self.label_seconds, 0, 5, 1, 1) # ---------------------------------------------------------------------------- # o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o # --- Groupbox display option limits --- self.groupbox_display_option_limits = QGroupBox() self.groupbox_display_option_limits.setTitle("Set the boundaries") self.gridLayout_groupbox_display_option_limits = QGridLayout(self.groupbox_display_option_limits) self.verticalLayout_groupbox_display_option.addWidget(self.groupbox_display_option_limits) # -------------------------------- self.label_min = QLabel() self.label_min.setText("min") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_min, 0, 1, 1, 1, Qt.AlignCenter) self.label_upstream = QLabel() self.label_upstream.setText("limit -->") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_upstream, 0, 2, 1, 1, Qt.AlignCenter) self.label_downstream = QLabel() self.label_downstream.setText("<-- limit") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_downstream, 0, 3, 1, 1, Qt.AlignCenter) self.label_max = QLabel() self.label_max.setText("max") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_max, 0, 4, 1, 1, Qt.AlignCenter) self.label_unit = QLabel() self.label_unit.setText("unit") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_unit, 0, 5, 1, 1, Qt.AlignCenter) # -------------------------------- self.label_depth = QLabel("Depth") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_depth, 1, 0, 1, 1, Qt.AlignRight) self.label_depth_min = QLabel() self.label_depth_min.setText("0.00") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_depth_min, 1, 1, 1, 1, Qt.AlignCenter) self.lineEdit_depth_min_limits = QLineEdit() self.lineEdit_depth_min_limits.setText("0.00") self.lineEdit_depth_min_limits.setMaximumWidth(80) self.gridLayout_groupbox_display_option_limits.addWidget(self.lineEdit_depth_min_limits, 1, 2, 1, 1, Qt.AlignCenter) self.lineEdit_depth_max_limits = QLineEdit() self.lineEdit_depth_max_limits.setText("0.00") self.lineEdit_depth_max_limits.setMaximumWidth(80) self.gridLayout_groupbox_display_option_limits.addWidget(self.lineEdit_depth_max_limits, 1, 3, 1, 1, Qt.AlignCenter) self.label_depth_max = QLabel() self.label_depth_max.setText("0.00") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_depth_max, 1, 4, 1, 1, Qt.AlignCenter) self.label_depth_unit_meter = QLabel("meters") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_depth_unit_meter, 1, 5, 1, 1, Qt.AlignCenter) self.pushbutton_apply_depth_limits = QPushButton() self.pushbutton_apply_depth_limits.setIcon(self.icon_apply_limits) self.gridLayout_groupbox_display_option_limits.addWidget(self.pushbutton_apply_depth_limits, 1, 6, 1, 1) # -------------------------------- self.label_recording_time = QLabel("Recording time") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_recording_time, 2, 0, 1, 1, Qt.AlignRight) self.label_time_min = QLabel() self.label_time_min.setText("0.00") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_time_min, 2, 1, 1, 1, Qt.AlignCenter) self.lineEdit_time_min_limits = QLineEdit() self.lineEdit_time_min_limits.setText("0.00") self.lineEdit_time_min_limits.setMaximumWidth(80) self.gridLayout_groupbox_display_option_limits.addWidget(self.lineEdit_time_min_limits, 2, 2, 1, 1, Qt.AlignCenter) self.lineEdit_time_max_limits = QLineEdit() self.lineEdit_time_max_limits.setText("0.00") self.lineEdit_time_max_limits.setMaximumWidth(80) self.gridLayout_groupbox_display_option_limits.addWidget(self.lineEdit_time_max_limits, 2, 3, 1, 1, Qt.AlignCenter) self.label_time_max = QLabel() self.label_time_max.setText("0.00") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_time_max, 2, 4, 1, 1, Qt.AlignCenter) self.label_recording_time_unit_meter = QLabel("seconds") self.gridLayout_groupbox_display_option_limits.addWidget(self.label_recording_time_unit_meter, 2, 5, 1, 1, Qt.AlignCenter) self.pushbutton_apply_recording_time_limits = QPushButton() self.pushbutton_apply_recording_time_limits.setIcon(self.icon_apply_limits) self.gridLayout_groupbox_display_option_limits.addWidget(self.pushbutton_apply_recording_time_limits, 2, 6, 1, 1) # --------------------------------- self.label_distance_from_bank = QLabel("Distance from bank") self.gridLayout_groupbox_display_option_limits.addWidget( self.label_distance_from_bank, 3, 0, 1, 1, Qt.AlignRight ) self.label_distance_from_bank.setEnabled(False) self.label_distance_from_bank_min = QLabel() self.label_distance_from_bank_min.setText("0.00") self.gridLayout_groupbox_display_option_limits.addWidget( self.label_distance_from_bank_min, 3, 1, 1, 1, Qt.AlignCenter ) self.label_distance_from_bank_min.setEnabled(False) self.lineEdit_distance_from_bank_min_limits = QLineEdit() self.lineEdit_distance_from_bank_min_limits.setText("0.00") self.lineEdit_distance_from_bank_min_limits.setMaximumWidth(80) self.gridLayout_groupbox_display_option_limits.addWidget( self.lineEdit_distance_from_bank_min_limits, 3, 2, 1, 1, Qt.AlignCenter ) self.lineEdit_distance_from_bank_min_limits.setEnabled(False) self.lineEdit_distance_from_bank_max_limits = QLineEdit() self.lineEdit_distance_from_bank_max_limits.setText("0.00") self.lineEdit_distance_from_bank_max_limits.setMaximumWidth(80) self.gridLayout_groupbox_display_option_limits.addWidget( self.lineEdit_distance_from_bank_max_limits, 3, 3, 1, 1, Qt.AlignCenter ) self.lineEdit_distance_from_bank_max_limits.setEnabled(False) self.label_distance_from_bank_max = QLabel() self.label_distance_from_bank_max.setText("0.00") self.gridLayout_groupbox_display_option_limits.addWidget( self.label_distance_from_bank_max, 3, 4, 1, 1, Qt.AlignCenter ) self.label_distance_from_bank_max.setEnabled(False) self.label_distance_from_bank_unit_meter = QLabel("meters") self.gridLayout_groupbox_display_option_limits.addWidget( self.label_distance_from_bank_unit_meter, 3, 5, 1, 1, Qt.AlignCenter ) self.label_distance_from_bank_unit_meter.setEnabled(False) self.pushbutton_apply_distance_from_bank_limits = QPushButton() self.pushbutton_apply_distance_from_bank_limits.setIcon(self.icon_apply_limits) self.gridLayout_groupbox_display_option_limits.addWidget( self.pushbutton_apply_distance_from_bank_limits, 3, 6, 1, 1 ) self.pushbutton_apply_distance_from_bank_limits.setEnabled(False) # --------------------------------------- self.groupbox_display_option_bathymetry = QGroupBox() self.groupbox_display_option_bathymetry.setTitle("Detect bottom of the river") self.gridLayout_groupbox_display_option_bathymetry = QGridLayout(self.groupbox_display_option_bathymetry) self.verticalLayout_groupbox_display_option.addWidget(self.groupbox_display_option_bathymetry) self.combobox_frequency_bathymetry = QComboBox() self.combobox_frequency_bathymetry.setMaximumWidth(150) self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.combobox_frequency_bathymetry, 0, 0, 1, 1, Qt.AlignCenter) self.label_from_bathy = QLabel() self.label_from_bathy.setText("From") self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_from_bathy, 0, 1, 1, 1, Qt.AlignCenter) self.lineEdit_depth_min_bathy = QLineEdit() self.lineEdit_depth_min_bathy.setText("0.00") self.lineEdit_depth_min_bathy.setMaximumWidth(80) self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.lineEdit_depth_min_bathy, 0, 2, 1, 1, Qt.AlignCenter) self.label_depth_min_unit = QLabel() self.label_depth_min_unit.setText("m") self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_depth_min_unit, 0, 3, 1, 1, Qt.AlignLeft) self.label_to_bathy = QLabel() self.label_to_bathy.setText("to") self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_to_bathy, 0, 4, 1, 1, Qt.AlignCenter) self.lineEdit_depth_max_bathy = QLineEdit() self.lineEdit_depth_max_bathy.setText("0.00") self.lineEdit_depth_max_bathy.setMaximumWidth(80) self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.lineEdit_depth_max_bathy, 0, 5, 1, 1, Qt.AlignCenter) self.label_depth_max_unit = QLabel() self.label_depth_max_unit.setText("m") self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_depth_max_unit, 0, 6, 1, 1, Qt.AlignLeft) self.label_next_cell = QLabel() self.label_next_cell.setText("+/-") self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_next_cell, 0, 7, 1, 1, Qt.AlignCenter) self.lineEdit_next_cell_bathy = QLineEdit() self.lineEdit_next_cell_bathy.setText("0.00") self.lineEdit_next_cell_bathy.setMaximumWidth(80) self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.lineEdit_next_cell_bathy, 0, 8, 1, 1, Qt.AlignCenter) self.label_next_cell_unit = QLabel() self.label_next_cell_unit.setText("m") self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.label_next_cell_unit, 0, 9, 1, 1, Qt.AlignLeft) self.pushbutton_apply_bathymetry = QPushButton() self.pushbutton_apply_bathymetry.setIcon(self.icon_apply_limits) self.gridLayout_groupbox_display_option_bathymetry.addWidget(self.pushbutton_apply_bathymetry, 0, 10, 1, 1) # ===================================================== # BOTTOM HORIZONTAL BOX LAYOUT # ===================================================== # +++++++++++++++++++++++++++++++++++++************+++ # | Group Box Backscatter Acoustic Raw Data 2D field | # ++++++++++++++++++++++++++************++++++++++++++ self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data = QVBoxLayout(self.groupbox_transect_2Dplot_raw_BS_data) self.canvas_BS = FigureCanvas() self.toolbar_BS = NavigationToolBar(self.canvas_BS, self) self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.addWidget(self.toolbar_BS) self.scroll_BS = QScrollArea() self.scroll_BS.setWidget(self.canvas_BS) self.scroll_BS.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.scroll_BS.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.scroll_BS.setAlignment(Qt.AlignCenter) self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.addWidget(self.scroll_BS) # +++++++++++++++++++++++++++++++++++++++++++ # | Group Box Plot profile from BS 2D field | # +++++++++++++++++++++++++++++++++++++++++++ self.verticalLayout_groupbox_plot_the_vertical_profile_for_a_frequency = QVBoxLayout(self.groupbox_plot_the_vertical_profile_for_a_frequency) self.groupbox_plot_the_vertical_profile_for_a_frequency.setTitle("Plot the vertical profile for one frequency") self.horizontalLayout_spacerItem_combobox_frequency_profile = QHBoxLayout() self.verticalLayout_groupbox_plot_the_vertical_profile_for_a_frequency.addLayout( self.horizontalLayout_spacerItem_combobox_frequency_profile) self.spacerItem_frequency_profile = QSpacerItem(50, 10, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_spacerItem_combobox_frequency_profile.addSpacerItem(self.spacerItem_frequency_profile) self.combobox_frequency_profile = QComboBox() self.horizontalLayout_spacerItem_combobox_frequency_profile.addWidget(self.combobox_frequency_profile) self.groupbox_plot_profile = QGroupBox() self.verticalLayout_groupbox_plot_profile = QVBoxLayout(self.groupbox_plot_profile) self.verticalLayout_groupbox_plot_the_vertical_profile_for_a_frequency.addWidget(self.groupbox_plot_profile) self.canvas_plot_profile = FigureCanvas() self.toolbar_profile = NavigationToolBar(self.canvas_plot_profile, self) self.verticalLayout_groupbox_plot_profile.addWidget(self.toolbar_profile) self.verticalLayout_groupbox_plot_profile.addWidget(self.canvas_plot_profile) # --- Slider for moving the profile --- self.horizontalLayout_slider = QHBoxLayout() self.verticalLayout_groupbox_plot_the_vertical_profile_for_a_frequency.addLayout(self.horizontalLayout_slider) self.pushbutton_slider_left_to_begin = QPushButton() self.pushbutton_slider_left_to_begin.setIcon(self.icon_triangle_left_to_begin) self.horizontalLayout_slider.addWidget(self.pushbutton_slider_left_to_begin) self.pushbutton_slider_left = QPushButton() self.pushbutton_slider_left.setIcon(self.icon_triangle_left) self.horizontalLayout_slider.addWidget(self.pushbutton_slider_left) self.lineEdit_slider = QLineEdit() self.lineEdit_slider.setText("1") self.lineEdit_slider.setFixedWidth(50) self.horizontalLayout_slider.addWidget(self.lineEdit_slider) self.pushbutton_slider_right = QPushButton() self.pushbutton_slider_right.setIcon(self.icon_triangle_right) self.horizontalLayout_slider.addWidget(self.pushbutton_slider_right) self.pushbutton_slider_right_to_end = QPushButton() self.pushbutton_slider_right_to_end.setIcon(self.icon_triangle_right_to_end) self.horizontalLayout_slider.addWidget(self.pushbutton_slider_right_to_end) self.slider = QSlider() self.horizontalLayout_slider.addWidget(self.slider, 9) self.slider.setOrientation(Qt.Horizontal) self.slider.setCursor(Qt.OpenHandCursor) self.slider.setMinimum(1) self.slider.setMaximum(10) self.slider.setTickInterval(1) self.slider.setValue(1) self.retranslate_acoustic_data_tab() self.max_selected_file = 1 # -------------------------------------------------------------------------------------------------------------- # --- Connect signal of widget --- self.combobox_ABS_system_choice.currentTextChanged.connect(self.ABS_system_choice) self.addBtn.clicked.connect(self.open_dialog_box) self.delBtn.clicked.connect(self.remove_file_from_ListWidget) self.clearBtn.clicked.connect(self.clear_files_from_ListWidget) self.fileListWidget.itemSelectionChanged.connect(self.fileListWidget_event) # self.fileListWidget.itemSelectionChanged.connect(self.print_selected_file) # self.fileListWidget.itemSelectionChanged.connect(self.fill_measurements_information_groupbox) # self.fileListWidget.itemSelectionChanged.connect(self.fill_table) # self.fileListWidget.itemSelectionChanged.connect(self.compute_tmin_tmax) # self.fileListWidget.itemSelectionChanged.connect(self.compute_rmin_rmax) # self.fileListWidget.itemSelectionChanged.connect(self.update_frequency_combobox) # # self.fileListWidget.itemSelectionChanged.connect(self.plot_backscattered_acoustic_signal_recording) # # self.fileListWidget.itemSelectionChanged.connect(self.plot_profile) # self.fileListWidget.itemSelectionChanged.connect(self.update_plot_backscattered_acoustic_signal_recording) # self.fileListWidget.itemSelectionChanged.connect(self.update_plot_profile) # self.fileListWidget.itemSelectionChanged.connect(self.set_range_for_spinboxes_bathymetry) self.combobox_ABS_name.currentIndexChanged.connect(self.fill_measurements_information_groupbox) self.checkbox_kt.stateChanged.connect(self.activate_unactivate_spinbox_kt) self.lineEdit_distance_from_ABS_to_free_surface.returnPressed.connect(self.distance_from_ABS_to_free_surface) self.pushbutton_distance_from_ABS_to_free_surface.clicked.connect(self.refresh_distance_from_ABS_to_free_surface) self.lineEdit_temperature.returnPressed.connect(self.temperature_value) self.lineEdit_speed_of_sound.returnPressed.connect(self.water_velocity) self.lineEdit_sound_attenuation.returnPressed.connect(self.water_attenuation) self.groupbox_gps_value.toggled.connect(self.groupbox_gps_value_toggle) self.groupbox_gps_value.toggled.connect(self.groupbox_gps_value_size_change) self.groupbox_gps_file.toggled.connect(self.groupbox_gps_file_toggle) self.groupbox_gps_file.toggled.connect(self.groupbox_gps_file_size_change) self.pushbutton_apply_depth_limits.clicked.connect(self.compute_BS_cross_section) self.pushbutton_apply_depth_limits.clicked.connect(self.update_plot_backscattered_acoustic_signal_recording) self.pushbutton_apply_depth_limits.clicked.connect(self.update_plot_profile) self.pushbutton_apply_depth_limits.clicked.connect(self.set_range_for_spinboxes_bathymetry) self.pushbutton_apply_recording_time_limits.clicked.connect(self.compute_BS_cross_section) self.pushbutton_apply_recording_time_limits.clicked.connect(self.detect_bottom) self.pushbutton_apply_recording_time_limits.clicked.connect(self.update_plot_backscattered_acoustic_signal_recording) self.pushbutton_apply_recording_time_limits.clicked.connect(self.update_plot_profile) self.pushbutton_apply_bathymetry.clicked.connect(self.detect_bottom) self.pushbutton_slider_left_to_begin.clicked.connect(self.slide_profile_number_to_begin) self.pushbutton_slider_left.clicked.connect(self.slide_profile_number_to_left) self.pushbutton_slider_right.clicked.connect(self.slide_profile_number_to_right) self.pushbutton_slider_right_to_end.clicked.connect(self.slide_profile_number_to_end) self.lineEdit_slider.returnPressed.connect(self.profile_number_on_lineEdit) self.slider.valueChanged.connect(self.update_lineEdit_by_moving_slider) self.slider.valueChanged.connect(self.update_plot_profile) self.slider.valueChanged.connect(self.update_plot_backscattered_acoustic_signal_recording) def _setup_icons(self): def path_icon(icon): return os.path.join( "icons", icon ) self.icon_folder = QIcon(path_icon("folder.png")) self.icon_apply_limits = QIcon(path_icon("circle_green_arrow_right.png")) self.icon_triangle_left_to_begin = QIcon(path_icon("triangle_left_to_begin.png")) self.icon_triangle_left = QIcon(path_icon("triangle_left.png")) self.icon_triangle_right = QIcon(path_icon("triangle_right.png")) self.icon_triangle_right_to_end = QIcon(path_icon("triangle_right_to_end.png")) self.icon_add = QIcon(path_icon("add.png")) self.icon_delete = QIcon(path_icon("delete.png")) self.icon_clear = QIcon(path_icon("clear.png")) self.icon_between = QPixmap(path_icon("between.png")) self.icon_refresh = QIcon(path_icon("update.png")) def _setup_attrs(self): self.fig_profile = None self.fig_BS = None # -------------------- Functions for Acoustic dataTab -------------------- def full_update(self): logger.debug(f"{__name__}: Update") self.blockSignals(True) self.fileListWidget.blockSignals(True) self.combobox_ABS_system_choice.blockSignals(True) self.combobox_ABS_system_choice.setCurrentText(stg.ABS_name[0]) self.ABS_system_choice() self.fileListWidget.addFilenames(stg.filename_BS_raw_data) self.fill_measurements_information_groupbox() self.fill_table() self.plot_backscattered_acoustic_signal_recording() self.plot_profile() self.update_frequency_combobox() self.update_bottom_detection_settings() self.water_attenuation() self.compute_tmin_tmax() self.compute_rmin_rmax() self.combobox_ABS_system_choice.blockSignals(False) self.fileListWidget.blockSignals(False) self.blockSignals(False) def retranslate_acoustic_data_tab(self): self.groupbox_info.setTitle(_translate("CONSTANT_STRING", cs.MEASUREMENTS_INFORMATION)) self.label_date_acoustic_file.setText(_translate("CONSTANT_STRING", cs.DATE) + ":") self.label_hour_acoustic_file.setText(_translate("CONSTANT_STRING", cs.HOUR) + ":") self.label_profiles.setText(_translate("CONSTANT_STRING", cs.NB_PROFILES) + ":") self.label_profiles.setToolTip(_translate("CONSTANT_STRING", cs.NB_PROFILES_TOOLTIP)) self.label_profiles_per_sec.setText(_translate("CONSTANT_STRING", cs.NB_PROFILES_PER_SEC) + ":") self.label_profiles_per_sec.setToolTip(_translate("CONSTANT_STRING", cs.NB_PROFILES_PER_SEC_TOOLTIP)) self.label_cells.setText(_translate("CONSTANT_STRING", cs.NB_CELLS) + ":") self.label_cells.setToolTip(_translate("CONSTANT_STRING", cs.NB_CELLS_TOOLTIP)) self.label_cell_size.setText(_translate("CONSTANT_STRING", cs.CELL_SIZE) + ":") self.label_cell_size.setToolTip(_translate("CONSTANT_STRING", cs.CELL_SIZE_TOOLTIP)) self.label_pulse_length.setText(_translate("CONSTANT_STRING", cs.PULSE_LENGHT) + ":") self.label_pulse_length.setToolTip(_translate("CONSTANT_STRING", cs.PULSE_LENGHT_TOOLTIP)) self.label_pings_per_sec.setText(_translate("CONSTANT_STRING", cs.NB_PINGS_PER_SEC)) self.label_pings_per_sec.setToolTip(_translate("CONSTANT_STRING", cs.NB_PINGS_PER_SEC_TOOLTIP)) self.label_pings_per_profile.setText(_translate("CONSTANT_STRING", cs.NB_PINGS_PER_PROFILE) + ":") self.label_pings_per_profile.setToolTip(_translate("CONSTANT_STRING", cs.NB_PINGS_PER_PROFILE_TOOLTIP)) self.label_freq.setText(_translate("CONSTANT_STRING", cs.FREQUENCY) + ":") self.label_freq.setToolTip(_translate("CONSTANT_STRING", cs.FREQUENCY_TOOLTIP)) self.label_kt.setText(_translate("CONSTANT_STRING", cs.KT) + ":") self.label_kt.setToolTip(_translate("CONSTANT_STRING", cs.KT_TOOLTIP)) self.label_rx.setText(_translate("CONSTANT_STRING", cs.GAIN_RX) + ":") self.label_rx.setToolTip(_translate("CONSTANT_STRING", cs.GAIN_RX_TOOLTIP)) self.label_tx.setText(_translate("CONSTANT_STRING", cs.GAIN_TX) + ":") self.label_tx.setToolTip(_translate("CONSTANT_STRING", cs.GAIN_TX_TOOLTIP)) self.groupbox_transect_2Dplot_raw_BS_data.setTitle(_translate("CONSTANT_STRING", cs.RAW_ACOUSTIC_DATA_2D_FIELD)) def fileListWidget_event(self): self.fileListWidget.blockSignals(True) self.print_selected_file() self.fill_measurements_information_groupbox() self.fill_table() self.compute_tmin_tmax() self.compute_rmin_rmax() # self.compute_time_cross_section() self.update_frequency_combobox() # self.fileListWidget.itemSelectionChanged.connect(self.plot_backscattered_acoustic_signal_recording) # self.fileListWidget.itemSelectionChanged.connect(self.plot_profile) self.update_plot_backscattered_acoustic_signal_recording() self.update_plot_profile() self.update_bottom_detection_settings() self.fileListWidget.blockSignals(False) def print_selected_file(self): logger.debug( f"Selected file in list widget : {self.fileListWidget.selectedItems()}" ) logger.debug( "self.fileListWidget.selectedItems()[1:] : " + f"{self.fileListWidget.selectedItems()[1:]}" ) if len(self.fileListWidget.selectedItems()) > self.max_selected_file: self.fileListWidget.setSelectionMode(1) def onClicked_radiobutton_gps(self): radiobutton = self.sender() if radiobutton.isChecked(): if self.radiobutton_value.isChecked(): self.groupbox_gps_value.setVisible(True) self.groupbox_gps_file.setVisible(False) elif self.radiobutton_file.isChecked(): self.groupbox_gps_value.setVisible(False) self.groupbox_gps_file.setVisible(True) def ABS_system_choice(self): if self.combobox_ABS_system_choice.currentText() == " ": self.groupbox_measurement_information_no_ABS() elif self.combobox_ABS_system_choice.currentText() == "AQUAscat": self.groupbox_measurement_information_Aquascat() elif self.combobox_ABS_system_choice.currentText() == "UBSediFlow": self.groupbox_measurement_information_UBSediFlow() def groupbox_measurement_information_no_ABS(self): self.label_ABS_name.hide() self.combobox_ABS_name.hide() self.label_date_acoustic_file.hide() self.label_hour_acoustic_file.hide() self.label_distance_from_ABS_to_free_surface.hide() self.lineEdit_distance_from_ABS_to_free_surface.hide() self.label_distance_from_ABS_to_free_surface_unit.hide() self.pushbutton_distance_from_ABS_to_free_surface.hide() self.label_temperature.hide() self.lineEdit_temperature.hide() self.label_temperature_unit.hide() self.label_speed_of_sound.hide() self.lineEdit_speed_of_sound.hide() self.label_speed_of_sound_unit.hide() self.label_sound_attenuation.hide() self.lineEdit_sound_attenuation.hide() self.label_sound_attenuation_unit.hide() self.label_freq.hide() self.combobox_frequency_information.hide() self.label_profiles.hide() self.label_profiles_per_sec.hide() self.label_cells.hide() self.label_cell_size.hide() self.label_pulse_length.hide() self.label_pings_per_sec.hide() self.label_pings_per_profile.hide() self.label_kt.hide() self.lineEdit_kt.hide() self.label_kt_unit.hide() self.checkbox_kt.hide() self.label_rx.hide() self.lineEdit_rx.hide() self.checkbox_rx.hide() self.label_tx.hide() self.lineEdit_tx.hide() self.checkbox_tx.hide() def groupbox_measurement_information_Aquascat(self): # --- Hide UBSediFlow information and remove widget from grid layout --- self.label_ABS_name.hide() self.combobox_ABS_name.hide() self.label_date_acoustic_file.hide() self.label_hour_acoustic_file.hide() self.label_distance_from_ABS_to_free_surface.hide() self.lineEdit_distance_from_ABS_to_free_surface.hide() self.label_distance_from_ABS_to_free_surface_unit.hide() self.pushbutton_distance_from_ABS_to_free_surface.hide() self.label_temperature.hide() self.lineEdit_temperature.hide() self.label_temperature_unit.hide() self.label_speed_of_sound.hide() self.lineEdit_speed_of_sound.hide() self.label_speed_of_sound_unit.hide() self.label_sound_attenuation.hide() self.lineEdit_sound_attenuation.hide() self.label_sound_attenuation_unit.hide() self.label_freq.hide() self.combobox_frequency_information.hide() self.label_profiles.hide() self.label_profiles_per_sec.hide() self.label_cells.hide() self.label_cell_size.hide() self.label_pulse_length.hide() self.label_pings_per_sec.hide() self.label_pings_per_profile.hide() self.label_kt.hide() self.lineEdit_kt.hide() self.label_kt_unit.hide() self.checkbox_kt.hide() self.label_rx.hide() self.lineEdit_rx.hide() self.checkbox_rx.hide() self.label_tx.hide() self.lineEdit_tx.hide() self.checkbox_tx.hide() for i in reversed(range(self.gridLayout_groupbox_info.count())): widgetToRemove = self.gridLayout_groupbox_info.itemAt(i).widget() # remove it from the layout list self.gridLayout_groupbox_info.removeWidget(widgetToRemove) # remove it from the gui widgetToRemove.setParent(None) # --- Show Aquascat information --- self.label_ABS_name.show() self.label_ABS_name.setText("Acoustic Backscatter System: AQUAscat") self.gridLayout_groupbox_info.addWidget(self.label_ABS_name, 0, 0, 1, 2, Qt.AlignCenter) self.combobox_ABS_name.show() self.gridLayout_groupbox_info.addWidget(self.combobox_ABS_name, 0, 2, 1, 2, Qt.AlignCenter) self.label_date_acoustic_file.show() self.gridLayout_groupbox_info.addWidget(self.label_date_acoustic_file, 1, 0, 1, 1, Qt.AlignLeft) self.label_hour_acoustic_file.show() self.gridLayout_groupbox_info.addWidget(self.label_hour_acoustic_file, 1, 1, 1, 1, Qt.AlignLeft) self.label_distance_from_ABS_to_free_surface.show() self.gridLayout_groupbox_info.addWidget(self.label_distance_from_ABS_to_free_surface, 2, 0, 1, 1, Qt.AlignLeft) self.lineEdit_distance_from_ABS_to_free_surface.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_distance_from_ABS_to_free_surface, 2, 1, 1, 1, Qt.AlignLeft) self.label_distance_from_ABS_to_free_surface_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_distance_from_ABS_to_free_surface_unit, 2, 2, 1, 1, Qt.AlignLeft) self.pushbutton_distance_from_ABS_to_free_surface.show() self.gridLayout_groupbox_info.addWidget(self.pushbutton_distance_from_ABS_to_free_surface, 2, 3, 1, 1, Qt.AlignLeft) self.label_temperature.show() self.gridLayout_groupbox_info.addWidget(self.label_temperature, 3, 0, 1, 1, Qt.AlignLeft) self.lineEdit_temperature.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_temperature, 3, 1, 1, 1, Qt.AlignLeft) self.label_temperature_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_temperature_unit, 3, 2, 1, 1, Qt.AlignLeft) self.setup_temperature_value() self.label_speed_of_sound.show() self.gridLayout_groupbox_info.addWidget(self.label_speed_of_sound, 4, 0, 1, 1, Qt.AlignLeft) self.lineEdit_speed_of_sound.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_speed_of_sound, 4, 1, 1, 1, Qt.AlignLeft) self.label_speed_of_sound_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_speed_of_sound_unit, 4, 2, 1, 1, Qt.AlignLeft) self.label_freq.show() self.gridLayout_groupbox_info.addWidget(self.label_freq, 5, 0, 1, 1, Qt.AlignLeft) self.combobox_frequency_information.show() self.gridLayout_groupbox_info.addWidget(self.combobox_frequency_information, 5, 1, 1, 1, Qt.AlignLeft) self.label_kt.show() self.gridLayout_groupbox_info.addWidget(self.label_kt, 6, 0, 1, 1, Qt.AlignLeft) self.lineEdit_kt.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_kt, 6, 1, 1, 1, Qt.AlignLeft) self.label_kt_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_kt_unit, 6, 2, 1, 1, Qt.AlignLeft) self.checkbox_kt.show() self.gridLayout_groupbox_info.addWidget(self.checkbox_kt, 6, 3, 1, 1, Qt.AlignLeft) self.label_sound_attenuation.show() self.gridLayout_groupbox_info.addWidget(self.label_sound_attenuation, 7, 0, 1, 1, Qt.AlignLeft) self.lineEdit_sound_attenuation.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_sound_attenuation, 7, 1, 1, 1, Qt.AlignLeft) self.label_sound_attenuation_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_sound_attenuation_unit, 7, 2, 1, 1, Qt.AlignLeft) self.label_profiles.show() self.gridLayout_groupbox_info.addWidget(self.label_profiles, 8, 0, 1, 1, Qt.AlignLeft) self.label_profiles_per_sec.show() self.gridLayout_groupbox_info.addWidget(self.label_profiles_per_sec, 9, 0, 1, 1, Qt.AlignLeft) self.label_cells.show() self.gridLayout_groupbox_info.addWidget(self.label_cells, 10, 0, 1, 1, Qt.AlignLeft) self.label_cell_size.show() self.gridLayout_groupbox_info.addWidget(self.label_cell_size, 11, 0, 1, 1, Qt.AlignLeft) self.label_pulse_length.show() self.gridLayout_groupbox_info.addWidget(self.label_pulse_length, 12, 0, 1, 1, Qt.AlignLeft) self.label_pings_per_sec.show() self.gridLayout_groupbox_info.addWidget(self.label_pings_per_sec, 13, 0, 1, 1, Qt.AlignLeft) self.label_pings_per_profile.show() self.gridLayout_groupbox_info.addWidget(self.label_pings_per_profile, 14, 0, 1, 1, Qt.AlignLeft) self.label_rx.show() self.gridLayout_groupbox_info.addWidget(self.label_rx, 15, 0, 1, 1, Qt.AlignLeft) self.lineEdit_rx.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_rx, 15, 1, 1, 1, Qt.AlignLeft) self.checkbox_rx.show() self.gridLayout_groupbox_info.addWidget(self.checkbox_rx, 15, 3, 1, 1, Qt.AlignLeft) self.label_tx.show() self.gridLayout_groupbox_info.addWidget(self.label_tx, 16, 0, 1, 1, Qt.AlignLeft) self.lineEdit_tx.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_tx, 16, 1, 1, 1, Qt.AlignLeft) self.checkbox_tx.show() self.gridLayout_groupbox_info.addWidget(self.checkbox_tx, 16, 3, 1, 1, Qt.AlignLeft) def groupbox_measurement_information_UBSediFlow(self): # --- Hide Aquascat information --- self.label_ABS_name.hide() self.combobox_ABS_name.hide() self.label_date_acoustic_file.hide() self.label_hour_acoustic_file.hide() self.label_distance_from_ABS_to_free_surface.hide() self.lineEdit_distance_from_ABS_to_free_surface.hide() self.label_distance_from_ABS_to_free_surface_unit.hide() self.pushbutton_distance_from_ABS_to_free_surface.hide() self.label_temperature.hide() self.lineEdit_temperature.hide() self.label_temperature_unit.hide() self.label_speed_of_sound.hide() self.lineEdit_speed_of_sound.hide() self.label_speed_of_sound_unit.hide() self.label_sound_attenuation.hide() self.lineEdit_sound_attenuation.hide() self.label_sound_attenuation_unit.hide() self.label_freq.hide() self.combobox_frequency_information.hide() self.label_profiles.hide() self.label_profiles_per_sec.hide() self.label_cells.hide() self.label_cell_size.hide() self.label_pulse_length.hide() self.label_pings_per_sec.hide() self.label_pings_per_profile.hide() self.label_kt.hide() self.lineEdit_kt.hide() self.label_kt_unit.hide() self.checkbox_kt.hide() self.label_rx.hide() self.lineEdit_rx.hide() self.checkbox_rx.hide() self.label_tx.hide() self.lineEdit_tx.hide() self.checkbox_tx.hide() for i in reversed(range(self.gridLayout_groupbox_info.count())): widgetToRemove = self.gridLayout_groupbox_info.itemAt(i).widget() # remove it from the layout list self.gridLayout_groupbox_info.removeWidget(widgetToRemove) # remove it from the gui widgetToRemove.setParent(None) # --- Show UBSediFlow information --- self.label_ABS_name.show() self.label_ABS_name.setText("Acoustic Backscatter System: UBSediFlow") self.gridLayout_groupbox_info.addWidget(self.label_ABS_name, 0, 0, 1, 2, Qt.AlignCenter) self.combobox_ABS_name.show() self.gridLayout_groupbox_info.addWidget(self.combobox_ABS_name, 0, 2, 1, 2, Qt.AlignCenter) self.label_date_acoustic_file.show() self.gridLayout_groupbox_info.addWidget(self.label_date_acoustic_file, 1, 0, 1, 1, Qt.AlignLeft) self.label_hour_acoustic_file.show() self.gridLayout_groupbox_info.addWidget(self.label_hour_acoustic_file, 1, 1, 1, 1, Qt.AlignLeft) self.label_distance_from_ABS_to_free_surface.show() self.gridLayout_groupbox_info.addWidget(self.label_distance_from_ABS_to_free_surface, 2, 0, 1, 1, Qt.AlignLeft) self.lineEdit_distance_from_ABS_to_free_surface.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_distance_from_ABS_to_free_surface, 2, 1, 1, 1, Qt.AlignLeft) self.label_distance_from_ABS_to_free_surface_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_distance_from_ABS_to_free_surface_unit, 2, 2, 1, 1, Qt.AlignLeft) self.pushbutton_distance_from_ABS_to_free_surface.show() self.gridLayout_groupbox_info.addWidget(self.pushbutton_distance_from_ABS_to_free_surface, 2, 3, 1, 1, Qt.AlignLeft) self.label_temperature.show() self.gridLayout_groupbox_info.addWidget(self.label_temperature, 3, 0, 1, 1, Qt.AlignLeft) self.lineEdit_temperature.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_temperature, 3, 1, 1, 1, Qt.AlignLeft) self.label_temperature_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_temperature_unit, 3, 2, 1, 1, Qt.AlignLeft) self.label_speed_of_sound.show() self.gridLayout_groupbox_info.addWidget(self.label_speed_of_sound, 4, 0, 1, 1, Qt.AlignLeft) self.lineEdit_speed_of_sound.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_speed_of_sound, 4, 1, 1, 1, Qt.AlignLeft) self.label_speed_of_sound_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_speed_of_sound_unit, 4, 2, 1, 1, Qt.AlignLeft) self.label_freq.show() self.gridLayout_groupbox_info.addWidget(self.label_freq, 5, 0, 1, 1, Qt.AlignLeft) self.combobox_frequency_information.show() self.gridLayout_groupbox_info.addWidget(self.combobox_frequency_information, 5, 1, 1, 1, Qt.AlignLeft) self.label_kt.show() self.gridLayout_groupbox_info.addWidget(self.label_kt, 6, 0, 1, 1, Qt.AlignLeft) self.lineEdit_kt.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_kt, 6, 1, 1, 1, Qt.AlignLeft) self.label_kt_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_kt_unit, 6, 2, 1, 1, Qt.AlignLeft) self.checkbox_kt.show() self.gridLayout_groupbox_info.addWidget(self.checkbox_kt, 6, 3, 1, 1, Qt.AlignLeft) self.label_sound_attenuation.show() self.gridLayout_groupbox_info.addWidget(self.label_sound_attenuation, 7, 0, 1, 1, Qt.AlignLeft) self.lineEdit_sound_attenuation.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_sound_attenuation, 7, 1, 1, 1, Qt.AlignLeft) self.label_sound_attenuation_unit.show() self.gridLayout_groupbox_info.addWidget(self.label_sound_attenuation_unit, 7, 2, 1, 1, Qt.AlignLeft) self.label_profiles.show() self.gridLayout_groupbox_info.addWidget(self.label_profiles, 8, 0, 1, 1, Qt.AlignLeft) self.label_profiles_per_sec.show() self.gridLayout_groupbox_info.addWidget(self.label_profiles_per_sec, 9, 0, 1, 1, Qt.AlignLeft) self.label_cells.show() self.gridLayout_groupbox_info.addWidget(self.label_cells, 10, 0, 1, 1, Qt.AlignLeft) self.label_cell_size.show() self.gridLayout_groupbox_info.addWidget(self.label_cell_size, 11, 0, 1, 1, Qt.AlignLeft) self.label_pulse_length.show() self.gridLayout_groupbox_info.addWidget(self.label_pulse_length, 12, 0, 1, 1, Qt.AlignLeft) self.label_pings_per_sec.show() self.gridLayout_groupbox_info.addWidget(self.label_pings_per_sec, 13, 0, 1, 1, Qt.AlignLeft) self.label_pings_per_profile.show() self.gridLayout_groupbox_info.addWidget(self.label_pings_per_profile, 14, 0, 1, 1, Qt.AlignLeft) self.label_rx.show() self.gridLayout_groupbox_info.addWidget(self.label_rx, 15, 0, 1, 1, Qt.AlignLeft) self.lineEdit_rx.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_rx, 15, 1, 1, 1, Qt.AlignLeft) self.checkbox_rx.show() self.gridLayout_groupbox_info.addWidget(self.checkbox_rx, 15, 2, 1, 1, Qt.AlignLeft) self.label_tx.show() self.gridLayout_groupbox_info.addWidget(self.label_tx, 16, 0, 1, 1, Qt.AlignLeft) self.lineEdit_tx.show() self.gridLayout_groupbox_info.addWidget(self.lineEdit_tx, 16, 1, 1, 1, Qt.AlignLeft) self.checkbox_tx.show() self.gridLayout_groupbox_info.addWidget(self.checkbox_tx, 16, 2, 1, 1, Qt.AlignLeft) def distance_from_ABS_to_free_surface(self): if self.fileListWidget.count() == 0: msgBox = QMessageBox() msgBox.setWindowTitle("Distance ABS - Free surface Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText("Upload data before setting distance ABS - Free surface") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() self.lineEdit_distance_from_ABS_to_free_surface.setText("0.00") return def refresh_distance_from_ABS_to_free_surface(self): self.pushbutton_distance_from_ABS_to_free_surface.blockSignals(True) data_id = self.fileListWidget.currentRow() previous = stg.distance_from_ABS_to_free_surface[data_id] new = ( float( self.lineEdit_distance_from_ABS_to_free_surface\ .text().replace(",", ".") ) ) self.lineEdit_distance_from_ABS_to_free_surface.setText(f"{new}") logger.debug(f"prev: {previous}, new: {new}") stg.depth[data_id] = stg.depth[data_id] - previous stg.depth_reshape[data_id] = stg.depth_reshape[data_id] - previous stg.depth[data_id] = stg.depth[data_id] + new stg.depth_reshape[data_id] = stg.depth_reshape[data_id] + new stg.depth_cross_section[data_id] = stg.depth[data_id] stg.distance_from_ABS_to_free_surface[data_id] = new self.fill_table() self.compute_rmin_rmax() self.compute_time_cross_section() self.compute_depth_cross_section() self.set_range_for_spinboxes_bathymetry() self.compute_BS_cross_section() self.update_plot_backscattered_acoustic_signal_recording() self.update_plot_profile() self.pushbutton_distance_from_ABS_to_free_surface.blockSignals(False) def setup_temperature_value(self): self.water_velocity() self.water_attenuation() def temperature_value(self): if findall(r",", self.lineEdit_temperature.text()): stg.temperature = float(self.lineEdit_temperature.text().replace(',', '.')) self.lineEdit_temperature.setText(self.lineEdit_temperature.text().replace(',', '.')) else: stg.temperature = float(self.lineEdit_temperature.text()) self.lineEdit_temperature.setText(self.lineEdit_temperature.text()) self.water_velocity() self.water_attenuation() def water_velocity(self): """Computing sond speed from Bilaniuk and Wong 1993""" temp = float(self.lineEdit_temperature.text()) C = (1.40238744 * 1e3 + 5.03836171 * temp - 5.81172916 * 1e-2 * temp ** 2 + 3.34638117 * 1e-4 * temp ** 3 - 1.48259672 * 1e-6 * temp ** 4 + 3.16585020 * 1e-9 * temp ** 5) stg.water_velocity = C self.lineEdit_speed_of_sound.setText(str(round(stg.water_velocity, 2))) def groupbox_gps_value_toggle(self): if self.groupbox_gps_value.isChecked() == True: self.groupbox_gps_file.setChecked(False) def groupbox_gps_value_size_change(self): duration = 500 self.animation_groupbox_gps_value = QPropertyAnimation(self.groupbox_gps_value, b"size") self.animation_groupbox_gps_value.setDuration(duration) self.animation_groupbox_gps_value.setStartValue(QSize(self.groupbox_gps_value.width(), self.groupbox_gps_value.height())) if self.groupbox_gps_value.isChecked(): self.animation_groupbox_gps_value.setEndValue( QSize(self.groupbox_gps_value.width(), self.groupbox_gps_value.sizeHint().height())) else: self.animation_groupbox_gps_value.setEndValue(QSize(self.groupbox_gps_value.width(), 25)) self.animation_groupbox_gps_value.start() def groupbox_gps_file_toggle(self): if self.groupbox_gps_file.isChecked() == True: self.groupbox_gps_value.setChecked(False) def groupbox_gps_file_size_change(self): duration = 500 self.animation_groupbox_gps_file = QPropertyAnimation(self.groupbox_gps_file, b"size") self.animation_groupbox_gps_file.setDuration(duration) self.animation_groupbox_gps_file.setStartValue(QSize(self.groupbox_gps_file.width(), self.groupbox_gps_file.height())) if self.groupbox_gps_file.isChecked(): self.animation_groupbox_gps_file.setEndValue( QSize(self.groupbox_gps_file.width(), self.groupbox_gps_file.sizeHint().height())) else: self.animation_groupbox_gps_file.setEndValue(QSize(self.groupbox_gps_file.width(), 25)) self.animation_groupbox_gps_file.start() # -------- Computing water attenuation coefficient ----------- # def water_attenuation(self): """Computing attenuation from François and Garrison 1982""" temp = float(self.lineEdit_temperature.text()) file_id = self.fileListWidget.currentRow() if self.fileListWidget.count() > 0: stg.water_attenuation[file_id].clear() for f in stg.freq[file_id]: if temp > 20: alpha = ((3.964 * 1e-4 - 1.146 * 1e-5 * temp + 1.45 * 1e-7 * temp ** 2 - 6.5 * 1e-10 * temp ** 3) * 1e-3 * (np.log(10) / 20) * (f * 1e-3) ** 2) else: alpha = ((4.937 * 1e-4 - 2.59 * 1e-5 * temp + 9.11 * 1e-7 * temp ** 2 - 1.5 * 1e-8 * temp ** 3) * 1e-3 * (np.log(10) / 20) * (f * 1e-3) ** 2) stg.water_attenuation[file_id].append(alpha) self.lineEdit_sound_attenuation.setText( str("%.6f" % stg.water_attenuation[file_id][ self.combobox_frequency_information.currentIndex()])) def open_dialog_box(self): abs_params = [ (None, None), ("AQUAscat file", "Aquascat file (*.aqa)"), ("UBSediFlow file", "UBSediFlow file (*.udt)"), ] system = self.combobox_ABS_system_choice.currentIndex() if system == 0: msgBox = QMessageBox() msgBox.setWindowTitle("Download Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText("Choose ABS system before download acoustic files") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() else: abs_name, abs_file_type = abs_params[system] filenames, _ = QFileDialog.getOpenFileNames( self, abs_name, [ stg.path_BS_raw_data[-1] if self.fileListWidget.count() > 0 else "" ][0], abs_file_type, options=QFileDialog.DontUseNativeDialog ) if len(filenames) == 0: return for n in filenames: stg.path_BS_raw_data.append(os.path.dirname(n)) stg.filename_BS_raw_data.append(os.path.basename(n)) stg.data_preprocessed.append(os.path.basename(n)) self.open_acoustic_data() def open_acoustic_data(self): # --- Fill lineEdit with path and file names + load acoustic data --- # --- fill date, hour and measurements information + fill frequency combobox for bottom detection --- system = self.combobox_ABS_system_choice.currentIndex() if system != 0: try: self.load_BS_acoustic_raw_data() except ValueError as e: msgBox = QMessageBox() msgBox.setWindowTitle("Download Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText("Please select a file") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() else: self.fileListWidget.blockSignals(True) if self.fileListWidget.count() == 0: for p, f in zip(stg.path_BS_raw_data, stg.filename_BS_raw_data): self.fileListWidget.addFilenames([f]) self.fileListWidget.setToolTip(p) else: for k in range(self.fileListWidget.count(), len(stg.filename_BS_raw_data), 1): self.fileListWidget.addFilenames( [stg.filename_BS_raw_data[k]] ) self.fileListWidget.setToolTip( stg.path_BS_raw_data[k] ) self.fill_measurements_information_groupbox() self.fill_table() self.plot_backscattered_acoustic_signal_recording() self.plot_profile() self.update_frequency_combobox() self.water_attenuation() self.compute_tmin_tmax() self.compute_rmin_rmax() self.set_range_for_spinboxes_bathymetry() stg.acoustic_data = list( range( self.fileListWidget.count() ) ) self.fileListWidget.blockSignals(False) def rename_file_in_ListWidget(self, event): if event.type() == QEvent.ContextMenu: menu = QMenu() menu.addAction('Rename') def remove_file_from_ListWidget(self): if self.fileListWidget.count() <= 0: return self.fileListWidget.blockSignals(True) # --- Clear files included in list Widget --- current_row = self.fileListWidget.currentRow() if current_row >= 0: current_item = self.fileListWidget.takeItem(current_row) del current_item # --- Clear variables --- list_to_pop1 = [ stg.acoustic_data, stg.date, stg.hour, stg.freq, stg.freq_text, stg.nb_profiles, stg.nb_profiles_per_sec, stg.nb_cells, stg.cell_size, stg.pulse_length, stg.nb_pings_per_sec, stg.nb_pings_averaged_per_profile, stg.kt_read, stg.kt_corrected, stg.gain_rx, stg.gain_tx, stg.filename_BS_raw_data, stg.path_BS_raw_data, stg.BS_raw_data, stg.time, stg.depth, stg.BS_raw_data_reshape, stg.time_reshape, stg.depth_reshape ] for p in list_to_pop1: if isinstance(p, list): p.pop(current_row) if stg.BS_cross_section: list_to_pop2 = [ stg.rmin, stg.rmax, stg.tmin, stg.tmax, stg.time_cross_section, stg.depth_cross_section, stg.BS_cross_section ] for k in list_to_pop2: k.pop(current_row) if stg.BS_stream_bed: list_to_pop3 = [ stg.BS_stream_bed, stg.depth_bottom, stg.val_bottom, stg.ind_bottom, stg.freq_bottom_detection ] for s in list_to_pop3: s.pop(current_row) if self.fileListWidget.count() == 0: self.clear_files_from_ListWidget_reset() self.fileListWidget.blockSignals(False) def clear_files_from_ListWidget(self): self.fileListWidget.blockSignals(True) self.clear_files_data() self.clear_files_from_ListWidget_reset() self.fileListWidget.blockSignals(False) def clear_files_from_ListWidget_reset(self): self.fileListWidget.clear() # self.fileListWidget.takeItem(0) if self.fileListWidget.count() == 0: # --- Clear measurmeents information --- self.label_date_acoustic_file.clear() self.label_date_acoustic_file.setText("Date: ") self.label_hour_acoustic_file.clear() self.label_hour_acoustic_file.setText("Hour: ") self.lineEdit_sound_attenuation.setText("0.00") self.combobox_frequency_information.clear() self.label_profiles_value.clear() self.label_profiles_per_sec_value.clear() self.label_cells_value.clear() self.label_cell_size_value.clear() self.label_pulse_length_value.clear() self.label_pings_per_sec_value.clear() self.label_pings_per_profile_value.clear() self.lineEdit_kt.setText("0.00") self.lineEdit_rx.setText("0.00") self.lineEdit_tx.setText("0.00") # --- Clear display options --- self.label_time_min.setText("0.00") self.lineEdit_time_min_limits.setText("0.00") self.lineEdit_time_max_limits.setText("0.00") self.label_time_max.setText("0.00") self.label_depth_min.setText("0.00") self.lineEdit_depth_min_limits.setText("0.00") self.lineEdit_depth_max_limits.setText("0.00") self.label_depth_max.setText("0.00") self.label_distance_from_bank_min.setText("0.00") self.lineEdit_distance_from_bank_min_limits.setText("0.00") self.lineEdit_distance_from_bank_max_limits.setText("0.00") self.label_distance_from_bank_max.setText("0.00") self.combobox_frequency_bathymetry.clear() self.lineEdit_depth_min_bathy.setText("0.00") self.lineEdit_depth_max_bathy.setText("0.00") self.lineEdit_next_cell_bathy.setText("0.00") # --- Clear table of values --- self.tableView.reset() data = pd.DataFrame(np.zeros((10, 10))) self.tableModel = TableModel(data) self.tableView.setModel(self.tableModel) # --- Clear figure : 2D plot of the acoustic recording --- self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.removeWidget(self.scroll_BS) self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.removeWidget(self.toolbar_BS) self.canvas_BS = FigureCanvas() self.toolbar_BS = NavigationToolBar(self.canvas_BS, self) self.scroll_BS.setWidget(self.canvas_BS) self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.addWidget(self.toolbar_BS) self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data.addWidget(self.scroll_BS) # --- Clear figure : profile --- self.combobox_frequency_profile.clear() self.verticalLayout_groupbox_plot_profile.removeWidget(self.canvas_plot_profile) self.verticalLayout_groupbox_plot_profile.removeWidget(self.toolbar_profile) self.canvas_plot_profile = FigureCanvas() self.toolbar_profile = NavigationToolBar(self.canvas_plot_profile, self) self.verticalLayout_groupbox_plot_profile.addWidget(self.toolbar_profile) self.verticalLayout_groupbox_plot_profile.addWidget(self.canvas_plot_profile) self.slider.setValue(0) self.slider.setMaximum(10) def clear_files_data(self): list_to_clear = [ stg.acoustic_data, stg.date, stg.hour, stg.freq, stg.freq_text, stg.nb_profiles, stg.nb_profiles_per_sec, stg.nb_cells, stg.cell_size, stg.pulse_length, stg.nb_pings_per_sec, stg.nb_pings_averaged_per_profile, stg.kt_read, stg.kt_corrected, stg.gain_rx, stg.gain_tx, stg.filename_BS_raw_data, stg.path_BS_raw_data, stg.BS_raw_data, stg.time, stg.depth, stg.BS_raw_data_reshape, stg.time_reshape, stg.depth_reshape, stg.rmin, stg.rmax, stg.tmin, stg.tmax, stg.time_cross_section, stg.depth_cross_section, stg.BS_cross_section, stg.BS_stream_bed ] for k in list_to_clear: if isinstance(k, list): k.clear() def load_BS_acoustic_raw_data(self): if self.fileListWidget.count() == 0: for p, f in zip(stg.path_BS_raw_data, stg.filename_BS_raw_data): if self.combobox_ABS_system_choice.currentIndex() == 1: acoustic_data = AcousticDataLoader( os.path.join(p, f) ) elif self.combobox_ABS_system_choice.currentIndex() == 2: acoustic_data = AcousticDataLoaderUBSediFlow( os.path.join(p, f) ) self.initiate_setting_parameters( acoustic_data=acoustic_data ) else: for k in range(self.fileListWidget.count(), len(stg.filename_BS_raw_data), 1): if self.combobox_ABS_system_choice.currentIndex() == 1: acoustic_data = AcousticDataLoader( os.path.join( stg.path_BS_raw_data[k], stg.filename_BS_raw_data[k] ) ) elif self.combobox_ABS_system_choice.currentIndex() == 2: acoustic_data = AcousticDataLoaderUBSediFlow( os.path.join( stg.path_BS_raw_data[k], stg.filename_BS_raw_data[k] ) ) self.initiate_setting_parameters( acoustic_data=acoustic_data ) def initiate_setting_parameters(self, acoustic_data): # --- The acoustic variables are field with loaded data --- stg.ABS_name.append(self.combobox_ABS_system_choice.currentText()) stg.BS_raw_data.append(acoustic_data._BS_raw_data) stg.BS_raw_data_reshape.append(acoustic_data.reshape_BS_raw_data()) stg.depth.append(acoustic_data._r) stg.depth_2D.append(np.array([])) stg.depth_reshape.append(acoustic_data.reshape_r()) stg.time.append(acoustic_data._time) stg.time_reshape.append(acoustic_data.reshape_t()) stg.freq.append(acoustic_data._freq) stg.freq_text.append(acoustic_data._freq_text) stg.date.append(acoustic_data._date) stg.hour.append(acoustic_data._hour) stg.distance_from_ABS_to_free_surface.append(0.00) stg.nb_profiles.append(acoustic_data._nb_profiles) stg.nb_profiles_per_sec.append(acoustic_data._nb_profiles_per_sec) stg.nb_cells.append(acoustic_data._nb_cells) stg.cell_size.append(acoustic_data._cell_size) stg.pulse_length.append(acoustic_data._cell_size) stg.nb_pings_per_sec.append(acoustic_data._nb_pings_per_sec) stg.nb_pings_averaged_per_profile.append(acoustic_data._nb_pings_averaged_per_profile) if self.combobox_ABS_name.currentIndex() == 1: stg.kt_read = acoustic_data._kt else: stg.kt_read = [0*i for i in range(acoustic_data._freq.shape[0])] stg.gain_rx.append(acoustic_data._gain_rx) stg.gain_tx.append(acoustic_data._gain_tx) stg.water_attenuation.append([]) self.initiate_setting_parameters_new_others() def initiate_setting_parameters_new_others(self): stg.BS_cross_section.append(np.array([])) stg.depth_cross_section.append(np.array([])) stg.time_cross_section.append(np.array([])) stg.tmin.append((0, 0)) stg.tmax.append((0, 0)) stg.rmin.append((0, 0)) stg.rmax.append((0, 0)) stg.BS_stream_bed.append(np.array([])) stg.depth_bottom.append(np.array([])) stg.val_bottom.append([]) stg.ind_bottom.append([]) stg.freq_bottom_detection.append((0, 0)) stg.depth_bottom_detection_min.append(0.0) stg.depth_bottom_detection_max.append(0.0) stg.depth_bottom_detection_interval.append(0.0) stg.BS_mean.append(np.array([])) stg.BS_noise_raw_data.append(np.array([])) stg.BS_noise_averaged_data.append(np.array([])) stg.SNR_raw_data.append(np.array([])) stg.SNR_cross_section.append(np.array([])) stg.SNR_stream_bed.append(np.array([])) stg.time_noise.append(np.array([])) stg.depth_noise.append(np.array([])) stg.noise_method.append(0) stg.noise_value.append(0) stg.SNR_filter_value.append(0) stg.Nb_cells_to_average_BS_signal.append(0) stg.filename_BS_noise_data.append("") stg.path_BS_noise_data.append("") stg.BS_raw_data_pre_process_SNR.append(np.array([])) stg.BS_raw_data_pre_process_average.append(np.array([])) stg.BS_cross_section_pre_process_SNR.append(np.array([])) stg.BS_cross_section_pre_process_average.append(np.array([])) stg.BS_stream_bed_pre_process_SNR.append(np.array([])) stg.BS_stream_bed_pre_process_average.append(np.array([])) stg.FCB = np.array([]) stg.depth_real = np.array([]) stg.lin_reg = [] stg.kt2D.append(np.array([])) stg.kt3D.append(np.array([])) stg.J_cross_section.append([np.array([]), np.array([])]) stg.VBI_cross_section.append(np.array([])) stg.SSC_fine.append(np.array([])) stg.SSC_sand.append(np.array([])) def fill_measurements_information_groupbox(self): if self.fileListWidget.currentRow() == -1: return self.fill_measurements_information_groupbox_datetime() self.fill_measurements_information_groupbox_frequency() self.fill_measurements_information_groupbox_cells() self.fill_measurements_information_groupbox_kt() self.water_velocity() self.water_attenuation() def fill_measurements_information_groupbox_datetime(self): file_id = self.fileListWidget.currentRow() logger.debug(f"file_id: {file_id}") logger.debug(f"stg.date: {stg.date}") self.label_date_acoustic_file.clear() self.label_date_acoustic_file.setText( "Date: " + str(stg.date[file_id]) ) self.gridLayout_groupbox_info.addWidget( self.label_date_acoustic_file, 1, 0, 1, 1, Qt.AlignLeft ) self.label_hour_acoustic_file.clear() self.label_hour_acoustic_file.setText( "Hour: " + str(stg.hour[file_id]) ) self.gridLayout_groupbox_info.addWidget( self.label_hour_acoustic_file, 1, 1, 1, 1, Qt.AlignLeft ) def fill_measurements_information_groupbox_frequency(self): file_id = self.fileListWidget.currentRow() freq_id = self.combobox_frequency_information.currentIndex() self.combobox_frequency_information.clear() self.combobox_frequency_information.addItems( stg.freq_text[file_id] ) self.combobox_frequency_information\ .currentIndexChanged\ .connect(self.combobox_frequency_information_update) self.lineEdit_distance_from_ABS_to_free_surface.setText( str(stg.distance_from_ABS_to_free_surface[file_id]) ) logger.debug(f"Set temperature = {stg.temperature}") self.lineEdit_temperature.setText(str(stg.temperature)) self.label_profiles_value.setText( str(stg.nb_profiles[file_id][freq_id]) ) self.gridLayout_groupbox_info.addWidget( self.label_profiles_value, 8, 1, 1, 1, Qt.AlignLeft ) self.label_profiles_per_sec_value.setText( str(stg.nb_profiles_per_sec[file_id][freq_id]) + " Hz" ) self.gridLayout_groupbox_info.addWidget( self.label_profiles_per_sec_value, 9, 1, 1, 1, Qt.AlignLeft ) def fill_measurements_information_groupbox_cells(self): file_id = self.fileListWidget.currentRow() freq_id = self.combobox_frequency_information.currentIndex() self.label_cells_value.setText( str(stg.nb_cells[file_id][freq_id]) ) self.gridLayout_groupbox_info.addWidget( self.label_cells_value, 10, 1, 1, 1, Qt.AlignLeft ) self.label_cell_size_value.setText( str(100*round(stg.cell_size[file_id][freq_id], 3)) + " cm" ) self.gridLayout_groupbox_info.addWidget( self.label_cell_size_value, 11, 1, 1, 1, Qt.AlignLeft ) self.label_pulse_length_value.setText( str(round(stg.pulse_length[file_id][freq_id], 6)) + " sec" ) self.gridLayout_groupbox_info.addWidget( self.label_pulse_length_value, 12, 1, 1, 1, Qt.AlignLeft ) self.label_pings_per_sec_value.setText( str(stg.nb_pings_per_sec[file_id][freq_id]) + " Hz" ) self.gridLayout_groupbox_info.addWidget( self.label_pings_per_sec_value, 13, 1, 1, 1, Qt.AlignLeft ) self.label_pings_per_profile_value.setText( str(stg.nb_pings_averaged_per_profile[file_id][freq_id]) ) self.gridLayout_groupbox_info.addWidget( self.label_pings_per_profile_value, 14, 1, 1, 1, Qt.AlignLeft ) def fill_measurements_information_groupbox_kt(self): file_id = self.fileListWidget.currentRow() freq_id = self.combobox_frequency_information.currentIndex() abs_id = self.combobox_ABS_name.currentText() data_ABS = self.calib_kt.data_ABS[abs_id]["Frequency"].values stg.kt_corrected.clear() for f in range(stg.freq[file_id].shape[0]): freq_array = np.array( [ stg.freq[file_id][f] - freq for freq in data_ABS ] ) stg.kt_corrected.append( self.calib_kt.data_ABS[abs_id].iloc[ np.where( np.abs( freq_array ) == np.min( np.abs( freq_array ) ) )[0][0] ][1] ) self.lineEdit_kt.setText( str("%.4f" % stg.kt_corrected[freq_id]) ) self.lineEdit_kt.setEnabled(True) self.lineEdit_kt.returnPressed.connect(self.kt_value) self.lineEdit_rx.setText( str("%.2f" % stg.gain_rx[file_id][freq_id]) ) self.lineEdit_rx.setEnabled(False) self.checkbox_rx.stateChanged.connect( self.activate_unactivate_spinbox_rx ) self.lineEdit_rx.returnPressed.connect(self.gain_rx_value) self.lineEdit_tx.setText(str("%.2f" % stg.gain_tx[file_id][freq_id])) self.lineEdit_tx.setEnabled(False) self.checkbox_tx.stateChanged.connect( self.activate_unactivate_spinbox_tx ) self.lineEdit_tx.returnPressed.connect(self.gain_tx_value) def combobox_frequency_information_update(self): if self.fileListWidget.count() <= 0: return file_id = self.fileListWidget.currentRow() freq_id = self.combobox_frequency_information.currentIndex() if stg.water_attenuation[file_id]: self.lineEdit_sound_attenuation.setText( str( "%.6f" % stg.water_attenuation[file_id][freq_id] ) ) self.label_profiles_value.clear() self.gridLayout_groupbox_info.removeWidget( self.label_profiles_value ) self.label_profiles_value.setText( str( stg.nb_profiles[file_id][freq_id] ) ) self.gridLayout_groupbox_info.addWidget( self.label_profiles_value, 8, 1, 1, 1, Qt.AlignLeft ) self.label_profiles_per_sec_value.clear() self.label_profiles_per_sec_value.setText( str( stg.nb_profiles_per_sec[file_id][freq_id] ) + " Hz" ) self.gridLayout_groupbox_info.addWidget( self.label_profiles_per_sec_value, 9, 1, 1, 1, Qt.AlignLeft ) self.label_cells_value.clear() self.label_cells_value.setText( str( stg.nb_cells[file_id][freq_id] ) ) self.gridLayout_groupbox_info.addWidget( self.label_cells_value, 10, 1, 1, 1, Qt.AlignLeft ) self.label_cell_size_value.clear() self.gridLayout_groupbox_info.removeWidget(self.label_cell_size_value) self.label_cell_size_value.setText( str( 100 * round(stg.cell_size[file_id][freq_id], 3) ) + " cm" ) self.gridLayout_groupbox_info.addWidget( self.label_cell_size_value, 11, 1, 1, 1, Qt.AlignLeft ) self.label_pulse_length_value.clear() self.label_pulse_length_value.setText( str( round(stg.pulse_length[file_id][freq_id], 6) ) + " sec" ) self.gridLayout_groupbox_info.addWidget( self.label_pulse_length_value, 12, 1, 1, 1, Qt.AlignLeft ) self.label_pings_per_sec_value.clear() self.label_pings_per_sec_value.setText( str( stg.nb_pings_per_sec[file_id][freq_id] ) + " Hz" ) self.gridLayout_groupbox_info.addWidget( self.label_pings_per_sec_value, 13, 1, 1, 1, Qt.AlignLeft ) self.label_pings_per_profile_value.clear() self.label_pings_per_profile_value.setText( str(stg.nb_pings_averaged_per_profile[file_id][freq_id]) ) self.gridLayout_groupbox_info.addWidget( self.label_pings_per_profile_value, 14, 1, 1, 1, Qt.AlignLeft ) if self.checkbox_kt.isChecked() and len(stg.kt_corrected) > freq_id: if self.combobox_frequency_information.count() > 0: self.lineEdit_kt.setText( str("%.4f" % stg.kt_corrected[freq_id]) ) else: self.lineEdit_kt.setText(str("%.4f" % stg.kt_read[freq_id])) self.lineEdit_rx.setText( str(stg.gain_rx[file_id][freq_id]) ) self.lineEdit_tx.setText(str(stg.gain_tx[file_id][freq_id])) def activate_unactivate_spinbox_kt(self): freq_id = self.combobox_frequency_information.currentIndex() if self.checkbox_kt.isChecked(): self.lineEdit_kt.setEnabled(True) if stg.kt_corrected: self.lineEdit_kt.setText(str("%.4f" % stg.kt_corrected[freq_id])) else: self.lineEdit_kt.setDisabled(True) if stg.kt_read: self.lineEdit_kt.setText(str("%.4f" % stg.kt_read[freq_id])) def activate_unactivate_spinbox_rx(self): if self.checkbox_rx.isChecked(): self.lineEdit_rx.setEnabled(True) else: self.lineEdit_rx.setDisabled(True) def activate_unactivate_spinbox_tx(self): if self.checkbox_tx.isChecked(): self.lineEdit_tx.setEnabled(True) else: self.lineEdit_tx.setDisabled(True) def kt_value(self): if self.fileListWidget.count() <= 0: return if not self.checkbox_kt.isChecked(): return freq_id = self.combobox_frequency_information.currentIndex() if findall(r",", self.lineEdit_kt.text()): stg.kt_corrected[freq_id] = ( float(self.lineEdit_kt.text().replace(',', '.')) ) self.lineEdit_kt.setText( "%.4f" % float( self.lineEdit_kt.text().replace(',', '.') ) ) else: stg.kt_corrected[freq_id] = ( float(self.lineEdit_kt.text()) ) self.lineEdit_kt.setText("%.4f" % float(self.lineEdit_kt.text())) def gain_rx_value(self): freq_id = self.combobox_frequency_information.currentIndex() if self.fileListWidget.count() > 0: stg.gain_rx[self.fileListWidget.currentRow()][freq_id] = ( float(self.lineEdit_rx.text()) ) def gain_tx_value(self): freq_id = self.combobox_frequency_information.currentIndex() if self.fileListWidget.count() > 0: stg.gain_tx[self.fileListWidget.currentRow()][freq_id] = ( float(self.lineEdit_tx.text()) ) def fill_table(self): # if self.fileListWidget.currentRow() != -1: if self.fileListWidget.selectedItems() != []: file_id = self.fileListWidget.currentRow() header_list = [] header_list.clear() table_data = np.array([[]]) for freq_ind, freq_value in enumerate(stg.freq_text[0]): header_list.append("Time - " + freq_value) header_list.append("Depth - " + freq_value) header_list.append("BS - " + freq_value) if freq_ind == 0: table_data = np.vstack( ( np.vstack( ( stg.time_reshape[file_id][:, freq_ind], stg.depth_reshape[file_id][:, freq_ind] ) ), stg.BS_raw_data_reshape[file_id][:, freq_ind] ) ) else: table_data = np.vstack(( table_data, np.vstack( ( np.vstack( ( stg.time_reshape[file_id][:, freq_ind], stg.depth_reshape[file_id][:, freq_ind] ) ), stg.BS_raw_data_reshape[file_id][:, freq_ind] ) ) )) stg.DataFrame_acoustic = pd.DataFrame(None) stg.DataFrame_acoustic = pd.DataFrame( data=table_data.transpose(), columns=header_list ) self.tableModel = TableModel(stg.DataFrame_acoustic) self.tableView.setModel(self.tableModel) def transect_xaxis_choice(self): if self.groupbox_xaxis_time.isChecked() == True: self.groupbox_xaxis_space.setChecked(False) elif self.groupbox_xaxis_space.isChecked() == True: self.groupbox_xaxis_time.setChecked(False) def compute_tmin_tmax(self): ''' tmin and tmax are filled with min and max of time when data are uploaded and double slider of time are updated with these values ''' if self.fileListWidget.currentRow() == -1: return data_id = self.fileListWidget.currentRow() tmin_indice = np.where( np.abs( stg.time[data_id][0, :] - np.nanmin(stg.time[data_id][0, :]) ) == np.nanmin( np.abs( stg.time[data_id][0, :] - np.nanmin(stg.time[data_id][0, :]) ) ) )[0][0] tmin_value = np.round( np.nanmin(stg.time[data_id][0, :]), 2 ) stg.tmin[data_id] = (tmin_indice, tmin_value) tmax_indice = np.where( np.abs( stg.time[data_id][0, :] - np.nanmax(stg.time[data_id][0, :]) ) == np.nanmin( np.abs( stg.time[data_id][0, :] - np.nanmax(stg.time[data_id][0, :]) ) ) )[0][0] tmax_value = np.round(np.nanmax(stg.time[data_id][0, :]), 2) stg.tmax[data_id] = (tmax_indice + 1, tmax_value) self.set_range_for_time_boundaries_option() def set_range_for_time_boundaries_option(self): data_id = self.fileListWidget.currentRow() self.label_time_min.clear() self.label_time_min.setText( f"{stg.time[data_id][0, 0]:.1f}" ) self.label_time_max.clear() self.label_time_max.setText( f"{stg.time[data_id][0, -1]:.1f}" ) if stg.time_cross_section[data_id].shape != (0,): self.lineEdit_time_min_limits.setText( f"{stg.time_cross_section[data_id][0, 0]:.1f}" ) self.lineEdit_time_max_limits.setText( f"{stg.time_cross_section[data_id][0, -1]:.1f}" ) else: self.lineEdit_time_min_limits.setText( f"{stg.time[data_id][0, 0]:.1f}" ) self.lineEdit_time_max_limits.setText( f"{stg.time[data_id][0, -1]:.1f}" ) def compute_time_cross_section(self): ''' tmin and tmax are updated with double slider of time ''' data_id = max(0, self.fileListWidget.currentRow()) time_min = float(self.lineEdit_time_min_limits.text().replace(",", ".")) time_max = float(self.lineEdit_time_max_limits.text().replace(",", ".")) stg.tmin[data_id] = (( np.where( np.abs( np.round( stg.time[data_id][0, :], 2 ) - time_min ) == np.nanmin( np.abs( np.round( stg.time[data_id][0, :], 2 ) - time_min ) ) )[0][0], time_min )) stg.tmax[data_id] = (( np.where( np.abs( np.round( stg.time[data_id][0, :], 2) - time_max ) == np.nanmin( np.abs( np.round( stg.time[data_id][0, :],2) - time_max ) ) )[0][0] + 1, time_max )) stg.time_cross_section[data_id] = ( stg.time[data_id][ :, stg.tmin[data_id][0]: stg.tmax[data_id][0] ] ) def compute_rmin_rmax(self): ''' rmin and rmax are filled with min and max of depth when data are uploaded and double slider of depth are updated with these values ''' if self.fileListWidget.currentRow() == -1: return data_id = self.fileListWidget.currentRow() # --- rmim / rmax --- rmin_indice = np.where( np.abs( stg.depth[data_id][0, :] - np.nanmin(stg.depth[data_id][0, :]) ) == np.nanmin( np.abs( stg.depth[data_id][0, :] - np.nanmin(stg.depth[data_id][0, :]) ) ) )[0][0] rmin_value = np.round(np.nanmin(stg.depth[data_id][0, :]), 2) stg.rmin[data_id] = (rmin_indice, rmin_value) rmax_indice = np.where( np.abs( stg.depth[data_id][0, :] - np.nanmax(stg.depth[data_id][0, :]) ) == np.nanmin( np.abs( stg.depth[data_id][0, :] - np.nanmax(stg.depth[data_id][0, :]) ) ) )[0][0] rmax_value = np.round(np.nanmax(stg.depth[data_id][0, :]), 2) stg.rmax[data_id] = (rmax_indice + 1, rmax_value) self.set_range_for_depth_boundaries_option() def set_range_for_depth_boundaries_option(self): data_id = self.fileListWidget.currentRow() self.label_depth_min.clear() self.label_depth_min.setText("-" + str("%.5s" % stg.depth[data_id][0, -1])) self.label_depth_max.clear() self.label_depth_max.setText("-" + str("%.5s" % stg.depth[data_id][0, 0])) if stg.depth_cross_section[data_id].shape != (0,): self.lineEdit_depth_min_limits.setText( "-" + str("%.5s" % stg.depth_cross_section[data_id][0, -1]) ) self.lineEdit_depth_max_limits.setText( "-" + str("%.5s" % stg.depth_cross_section[data_id][0, 0]) ) else: self.lineEdit_depth_min_limits.setText( "-" + str("%.5s" % stg.depth[data_id][0, -1]) ) self.lineEdit_depth_max_limits.setText( "-" + str("%.5s" % stg.depth[data_id][0, 0]) ) def compute_depth_cross_section(self): ''' rmin and rmax are updated with double slider of depth ''' data_id = self.fileListWidget.currentRow() round_depth = np.round(stg.depth[data_id][0, :], 2) depth_max = float( "".join( findall( "[.0-9]", self.lineEdit_depth_max_limits.text() ) ) ) depth_min = float( "".join( findall( "[.0-9]", self.lineEdit_depth_min_limits.text() ) ) ) diff_max = np.abs(round_depth - depth_max) diff_min = np.abs(round_depth - depth_min) stg.rmin[data_id] = (( np.where(diff_max == np.nanmin(diff_max))[0][0]+1, depth_max )) stg.rmax[data_id] = (( np.where(diff_min == np.nanmin(diff_min))[0][0], depth_min )) stg.depth_cross_section[data_id] = ( stg.depth[data_id][ :, stg.rmin[data_id][0]:stg.rmax[data_id][0] ] ) def compute_BS_cross_section(self): if self.fileListWidget.currentRow() == -1: return data_id = self.fileListWidget.currentRow() self.compute_depth_cross_section() self.compute_time_cross_section() stg.BS_cross_section[data_id] = ( stg.BS_raw_data[data_id][ :, stg.rmin[data_id][0]:stg.rmax[data_id][0], stg.tmin[data_id][0]:stg.tmax[data_id][0] ] ) def update_frequency_combobox(self): data_id = self.fileListWidget.currentRow() if data_id == -1: return self.combobox_frequency_bathymetry.clear() self.combobox_frequency_bathymetry.addItems( [f for f in stg.freq_text[data_id]] ) self.combobox_frequency_profile.clear() self.combobox_frequency_profile.addItems( [f for f in stg.freq_text[data_id]] ) def set_range_for_doubleRangeSlider_intg_area(self): if self.fileListWidget.currentRow() == -1: return data_id = self.fileListWidget.currentRow() if stg.depth_cross_section[data_id].shape == (0,): self.doubleRangeSlider_intg_area.setRange( min=-stg.depth[data_id][0, -1], max=-stg.depth[data_id][0, 0] ) self.doubleRangeSlider_intg_area.setValue( value=( -stg.depth[data_id][0, -1], -stg.depth[data_id][0, 0] ) ) else: self.doubleRangeSlider_intg_area.setRange( min=-stg.depth_cross_section[data_id][0, -1], max=-stg.depth_cross_section[data_id][0, 0] ) self.doubleRangeSlider_intg_area.setValue( value=( -stg.depth_cross_section[data_id][0, -1], -stg.depth_cross_section[data_id][0, 0] ) ) def set_range_for_spinboxes_bathymetry(self): if self.fileListWidget.currentRow() == -1: return data_id = self.fileListWidget.currentRow() if stg.depth_cross_section[data_id].shape != (0,): self.lineEdit_depth_min_bathy.setText( "-" + str("%.5s" % stg.depth_cross_section[data_id][0, -1]) ) self.lineEdit_depth_max_bathy.setText( "-" + str("%.5s" % stg.depth_cross_section[data_id][0, 0]) ) else: self.lineEdit_depth_min_bathy.setText( "-" + str("%.5s" % stg.depth[data_id][0, -1]) ) self.lineEdit_depth_max_bathy.setText( "-" + str("%.5s" % stg.depth[data_id][0, 0]) ) def plot_backscattered_acoustic_signal_recording(self): if self.fileListWidget.count() <= 0: return layout = self.verticalLayout_groupbox_transect_2Dplot_raw_BS_data file_id = self.fileListWidget.currentRow() freq_id = self.combobox_frequency_profile.currentIndex() layout.removeWidget(self.toolbar_BS) layout.removeWidget(self.scroll_BS) if self.fig_BS is not None: self.fig_BS.clear() self.fig_BS, self.axis_BS = plt.subplots( nrows=stg.freq[file_id].shape[0], ncols=1, sharex=False, sharey=False, layout="constrained" ) self.canvas_BS = FigureCanvas(self.fig_BS) self.toolbar_BS = NavigationToolBar(self.canvas_BS, self) self.scroll_BS.setWidget(self.canvas_BS) layout.addWidget(self.toolbar_BS) layout.addWidget(self.scroll_BS) for f, _ in enumerate(stg.freq[file_id]): val_min = np.nanmin(stg.BS_raw_data[file_id][f, :, :]) val_max = np.nanmax(stg.BS_raw_data[file_id][f, :, :]) if val_min == 0: val_min = 1e-5 if self.combobox_ABS_system_choice.currentIndex() == 1: pcm = self.axis_BS[f].pcolormesh( stg.time[file_id][f, :], -stg.depth[file_id][f, :], stg.BS_raw_data[file_id][f, :, :], cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max) ) elif self.combobox_ABS_system_choice.currentIndex() == 2: pcm = self.axis_BS[f].pcolormesh( stg.time[file_id][f, :], -stg.depth[file_id][f, :], np.log(stg.BS_raw_data[file_id][f, :, :]), cmap='Blues' ) self.axis_BS[f].text( 1, .70, stg.freq_text[file_id][f], fontsize=14, fontweight='bold', fontname="DejaVu Sans", c="black", alpha=0.5, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_BS[f].transAxes ) # --- Plot red solid line on transect to visualize position of # --- plotted profile --- self.axis_BS[freq_id].plot( stg.time[file_id][ freq_id, self.slider.value() - 1 ] * np.ones(stg.depth[file_id].shape[1]), -stg.depth[file_id][freq_id, :], color='red', linestyle="solid", linewidth=2 ) self.fig_BS.supxlabel('Time (sec)', fontsize=10) self.fig_BS.supylabel('Depth (m)', fontsize=10) cbar = self.fig_BS.colorbar( pcm, ax=self.axis_BS[:], shrink=1, location='right' ) cbar.set_label( label='Acoustic backscatter signal (V)', rotation=270, labelpad=10 ) self.fig_BS.canvas.draw_idle() def update_plot_backscattered_acoustic_signal_recording(self): # --- Condition if table is filled but transect is not plotted # --- => Error message if spin box values of tmin or tmax is change if self.canvas_BS == None: msgBox = QMessageBox() msgBox.setWindowTitle("Plot transect Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText("Plot transect before change x-axis value") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() return data_id = max(0, self.fileListWidget.currentRow()) if data_id == -1: return if len(self.axis_BS.tolist()) != stg.freq[data_id].shape[0]: if self.fig_BS is not None: self.fig_BS.clear() self.fig_BS, self.axis_BS = plt.subplots( nrows=stg.freq[data_id].shape[0], ncols=1, sharex=False, sharey=False, layout="constrained" ) for f, _ in enumerate(stg.freq[data_id]): self.axis_BS[f].cla() if stg.BS_cross_section[data_id].shape != (0,): BS_data = stg.BS_cross_section time_data = stg.time_cross_section depth_data = stg.depth_cross_section else: BS_data = stg.BS_raw_data time_data = stg.time depth_data = stg.depth val_min = np.nanmin(BS_data[data_id][f, :, :]) val_max = np.nanmax(BS_data[data_id][f, :, :]) if val_min == 0: val_min = 1e-5 if self.combobox_ABS_system_choice.currentIndex() == 1: pcm = self.axis_BS[f].pcolormesh( time_data[data_id][f, :], -depth_data[data_id][f, :], BS_data[data_id][f, :, :], cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max) ) elif self.combobox_ABS_system_choice.currentIndex() == 2: pcm = self.axis_BS[f].pcolormesh( time_data[data_id][f, :], -depth_data[data_id][f, :], np.log(BS_data[data_id][f, :, :]), cmap='Blues' ) # --- Plot red solid line on transect to visualize position of plotted profile --- slider_value = [ self.slider.value() - 1 if self.slider.value() - 1 <= time_data[data_id].shape[1] - 1 else np.max(time_data[data_id].shape[1] - 1) ][0] freq_id = self.combobox_frequency_profile.currentIndex() self.axis_BS[freq_id].plot( time_data[data_id][0, slider_value] * np.ones( depth_data[data_id].shape[1] ), -depth_data[data_id][freq_id, :], color='red', linestyle="solid", linewidth=2 ) # --- Plot river bottom line --- if stg.depth_bottom[data_id].shape != (0,): self.axis_BS[f].plot( time_data[data_id][ self.combobox_frequency_bathymetry.currentIndex(), : ], -stg.depth_bottom[data_id], color='black', linewidth=1, linestyle="solid" ) self.fig_BS.supxlabel('Time (sec)', fontsize=10) self.fig_BS.supylabel('Depth (m)', fontsize=10) self.fig_BS.canvas.draw_idle() def plot_profile(self): if self.fileListWidget.currentRow() != -1: self.combobox_frequency_profile.setCurrentIndex(0) self.combobox_frequency_profile.currentIndexChanged.connect(self.update_plot_profile) self.combobox_frequency_profile.currentIndexChanged.connect( self.update_plot_backscattered_acoustic_signal_recording ) self.slider.setMaximum(stg.time[self.fileListWidget.currentRow()].shape[1]) self.verticalLayout_groupbox_plot_profile.removeWidget(self.toolbar_profile) self.verticalLayout_groupbox_plot_profile.removeWidget(self.canvas_plot_profile) # --- Figure to plot profiles --- if self.fig_profile is not None: self.fig_profile.clear() self.fig_profile, self.axis_profile = plt.subplots(nrows=1, ncols=1, layout="constrained") self.canvas_plot_profile = FigureCanvas(self.fig_profile) self.toolbar_profile = NavigationToolBar(self.canvas_plot_profile, self) self.verticalLayout_groupbox_plot_profile.addWidget(self.toolbar_profile) self.verticalLayout_groupbox_plot_profile.addWidget(self.canvas_plot_profile) slider_value = [ self.slider.value() - 1 if self.slider.value() - 1 <= stg.time[self.fileListWidget.currentRow()].shape[ 1] - 1 else np.max(stg.time[self.fileListWidget.currentRow()].shape[1] - 1)][0] # --- Profile plot --- self.axis_profile.plot(stg.BS_raw_data[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :, self.slider.value() - 1], -stg.depth[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), :], linestyle='solid', color='k', linewidth=1) self.axis_profile.text(.95, .05, stg.freq_text[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()], fontsize=10, fontweight='bold', fontname="DejaVu Sans", fontstyle="normal", c="black", alpha=0.2, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_profile.transAxes) # --- Plot bottom line --- if len(stg.depth_bottom[self.fileListWidget.currentRow()]) != 0: self.axis_profile.plot([0, np.nanmax(stg.BS_raw_data[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :, slider_value])], -stg.depth[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), int(stg.ind_bottom[self.fileListWidget.currentRow()][slider_value])] * np.ones(2), linestyle='solid', color='r', linewidth=1) position_x = (stg.depth[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), int(stg.ind_bottom[self.fileListWidget.currentRow()][slider_value])] / np.nanmax( stg.depth[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), :])) self.axis_profile.text(.95, 1 - position_x + 0.05, "River bed", fontsize=10, fontweight='normal', fontname="Times New Roman", fontstyle="italic", c="red", alpha=0.2, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_profile.transAxes) self.fig_profile.supxlabel("Acoustic Backscatter Signal (V)") self.fig_profile.supylabel("Depth (m)") self.fig_profile.canvas.draw_idle() def update_plot_profile(self): if self.fileListWidget.currentRow() != -1: if stg.BS_cross_section[self.fileListWidget.currentRow()].shape != (0,): self.axis_profile.cla() # --- Set slider value --- self.slider.setMaximum(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1]) slider_value = [self.slider.value() - 1 if self.slider.value() - 1 <= stg.time_cross_section[ self.fileListWidget.currentRow()].shape[1] - 1 else np.max(stg.time_cross_section[self.fileListWidget.currentRow()].shape[1] - 1)][0] # --- Profile plot --- self.axis_profile.plot(stg.BS_cross_section[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :, slider_value], -stg.depth_cross_section[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :], linestyle='solid', color='k', linewidth=1) # --- Write frequency on graph --- self.axis_profile.text(.95, .90, stg.freq_text[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex()], fontsize=14, fontweight='bold', fontname="DejaVu Sans", fontstyle="normal", c="black", alpha=0.2, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_profile.transAxes) # --- Plot bottom line --- if stg.depth_bottom[self.fileListWidget.currentRow()].shape != (0,): self.axis_profile.plot([0, np.nanmax(stg.BS_cross_section[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :, slider_value])], -stg.depth[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), int(stg.ind_bottom[self.fileListWidget.currentRow()][ slider_value])] * np.ones(2), linestyle='solid', color='r', linewidth=1) position_x = (stg.depth[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), int(stg.ind_bottom[self.fileListWidget.currentRow()][slider_value])] / np.nanmax(stg.depth[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :])) self.axis_profile.text(.95, 1 - position_x + 0.05, "River bed", fontsize=10, fontweight='normal', fontname="DejaVu Sans", fontstyle="italic", c="red", alpha=0.2, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_profile.transAxes) else: self.axis_profile.cla() # --- Set slider value --- self.slider.setMaximum(stg.time[self.fileListWidget.currentRow()].shape[1]) slider_value = [self.slider.value() - 1 if self.slider.value() - 1 <= stg.time[ self.fileListWidget.currentRow()].shape[1] - 1 else np.max(stg.time[self.fileListWidget.currentRow()].shape[1] - 1)][0] # --- Profile plot --- self.axis_profile.plot(stg.BS_raw_data[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :, self.slider.value() - 1], -stg.depth[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :], linestyle='solid', color='k', linewidth=1) # --- Write frequency on graph --- self.axis_profile.text(.95, .05, stg.freq_text[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex()], fontsize=10, fontweight='bold', fontname="DejaVu Sans", fontstyle="normal", c="black", alpha=0.2, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_profile.transAxes) # --- Plot bottom line --- if stg.depth_bottom[self.fileListWidget.currentRow()].shape != (0,): self.axis_profile.plot([0, np.nanmax(stg.BS_raw_data[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :, slider_value])], -stg.depth[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), int(stg.ind_bottom[self.fileListWidget.currentRow()][ slider_value])] * np.ones(2), linestyle='solid', color='r', linewidth=1) position_x = (stg.depth[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), int(stg.ind_bottom[self.fileListWidget.currentRow()][slider_value])] / np.nanmax(stg.depth[self.fileListWidget.currentRow()][ self.combobox_frequency_profile.currentIndex(), :])) self.axis_profile.text(.95, 1 - position_x + 0.05, "River bed", fontsize=10, fontweight='normal', fontname="DejaVu Sans", fontstyle="italic", c="red", alpha=0.2, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_profile.transAxes) self.fig_profile.supxlabel("Acoustic Backscatter Signal (V)") self.fig_profile.supylabel("Depth (m)") self.fig_profile.canvas.draw_idle() def slide_profile_number_to_begin(self): self.slider.setValue(int(self.slider.minimum())) self.update_lineEdit_by_moving_slider() def slide_profile_number_to_right(self): self.slider.setValue(int(self.slider.value()) + 1) self.update_lineEdit_by_moving_slider() def slide_profile_number_to_left(self): self.slider.setValue(int(self.slider.value()) - 1) self.update_lineEdit_by_moving_slider() def slide_profile_number_to_end(self): self.slider.setValue(int(self.slider.maximum())) self.update_lineEdit_by_moving_slider() def profile_number_on_lineEdit(self): if stg.time_cross_section[self.fileListWidget.currentRow()].shape != (0,): self.slider.setValue( int(np.where(np.abs(stg.time_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()] - float(self.lineEdit_slider.text().replace(",", "."))) == np.nanmin(np.abs(stg.time_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()] - float(self.lineEdit_slider.text().replace(",", ".")))))[0][0])) else: self.slider.setValue( int(np.where(np.abs(stg.time[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()] - float(self.lineEdit_slider.text().replace(",", "."))) == np.nanmin(np.abs(stg.time[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex()] - float(self.lineEdit_slider.text().replace(",", ".")))))[0][0])) def update_lineEdit_by_moving_slider(self): if stg.time_cross_section[self.fileListWidget.currentRow()].shape != (0,): self.lineEdit_slider.setText( str(stg.time_cross_section[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), self.slider.value()-1])) else: self.lineEdit_slider.setText( str(stg.time[self.fileListWidget.currentRow()][self.combobox_frequency_profile.currentIndex(), self.slider.value()-1])) def update_bottom_detection_settings(self): data_id = max(0, self.fileListWidget.currentRow()) if stg.depth_bottom_detection_interval[data_id] == 0.0: self.set_range_for_spinboxes_bathymetry() return self.combobox_frequency_bathymetry.setCurrentIndex( int(stg.freq_bottom_detection[data_id][0]) ) self.lineEdit_depth_min_bathy.setText( str(stg.depth_bottom_detection_min[data_id]) ) self.lineEdit_depth_max_bathy.setText( str(stg.depth_bottom_detection_max[data_id]) ) self.lineEdit_next_cell_bathy.setText( str(stg.depth_bottom_detection_interval[data_id]) ) def save_bottom_detection_settings(self): data_id = max(0, self.fileListWidget.currentRow()) stg.freq_bottom_detection[data_id] = ( int(self.combobox_frequency_bathymetry.currentIndex()), str(self.combobox_frequency_bathymetry.currentText()), ) stg.depth_bottom_detection_min[data_id] = float( self.lineEdit_depth_min_bathy.text() ) stg.depth_bottom_detection_max[data_id] = float( self.lineEdit_depth_max_bathy.text() ) stg.depth_bottom_detection_interval[data_id] = float( self.lineEdit_next_cell_bathy.text() ) def detect_bottom(self): self.save_bottom_detection_settings() if self.fileListWidget.count() == 0: msgBox = QMessageBox() msgBox.setWindowTitle("Detect bottom Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText("Load data before compute bathymety algorithm") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() return elif self.canvas_BS == None: msgBox = QMessageBox() msgBox.setWindowTitle("Detect bottom Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText("Plot transect before compute bathymety algorithm") msgBox.setStandardButtons(QMessageBox.Ok) msgBox.exec() return elif self.lineEdit_next_cell_bathy.text() == "0.00": return self.detect_bottom_compute() def detect_bottom_compute(self): data_id = max(0, self.fileListWidget.currentRow()) freq_id = self.combobox_frequency_bathymetry.currentIndex() freq_text = self.combobox_frequency_bathymetry.currentText() if stg.BS_cross_section[data_id].shape != (0,): BS_data = stg.BS_cross_section time_data = stg.time_cross_section depth_data = stg.depth_cross_section elif stg.BS_raw_data[data_id].shape != (0,): BS_data = stg.BS_raw_data time_data = stg.time depth_data = stg.depth stg.freq_bottom_detection[data_id] = (freq_id, freq_text) rmin = float( "".join(findall( "[.0-9]", self.lineEdit_depth_max_bathy.text() )) ) rmax = float( "".join(findall( "[.0-9]", self.lineEdit_depth_min_bathy.text() )) ) r_bottom = np.zeros(time_data[data_id].shape[1]) val_bottom = np.zeros(time_data[data_id].shape[1]) r_bottom_ind = [] BS_smooth = deepcopy(BS_data[data_id][freq_id, :, :]) for k in range(time_data[data_id].shape[1]): BS_smooth[:, k] = savgol_filter(BS_smooth[:, k], 10, 2) # ----------- Detecting the bottom ------------- for d in range(time_data[data_id].shape[1]): ind_min = np.where( depth_data[data_id][freq_id, :] >= rmin )[0][0] ind_max = np.where( depth_data[data_id][freq_id, :] <= rmax )[0][-1] # Getting the peak try: val_bottom[d] = np.nanmax(BS_smooth[ind_min:ind_max, d]) except ValueError as e: msgBox = QMessageBox() msgBox.setWindowTitle("Detect bottom Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText( f"1/ {e} : maximum value of section bottom is not found. \n " f"Please change parameter of algorithm" ) msgBox.setStandardButtons(QMessageBox.Ok) msgBox_return = msgBox.exec() if msgBox_return == msgBox.Ok: break else: ind_bottom = np.where( (BS_smooth[ind_min:ind_max, d]) == val_bottom[d] )[0][0] # np.append(stg.ind_bottom, ind_bottom) r_bottom[d] = depth_data[data_id][ freq_id, ind_bottom + ind_min ] r_bottom_ind.append(ind_bottom + ind_min) # Updating the range where we will look for the peak (in the next cell) rmin = r_bottom[d] - float( "".join(findall( "[.0-9]", self.lineEdit_next_cell_bathy.text() )) ) rmax = r_bottom[d] + float( "".join(findall( "[.0-9]", self.lineEdit_next_cell_bathy.text() )) ) BS_section_bottom = np.zeros(( depth_data[data_id].shape[1], time_data[data_id].shape[1] )) for i in range(BS_section_bottom.shape[0]): try: BS_section_bottom[r_bottom_ind[i]][i] = 1 except IndexError as e: msgBox = QMessageBox() msgBox.setWindowTitle("Detect bottom Error") msgBox.setIcon(QMessageBox.Warning) msgBox.setText( f"2/ {e} : maximum value of section bottom is not found. \n " f"Please change parameter of algorithm" ) msgBox.setStandardButtons(QMessageBox.Ok) msgBox_return = msgBox.exec() if msgBox_return == msgBox.Ok: break if BS_section_bottom.sum() > 2: stg.depth_bottom[data_id] = r_bottom stg.val_bottom[data_id] = val_bottom stg.ind_bottom[data_id] = r_bottom_ind BS_stream_bed_copy = deepcopy(BS_data[data_id]) for f, _ in enumerate(stg.freq[data_id]): for k, _ in enumerate(stg.depth_bottom[data_id]): BS_stream_bed_copy[ f, np.where( depth_data[data_id][freq_id, :] >= stg.depth_bottom[data_id][k] )[0], k ] = np.nan stg.BS_stream_bed[data_id] = BS_stream_bed_copy self.detect_bottom_compute_plot_BS_with_bathymetry( BS_data, time_data, depth_data ) # --- Update plot profile --- self.update_plot_profile() self.fig_BS.canvas.draw_idle() def detect_bottom_compute_plot_BS_with_bathymetry( self, BS_data, time_data, depth_data ): data_id = max(0, self.fileListWidget.currentRow()) freq_id = self.combobox_frequency_bathymetry.currentIndex() for f, _ in enumerate(stg.freq[data_id]): self.axis_BS[f].cla() val_min = np.min(stg.BS_raw_data[data_id][f, :, :]) val_max = np.max(stg.BS_raw_data[data_id][f, :, :]) if val_min == 0: val_min = 1e-5 if self.combobox_ABS_system_choice.currentIndex() == 1: pcm = self.axis_BS[f].pcolormesh( time_data[data_id][f, :], -depth_data[data_id][f, :], BS_data[data_id][f, :, :], cmap='viridis', norm=LogNorm(vmin=val_min, vmax=val_max) ) elif self.combobox_ABS_system_choice.currentIndex() == 2: pcm = self.axis_BS[f].pcolormesh( time_data[data_id][f, :], -depth_data[data_id][f, :], np.log(BS_data[data_id][f, :, :]), cmap='Blues' ) self.axis_BS[f].plot( time_data[data_id][freq_id, :], -stg.depth_bottom[data_id], color='black', linewidth=1, linestyle="solid" ) self.axis_BS[f].text( 1, .70, stg.freq_text[data_id][f], fontsize=14, fontweight='bold', fontname="DejaVu Sans", c="black", alpha=0.5, horizontalalignment='right', verticalalignment='bottom', transform=self.axis_BS[f].transAxes )