Compare commits

...

25 Commits

Author SHA1 Message Date
Pierre-Antoine 42e104cba9 git: Fix missing 'xlsxwriter' in requirements. 2025-05-07 16:08:29 +02:00
Pierre-Antoine ae6b91366a Acoustic inversion: Time the export. 2025-05-07 14:57:56 +02:00
Pierre-Antoine 5ce7ffb52b Acoustic inversion: Refactoring sand plot. 2025-05-07 14:49:25 +02:00
Pierre-Antoine abce4bac07 Acoustic inversion: Fix fine plot and minor change sand plot. 2025-05-07 14:44:29 +02:00
Pierre-Antoine a570ca3522 Sample data: Fix plot without data. 2025-05-07 14:06:48 +02:00
Pierre-Antoine 0dd38af7a9 Sediment calibration: Minor change. 2025-05-07 11:51:35 +02:00
Pierre-Antoine 34690264b1 Sediment calibration: Split 'read_calibration_file_and_fill_parameter'. 2025-05-07 11:38:57 +02:00
Pierre-Antoine d5d8fa026f Sediment calibration: Fix calibration import functions. 2025-05-07 11:24:47 +02:00
Pierre-Antoine 2df094f450 Tuto: Minor change. 2025-05-06 17:58:32 +02:00
Pierre-Antoine 8418935cd5 Packages: Put a minimal README. 2025-05-06 16:11:03 +02:00
Pierre-Antoine e1cbe77ea7 Acoused: Close mpl figure at redraw. 2025-05-06 15:33:04 +02:00
Pierre-Antoine 252b09a333 Acoustic inversion: Close plot and add ods and csv results export. 2025-05-06 15:27:06 +02:00
Pierre-Antoine 6cd0058bea Note: Fix icons path. 2025-05-06 15:02:59 +02:00
Pierre-Antoine 5add1ac9f8 Signal processing: Remove debug trace. 2025-05-06 15:02:39 +02:00
Pierre-Antoine 66024342dc SQL: read: Minor change. 2025-05-06 15:02:27 +02:00
Pierre-Antoine 8ef6c22f7c Packages: Windows: Update acoused tuto. 2025-05-06 10:07:35 +02:00
Pierre-Antoine 817be64558 Packages: Add linux wine env script. 2025-05-05 17:16:54 +02:00
Pierre-Antoine 1e8925fbb3 Windows: Change release icons and logos path to '_internal/'. 2025-05-05 16:45:09 +02:00
Pierre-Antoine fea4957f61 Plot noise window: Remove all eval and exec. 2025-05-05 15:07:28 +02:00
Pierre-Antoine bf8640fb30 Calibration constant kt: Remove all exec and eval. 2025-05-05 14:39:42 +02:00
Pierre-Antoine a6e81b3329 README: Minor change. 2025-05-05 13:30:18 +02:00
Pierre-Antoine c6bd5a1b5e README: Add images links. 2025-05-05 11:03:10 +02:00
Pierre-Antoine fa6f50b443 README: Fix image size. 2025-05-05 10:57:27 +02:00
Pierre-Antoine 7b4aeca56a README: Fix image and add links. 2025-05-05 10:50:44 +02:00
Pierre-Antoine 4f6be7d65d Calibration constant kt: Minor change. 2025-05-05 10:44:30 +02:00
18 changed files with 623 additions and 376 deletions

View File

@ -19,20 +19,19 @@
# ============================================================================== #
from os import path
import os
import pandas as pd
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QDialog, QTabWidget, QGridLayout, QScrollArea,
QFileDialog, QMessageBox, QLabel)
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QDialog, QTabWidget, QGridLayout,
QScrollArea, QFileDialog, QMessageBox, QLabel
)
from PyQt5.QtCore import Qt
class CalibrationConstantKt(QDialog):
def __init__(self, parent=None):
super(CalibrationConstantKt, self).__init__(parent)
self.setGeometry(400, 200, 300, 400)
self.setWindowTitle("Calibration constant kt")
self.verticalLayout_Main = QVBoxLayout()
@ -41,15 +40,18 @@ class CalibrationConstantKt(QDialog):
self.verticalLayout_Main.addWidget(self.tab)
try:
self.data_ABS = pd.read_excel("ABS_calibration_constant_kt.xlsx", header=0, sheet_name=None)
self.data_ABS = pd.read_excel(
"ABS_calibration_constant_kt.xlsx",
header=0, sheet_name=None
)
except FileNotFoundError as e:
msgBox = QMessageBox()
msgBox.setWindowTitle("File Not Found Error")
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("Please check Excel file name for the calibration constant kt \n"
"It should be an excel file named : 'ABS_calibration_constant_kt.xlsx'")
msgBox.setText(
"Please check Excel file name for the calibration constant kt \n"
"It should be an excel file named : 'ABS_calibration_constant_kt.xlsx'"
)
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
@ -57,58 +59,74 @@ class CalibrationConstantKt(QDialog):
self.load_freq_and_kt_values()
def open_dialog_box(self):
filename = QFileDialog.getOpenFileNames(self, "Calibration file", "", "Calibration file (*.xlsx)",
options=QFileDialog.DontUseNativeDialog)
print(filename)
dir_name = path.dirname(filename[0][0])
file_name = path.basename(filename[0][0])
filename = QFileDialog.getOpenFileNames(
self, "Calibration file", "", "Calibration file (*.xlsx)",
options=QFileDialog.DontUseNativeDialog
)
dir_name = os.path.dirname(filename[0][0])
file_name = os.path.basename(filename[0][0])
print(f"dir name : {dir_name} & file name : {file_name}")
self.data_ABS = pd.read_excel(dir_name + "/" + file_name)
self.data_ABS = pd.read_excel(os.path.join(dir_name, file_name))
self.lineEdit_file.setText(file_name)
self.load_freq_and_kt_values()
def load_freq_and_kt_values(self):
for t in range(len(self.data_ABS.keys())):
self.tab.removeTab(t)
for t_index, t_value in enumerate(list(self.data_ABS.keys())):
tab_calib = QWidget()
self.tab.addTab(tab_calib, t_value)
exec("self.tab_calib_" + str(t_index) + "= QWidget()")
eval("self.tab.addTab(self.tab_calib_" + str(t_index) + ", '" + str(t_value) + "')")
verticalLayout = QVBoxLayout(tab_calib)
exec("self.verticalLayout_tab_" + str(t_index) + "= QVBoxLayout(self.tab_calib_" + str(t_index) + ")")
scrollarea = QScrollArea(tab_calib)
scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scrollarea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scrollarea.setWidgetResizable(True)
exec("self.scrollarea_tab_" + str(t_index) + " = QScrollArea(self.tab_calib_" + str(t_index) + ")")
eval("self.scrollarea_tab_" + str(t_index) + ".setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)")
eval("self.scrollarea_tab_" + str(t_index) + ".setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)")
eval("self.scrollarea_tab_" + str(t_index) + ".setWidgetResizable(True)")
verticalLayout.addWidget(scrollarea)
gridLayout = QGridLayout(scrollarea)
eval("self.verticalLayout_tab_" + str(t_index) + ".addWidget(self.scrollarea_tab_" + str(t_index) + ")")
exec("self.gridLayout_tab_" + str(t_index) + " = QGridLayout(self.scrollarea_tab_" + str(t_index) + ")")
if [*self.data_ABS.values()][t_index].columns.any():
exec("self.label_freq_" + str(t_index) + " = QLabel('" + str([*self.data_ABS.values()][t_index].columns[0]) + " (MHz)')")
exec("self.label_kt_" + str(t_index) + " = QLabel('" + str([*self.data_ABS.values()][t_index].columns[1]) + " (V.m<sup>1.5</sup>)')")
label_freq = QLabel(
f"{[*self.data_ABS.values()][t_index].columns[0]} (MHz)"
)
label_kt = QLabel(
f"{[*self.data_ABS.values()][t_index].columns[1]} "
+ "(V.m<sup>1.5</sup>)"
)
else:
exec("self.label_freq_" + str(t_index) + " = QLabel('Frequency (MHz)')")
exec("self.label_kt_" + str(t_index) + " = QLabel('kt (V.m<sup>1.5</sup>)')")
eval("self.gridLayout_tab_" + str(t_index) + ".addWidget(self.label_freq_" + str(t_index) + ", 0, 0, 1, 1, Qt.AlignCenter)")
eval("self.gridLayout_tab_" + str(t_index) + ".addWidget(self.label_kt_" + str(t_index) + ", 0, 1, 1, 1, Qt.AlignCenter)")
label_freq = QLabel('Frequency (MHz)')
label_kt = QLabel('kt (V.m<sup>1.5</sup>)')
gridLayout.addWidget(
label_freq, 0, 0, 1, 1, Qt.AlignCenter
)
gridLayout.addWidget(
label_kt, 0, 1, 1, 1, Qt.AlignCenter
)
for x in range(self.data_ABS[t_value].shape[0]):
exec("self.label_freq_" + str(x) + "_ABS_" + str(t_index) + " = QLabel()")
# print(eval("self.label_freq_" + str(x) + "_ABS_" + str(t_index) + ".setText('" + str(self.data_ABS[t_value].iloc[x][0]*1e-6) + " MHz')"))
eval("self.label_freq_" + str(x) + "_ABS_" + str(t_index) + ".setText('" + str(self.data_ABS[t_value].iloc[x][0]*1e-6) + " (MHz)')")
# eval("self.label_freq_" + str(x) + "_ABS_" + str(t_index) + ".setDisabled(True)")
eval("self.gridLayout_tab_" + str(t_index) + ".addWidget(self.label_freq_" + str(x) + "_ABS_" + str(t_index) +
", " + str(x + 1) + ", 0, 1, 1,Qt.AlignCenter)")
exec("self.label_kt_" + str(x) + "_ABS_" + str(t_index) + " = QLabel()")
exec("self.label_kt_" + str(x) + "_ABS_" + str(t_index) + ".setText('" + str(self.data_ABS[t_value].iloc[x][1]) + "V.m<sup>1.5</sup>')")
eval("self.label_kt_" + str(x) + "_ABS_" + str(t_index) + ".setStyleSheet('border: 1px solid black;')")
eval("self.gridLayout_tab_" + str(t_index) + ".addWidget(self.label_kt_" + str(x) + "_ABS_" + str(t_index) +
", " + str(x+1) + ", 1, 1, 1, Qt.AlignCenter)")
label_freq_ABS = QLabel()
label_freq_ABS.setText(
f"{self.data_ABS[t_value].iloc[x][0]*1e-6}" + "(MHz)"
)
gridLayout.addWidget(
label_freq_ABS, x + 1, 0, 1, 1,Qt.AlignCenter
)
label_kt_ABS = QLabel()
label_kt_ABS.setText(
f"{self.data_ABS[t_value].iloc[x][1]} V.m<sup>1.5</sup>"
)
label_kt_ABS.setStyleSheet('border: 1px solid black;')
gridLayout.addWidget(
label_kt_ABS, x + 1 , 1, 1, 1, Qt.AlignCenter
)

View File

@ -551,7 +551,11 @@ class ReadTableForOpen:
FROM SedimentsFile
'''
data = self.execute(query)[0]
res = self.execute(query)
if len(res) == 0:
return
data = res[0]
stg.path_fine = data[0]
stg.filename_fine = data[1]
@ -594,6 +598,9 @@ class ReadTableForOpen:
stg.frac_vol_sand = []
stg.frac_vol_sand_cumul = []
if len(data) == 0:
return
for d in data:
stg.sample_fine.append((d[0], d[1]))
stg.distance_from_bank_fine.append(d[2])
@ -642,6 +649,9 @@ class ReadTableForOpen:
'''
data = self.execute(query)
if len(data) == 0:
return
it = iter(data[0])
stg.calib_acoustic_data = next(it)
@ -708,6 +718,9 @@ class ReadTableForOpen:
'''
data = self.execute(query)
if len(data) == 0:
return
it = iter(data[0])
stg.path_calibration_file = next(it)

View File

@ -3,7 +3,9 @@
AcouSed for **Acou**stic Backscattering for Concentration of Suspended **Sed**iments in Rivers is a software developped by INRAE, in collaboation with CNR.
<p>
<img src="logos/AcouSed.png" align="center" width=20% height=20% >
<a href="https://riverhydraulics.riverly.inrae.fr/outils/logiciels-pour-la-mesure/acoused">
<img src="logos/AcouSed.png" align="center" width=200px>
</a>
</p>
It is divided in six tabs:
@ -17,7 +19,7 @@ It is divided in six tabs:
### Standalone software
AcouSed can be launched with python installation. An executable is available on [River Hydraulics](https://riverhydraulics.riverly.inrae.fr/outils/logiciels-pour-la-mesure/acoused) teams website.
AcouSed can be launched with python installation. An executable is available on [River Hydraulics](https://riverhydraulics.riverly.inrae.fr/outils/logiciels-pour-la-mesure/acoused) teams website.
The user needs to download the folder "acoused-packaging" including :
- icons and logos folder
- _internal folder (python packages)
@ -25,7 +27,8 @@ The user needs to download the folder "acoused-packaging" including :
- calibration constant file
- documentation
Acoused.exe file must be launched from this folder.
Acoused.exe file must be launched from this folder.
Test data can be dowloaded from the [INRAE nextcloud](https://nextcloud.inrae.fr/s/3zZdieztrx7nwYa)
### Python environment
@ -40,7 +43,7 @@ Acoused.
You can use Pypi to get correct software environment and run the
program.
```shell
```bat
python -m venv env
env\Scripts\activate.bat
python -m pip install -U -r ..\virtualenv\requirements.txt
@ -91,42 +94,42 @@ If you have any questions or suggestions, please contact us to celine.berni@inra
## Acknowledgment
This study was conducted within the [Rhône Sediment Observatory](https://observatoire-sediments-rhone.fr/) (OSR), a multi-partner research program funded through the Plan Rhône by the European Regional Development Fund (ERDF), Agence de lEau RMC, CNR, EDF and three regional councils (Auvergne-Rhône-Alpes, PACA and Occitanie).
This study was conducted within the [Rhône Sediment Observatory](https://observatoire-sediments-rhone.fr/) (OSR), a multi-partner research program funded through the Plan Rhône by the European Regional Development Fund (ERDF), Agence de lEau RMC, CNR, EDF and three regional councils (Auvergne-Rhône-Alpes, PACA and Occitanie).
<p>
<img src="logos/OSR.png" align="center" width=10% height=10% >
<a href="https://observatoire-sediments-rhone.fr/">
<img src="logos/OSR.png" align="center" width=200px>
</a>
</p>
## Industrial partners
[CNR](https://www.cnr.tm.fr/)
<p>
<img src="logos/CNR.png" align="center" width=10% height=10% >
</p>
<a href="https://www.cnr.tm.fr/">
<img src="logos/CNR.png" align="center" width=200px>
</a>
[UBERTONE](https://ubertone.com/)
<a href="https://ubertone.com/">
<img src="logos/Ubertone.jpg" align="center" width=200px>
</a>
<p>
<img src="logos/Ubertone.jpeg" align="center" width=10% height=10% >
</p>
[EDF](https://www.edf.fr/hydraulique-isere-drome)
<p>
<img src="logos/EDF.png" align="center" width=10% height=10% >
<a href="https://www.edf.fr/hydraulique-isere-drome">
<img src="logos/EDF.png" align="center" width=200px>
</a>
</p>
## License
<p>
<a href="https://www.inrae.fr/">
<img src="logos/BlocMarque-INRAE-Inter.jpg" align="center" width=200px>
</a>
</p>
AcouSed
Copyright (C) 2024-2025 - INRAE
<p>
<img src="logos/BlocMarque-INRAE-Inter.jpg" align="center" width=10% height=10% >
</p>
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.

Binary file not shown.

Binary file not shown.

View File

@ -27,20 +27,24 @@ import os
class Logos():
def __init__(self):
self.logo_AcouSed = os.path.join('logos', "AcouSed.png")
def path_logo(icon):
return os.path.join(
os.path.dirname(__file__), "..", "logos", icon
)
self.logo_INRAE = os.path.join('logos', "BlocMarque-INRAE-Inter.jpg")
self.logo_AcouSed = path_logo("AcouSed.png")
self.logo_OSR = os.path.join('logos', "OSR.png")
self.logo_europe = os.path.join('logos', "Europe.png")
self.logo_saone_rhone = os.path.join('logos', "plan_Rhone_Saone.png")
self.logo_carnot = os.path.join('logos', "Carnot_EE.png")
self.logo_INRAE = path_logo("BlocMarque-INRAE-Inter.jpg")
self.logo_CNR = os.path.join('logos', "CNR.png")
self.logo_EDF = os.path.join('logos', "EDF.png")
self.logo_Ubertone = os.path.join('logos', "Ubertone.jpg")
self.logo_OSR = path_logo("OSR.png")
self.logo_europe = path_logo("Europe.png")
self.logo_saone_rhone = path_logo("plan_Rhone_Saone.png")
self.logo_carnot = path_logo("Carnot_EE.png")
self.logo_CNR = path_logo("CNR.png")
self.logo_EDF = path_logo("EDF.png")
self.logo_Ubertone = path_logo("Ubertone.jpg")
logos_inst = Logos()
@ -291,7 +295,7 @@ class Authors(QDialog):
self.gridLayout.addWidget(self.label_brahim, 4, 0, 1, 1)
self.label_PA = QLabel()
self.label_PA.setText("TECC company (< a href = https://parouby.fr/ > https://parouby.fr/ </a>) was involved in 2025 to improve program architecture.")
self.label_PA.setText("TECC company (< a href = https://parouby.fr/ > https://parouby.fr/ </a>) was involved in 2025 to debugging the program.")
self.gridLayout.addWidget(self.label_PA, 5, 0, 1, 1)

View File

@ -718,7 +718,7 @@ class AcousticDataTab(QWidget):
def _setup_icons(self):
def path_icon(icon):
return os.path.join(
"icons", icon
os.path.dirname(__file__), "..", "icons", icon
)
self.icon_folder = QIcon(path_icon("folder.png"))
@ -2502,6 +2502,7 @@ class AcousticDataTab(QWidget):
if self.fig_BS is not None:
self.fig_BS.clear()
plt.close(self.fig_BS)
self.fig_BS, self.axis_BS = plt.subplots(
nrows=stg.freq[file_id].shape[0],
@ -2682,6 +2683,7 @@ class AcousticDataTab(QWidget):
# --- Figure to plot profiles ---
if self.fig_profile is not None:
self.fig_profile.clear()
plt.close(self.fig_profile)
self.fig_profile, self.axis_profile = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.canvas_plot_profile = FigureCanvas(self.fig_profile)

View File

@ -21,6 +21,8 @@
# -*- coding: utf-8 -*-
import os
import gc
import time
import logging
import numpy as np
import pandas as pd
@ -69,7 +71,9 @@ class AcousticInversionTab(QWidget):
self._setup_connections()
def _path_icon(self, icon):
return os.path.join("icons", icon)
return os.path.join(
os.path.dirname(__file__), "..", "icons", icon
)
def _setup_icons(self):
self.icon_folder = QIcon(self._path_icon("folder.png"))
@ -406,7 +410,7 @@ class AcousticInversionTab(QWidget):
self.pushbutton_run_inversion\
.clicked.connect(self.function_run_inversion)
self.pushbutton_save_result\
.clicked.connect(self.save_result_in_excel_file)
.clicked.connect(self.save_result)
self.pushbutton_left_to_begin_fine\
.clicked.connect(self.slider_profile_number_to_begin_fine)
@ -599,6 +603,7 @@ class AcousticInversionTab(QWidget):
if self.figure_SSC_fine is not None:
self.figure_SSC_fine.clear()
plt.close(fig=self.figure_SSC_fine)
self.figure_SSC_fine, self.axis_SSC_fine = plt.subplots(
nrows=1, ncols=1, layout="constrained"
@ -727,6 +732,7 @@ class AcousticInversionTab(QWidget):
if self.figure_vertical_profile_SSC_fine is not None:
self.figure_vertical_profile_SSC_fine.clear()
plt.close(fig=self.figure_vertical_profile_SSC_fine)
fig, ax = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.figure_vertical_profile_SSC_fine = fig
@ -1011,6 +1017,7 @@ class AcousticInversionTab(QWidget):
else:
if self.figure_measured_vs_inverted_fine is not None:
self.figure_measured_vs_inverted_fine.clear()
plt.close(fig=self.figure_measured_vs_inverted_fine)
fig, ax = plt.subplots(nrows=1, ncols=1, layout="constrained")
@ -1029,7 +1036,7 @@ class AcousticInversionTab(QWidget):
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_fine\
.addWidget(self.canvas_inverted_vs_measured_SSC_fine)
if stg.SSC_fine[data_id].shape == (0,):
if stg.SSC_fine[data_id].shape != (0,):
fine_id = self.combobox_fine_sample_choice.currentData()
self.fine_sample_to_plot = [
@ -1154,6 +1161,7 @@ class AcousticInversionTab(QWidget):
else:
if self.figure_SSC_sand is not None:
self.figure_SSC_sand.clear()
plt.close(fig=self.figure_SSC_sand)
self.figure_SSC_sand, self.axis_SSC_sand = plt.subplots(
nrows=1, ncols=1, layout="constrained"
@ -1281,6 +1289,7 @@ class AcousticInversionTab(QWidget):
if self.figure_vertical_profile_SSC_sand is not None:
self.figure_vertical_profile_SSC_sand.clear()
plt.close(fig=self.figure_vertical_profile_SSC_sand)
fig, ax = plt.subplots(
nrows=1, ncols=1, layout="constrained"
@ -1543,142 +1552,168 @@ class AcousticInversionTab(QWidget):
)
def plot_measured_vs_inverted_SSC_sand(self):
data_id = self.combobox_acoustic_data_choice.currentIndex()
if self.combobox_acoustic_data_choice.count() > 0:
if self.combobox_acoustic_data_choice.count() <= 0:
return
if stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()].shape == (0,):
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.removeWidget(self.toolbar_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.removeWidget(self.canvas_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand.removeWidget(
self.toolbar_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand.removeWidget(
self.canvas_inverted_vs_measured_SSC_sand)
if stg.SSC_sand[data_id].shape == (0,):
self.canvas_inverted_vs_measured_SSC_sand = FigureCanvas()
self.toolbar_inverted_vs_measured_SSC_sand = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_sand, self
)
else:
if self.figure_measured_vs_inverted_sand is not None:
self.figure_measured_vs_inverted_sand.clear()
plt.close(fig=self.figure_measured_vs_inverted_sand)
self.canvas_inverted_vs_measured_SSC_sand = FigureCanvas()
self.toolbar_inverted_vs_measured_SSC_sand = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_sand, self)
fig, ax = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand.addWidget(
self.toolbar_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand.addWidget(
self.canvas_inverted_vs_measured_SSC_sand)
self.figure_measured_vs_inverted_sand = fig
self.axis_measured_vs_inverted_sand = ax
else:
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand.removeWidget(
self.toolbar_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand.removeWidget(
self.canvas_inverted_vs_measured_SSC_sand)
if self.figure_measured_vs_inverted_sand is not None:
self.figure_measured_vs_inverted_sand.clear()
fig, ax = plt.subplots(nrows=1, ncols=1, layout="constrained")
self.figure_measured_vs_inverted_sand = fig
self.axis_measured_vs_inverted_sand = ax
self.canvas_inverted_vs_measured_SSC_sand = FigureCanvas(self.figure_measured_vs_inverted_sand)
self.toolbar_inverted_vs_measured_SSC_sand = NavigationToolBar(self.canvas_inverted_vs_measured_SSC_sand, self)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand.addWidget(
self.toolbar_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand.addWidget(
self.canvas_inverted_vs_measured_SSC_sand)
self.sand_sample_to_plot = [int(f[1:]) - 1 for f in self.combobox_sand_sample_choice.currentData()]
if self.sand_sample_to_plot:
self.axis_measured_vs_inverted_sand.plot(
[stg.Ctot_sand[k] for k in self.sand_sample_to_plot],
[stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][
stg.sand_sample_position[k][1],
stg.sand_sample_position[k][0]] for k in
self.sand_sample_to_plot],
ls=" ", marker='o', ms=5, mec='black', mfc="black"
)
self.axis_measured_vs_inverted_sand.plot(
[0, np.nanmax([np.nanmax([stg.Ctot_sand[c] for c in self.sand_sample_to_plot]),
np.nanmax([stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]]
for i in self.sand_sample_to_plot])]) + 1],
[0, np.nanmax([np.nanmax([stg.Ctot_sand[c] for c in self.sand_sample_to_plot]),
np.nanmax([stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]]
for i in self.sand_sample_to_plot])]) + 1],
ls="solid", linewidth=1, color="k"
)
# --- Display sample label on plot ---
for i in self.sand_sample_to_plot:
self.axis_measured_vs_inverted_sand.text(
stg.Ctot_sand[i],
stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]],
stg.sample_sand[i][0],
fontstyle="normal", fontweight="light", fontsize=10)
else:
self.axis_measured_vs_inverted_sand.plot(
[stg.Ctot_sand[k] for k in range(len(stg.sample_sand))],
[stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][
stg.sand_sample_position[k][1],
stg.sand_sample_position[k][0]] for k in
range(len(stg.sample_sand))],
ls=" ", marker='o', ms=5, mec='black', mfc="black"
)
self.axis_measured_vs_inverted_sand.plot(
[0, np.nanmax([np.nanmax([stg.Ctot_sand[c] for c in range(len(stg.sample_sand))]),
np.nanmax([stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]]
for i in range(len(stg.sample_sand))])]) + 1],
[0, np.nanmax([np.nanmax([stg.Ctot_sand[c] for c in range(len(stg.sample_sand))]),
np.nanmax([stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]]
for i in range(len(stg.sample_sand))])]) + 1],
ls="solid", linewidth=1, color="k"
)
for j in range(len(stg.sample_sand)):
self.axis_measured_vs_inverted_sand.text(
stg.Ctot_sand[j],
stg.SSC_sand[self.combobox_acoustic_data_choice.currentIndex()][
stg.sand_sample_position[j][1],
stg.sand_sample_position[j][0]],
stg.sample_sand[j][0],
fontstyle="normal", fontweight="light", fontsize=10)
self.axis_measured_vs_inverted_sand.set_xlabel("Measured SSC sand (g/L)")
self.axis_measured_vs_inverted_sand.set_ylabel("Inverted SSC sand (g/L)")
self.figure_measured_vs_inverted_sand.canvas.draw_idle()
def save_result_in_excel_file(self):
if self.combobox_acoustic_data_choice.count() > 0:
name, _ = QFileDialog.getSaveFileName(
caption="Save As - Inversion results",
directory="",
filter="Excel Files (*.xlsx)",
options=QFileDialog.DontUseNativeDialog
self.canvas_inverted_vs_measured_SSC_sand = FigureCanvas(
self.figure_measured_vs_inverted_sand
)
self.toolbar_inverted_vs_measured_SSC_sand = NavigationToolBar(
self.canvas_inverted_vs_measured_SSC_sand, self
)
if name == '':
return
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.addWidget(self.toolbar_inverted_vs_measured_SSC_sand)
self.verticalLayout_groupbox_plot_measured_vs_inverted_SSC_sand\
.addWidget(self.canvas_inverted_vs_measured_SSC_sand)
dirname = os.path.dirname(name)
filename = os.path.basename(name)
os.chdir(dirname)
if stg.SSC_sand[data_id].shape != (0,):
sand_id = self.combobox_sand_sample_choice.currentData()
results = []
self.sand_sample_to_plot = [
int(f[1:]) - 1 for f in sand_id
]
if self.sand_sample_to_plot:
sand_range = lambda : self.sand_sample_to_plot
else:
sand_range = lambda : range(len(stg.sample_sand))
self.axis_measured_vs_inverted_sand.plot(
[stg.Ctot_sand[k] for k in sand_range()],
[
stg.SSC_sand[data_id][
stg.sand_sample_position[k][1],
stg.sand_sample_position[k][0]
] for k in sand_range()
],
ls=" ", marker='o', ms=5, mec='black', mfc="black"
)
self.axis_measured_vs_inverted_sand.plot(
[
0, np.nanmax(
[
np.nanmax(
[stg.Ctot_sand[c] for c in sand_range()]
),
np.nanmax(
[
stg.SSC_sand[data_id][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]
] for i in sand_range()
]
)
]
) + 1
],
[
0, np.nanmax(
[
np.nanmax(
[stg.Ctot_sand[c] for c in sand_range()]
),
np.nanmax(
[
stg.SSC_sand[data_id][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]
] for i in sand_range()
]
)
]
) + 1
],
ls="solid", linewidth=1, color="k"
)
# --- Display sample label on plot ---
for i in sand_range():
self.axis_measured_vs_inverted_sand.text(
stg.Ctot_sand[i],
stg.SSC_sand[data_id][
stg.sand_sample_position[i][1],
stg.sand_sample_position[i][0]
],
stg.sample_sand[i][0],
fontstyle="normal", fontweight="light", fontsize=10
)
self.axis_measured_vs_inverted_sand\
.set_xlabel("Measured SSC sand (g/L)")
self.axis_measured_vs_inverted_sand\
.set_ylabel("Inverted SSC sand (g/L)")
self.figure_measured_vs_inverted_sand.canvas.draw_idle()
def save_result(self):
if self.combobox_acoustic_data_choice.count() <= 0:
return
file_type = {
"CSV Files (*.csv)": (self.save_result_in_csv_file, ".csv"),
"Excel Files (*.xlsx)": (self.save_result_in_excel_file, ".xlsx"),
# "LibreOffice Calc Files (*.ods)": (self.save_result_in_excel_file, ".ods"),
}
name, type_ext = QFileDialog.getSaveFileName(
caption="Save As - Inversion results",
directory="",
filter=";;".join(file_type),
options=QFileDialog.DontUseNativeDialog
)
if name == '':
return
dirname = os.path.dirname(name)
filename = os.path.basename(name)
_, ext = os.path.splitext(filename)
os.chdir(dirname)
fun, t_ext = file_type[type_ext]
if t_ext not in filename:
filename += t_ext
t = time.time()
logger.info(f"Export results to {os.path.join(dirname, filename)}")
fun(dirname, filename)
logger.info(f"... export done in {time.time() - t:.4f} sec")
def save_result_in_excel_file(self, dirname, filename):
if ".ods" in filename:
engine = "odf"
else:
engine = 'xlsxwriter'
with pd.ExcelWriter(
os.path.join(dirname, filename),
engine=engine
) as writer:
for k in range(self.combobox_acoustic_data_choice.count()):
if stg.time_cross_section[k].shape != (0,):
time_data = stg.time_cross_section
@ -1703,41 +1738,99 @@ class AcousticInversionTab(QWidget):
for j in range(depth_data[k].shape[1]):
r_id = i * depth_data[k].shape[1] + j
r[r_id] = (
depth_data[k][
int(stg.frequency_for_inversion[1]), j
]
)
r[r_id] = depth_data[k][
int(stg.frequency_for_inversion[1]), j
]
if stg.SSC_fine[k].shape == (0,):
stg.SSC_fine[k] = np.zeros(r.shape[0])
if stg.SSC_sand[k].shape == (0,):
stg.SSC_sand[k] = np.zeros(r.shape[0])
results.append(
pd.DataFrame(
{
'Time (sec)': list(t),
'Depth (m)': list(r),
'SSC_fine (g/L)': list(
stg.SSC_fine[k].reshape(t.shape[0])
),
'SSC_sand (g/L)': list(
stg.SSC_sand[k].reshape(t.shape[0])
),
}
)
result = pd.DataFrame(
{
'Time (sec)': list(t),
'Depth (m)': list(r),
'SSC_fine (g/L)': list(
stg.SSC_fine[k].reshape(t.shape[0])
),
'SSC_sand (g/L)': list(
stg.SSC_sand[k].reshape(t.shape[0])
),
}
)
if os.path.splitext(filename)[1] != ".xlsx":
filename += ".xlsx"
gc.collect() # Force garbade collection
with pd.ExcelWriter(
os.path.join(dirname, filename)
) as writer:
for k in range(self.combobox_acoustic_data_choice.count()):
results[k].to_excel(
writer, index=False,
engine='xlsxwriter', na_rep='NA',
sheet_name=stg.data_preprocessed[k],
result.to_excel(
writer, index=False, na_rep='NA',
sheet_name=stg.data_preprocessed[k],
)
def save_result_in_csv_file(self, dirname, filename):
d_id = []
t = []
r = []
ssc_fine = []
ssc_sand = []
for k in range(self.combobox_acoustic_data_choice.count()):
if stg.time_cross_section[k].shape != (0,):
time_data = stg.time_cross_section
else:
time_data = stg.time
if stg.depth_cross_section[k].shape != (0,):
depth_data = stg.depth_cross_section
else:
depth_data = stg.depth
time_shape = time_data[k].shape[1]
depth_shape = depth_data[k].shape[1]
d_id += np.repeat(k, depth_shape * time_shape).tolist()
tmp_t = np.repeat(
time_data[k][stg.frequency_for_inversion[1]],
depth_shape
)
tmp_r = np.zeros(
depth_shape * time_shape
)
for i in range(time_shape):
for j in range(depth_shape):
r_id = i * depth_shape + j
tmp_r[r_id] = (
depth_data[k][
int(stg.frequency_for_inversion[1]), j
]
)
t += tmp_t.tolist()
r += tmp_r.tolist()
if stg.SSC_fine[k].shape == (0,):
stg.SSC_fine[k] = np.zeros(tmp_r.shape[0])
if stg.SSC_sand[k].shape == (0,):
stg.SSC_sand[k] = np.zeros(tmp_r.shape[0])
ssc_fine += stg.SSC_fine[k].reshape(tmp_r.shape[0]).tolist()
ssc_sand += stg.SSC_sand[k].reshape(tmp_r.shape[0]).tolist()
results = pd.DataFrame(
{
'acoustic data': d_id,
'Time (sec)': t,
'Depth (m)': r,
'SSC_fine (g/L)': ssc_fine,
'SSC_sand (g/L)': ssc_sand,
}
)
results.to_csv(
os.path.join(dirname, filename),
index=False
)

View File

@ -132,28 +132,33 @@ class Ui_MainWindow(object):
self.toolBar.setObjectName("toolBar")
self.mainwindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
def path_icon(icon):
return os.path.join(
os.path.dirname(__file__), "..", "icons", icon
)
self.actionOpen = QtWidgets.QAction(self.mainwindow)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap("icons/icon_folder.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon1.addPixmap(QtGui.QPixmap(path_icon("icon_folder.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionOpen.setIcon(icon1)
self.actionOpen.setObjectName("actionOpen")
self.actionSave = QtWidgets.QAction(self.mainwindow)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap("icons/save.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon2.addPixmap(QtGui.QPixmap(path_icon("save.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionSave.setIcon(icon2)
self.actionSave.setObjectName("actionSave")
self.actionEnglish = QtWidgets.QAction(self.mainwindow)
icon6 = QtGui.QIcon()
icon6.addPixmap(QtGui.QPixmap("icons/en.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon6.addPixmap(QtGui.QPixmap(path_icon("en.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionEnglish.setIcon(icon6)
self.actionEnglish.setObjectName("actionEnglish")
self.actionEnglish.setEnabled(False)
self.actionFrench = QtWidgets.QAction(self.mainwindow)
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap("icons/fr.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon7.addPixmap(QtGui.QPixmap(path_icon("fr.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.actionFrench.setIcon(icon7)
self.actionFrench.setObjectName("actionFrench")
self.actionFrench.setEnabled(False)

View File

@ -20,7 +20,9 @@ class NoteTab(QWidget):
''' This class generates a enhanced notepad in Note Tab '''
def _path_icon(self, icon):
return os.path.join("icons", icon)
return os.path.join(
os.path.dirname(__file__), "..", "icons", icon
)
def __init__(self, widget_tab):
super().__init__()

View File

@ -1,7 +1,10 @@
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtWidgets import (QWidget, QLabel, QHBoxLayout, QVBoxLayout, QApplication, QMainWindow, QGridLayout,
QDialog, QFrame, QTabWidget, QScrollArea)
from PyQt5.QtWidgets import (
QWidget, QLabel, QHBoxLayout, QVBoxLayout, QApplication,
QMainWindow, QGridLayout, QDialog, QFrame, QTabWidget,
QScrollArea
)
import numpy as np
@ -14,9 +17,7 @@ import settings as stg
class PlotNoiseWindow(QDialog):
def __init__(self, parent=None):
super(PlotNoiseWindow, self).__init__(parent)
self.setGeometry(400, 200, 700, 500)
@ -29,65 +30,60 @@ class PlotNoiseWindow(QDialog):
self.tab = QTabWidget()
self.verticalLayout_Main.addWidget(self.tab)
self.tabs = []
for i in range(len(stg.filename_BS_raw_data)):
self.tabs.append(QWidget())
exec("self.tab" + str(i) + "= QWidget()")
exec("self.tab.addTab(self.tab" + str(i) + ", stg.filename_BS_raw_data[" + str(i) + "])")
self.tab.addTab(self.tabs[i], stg.filename_BS_raw_data[i])
exec("self.verticalLayout_tab" + str(i) + "= QVBoxLayout()")
exec("self.tab" + str(i) + ".setLayout(self.verticalLayout_tab" + str(i) + ")")
verticalLayout = QVBoxLayout()
self.tabs[i].setLayout(verticalLayout)
exec("self.fig" + str(i) + ", self.ax" + str(i) +
"= plt.subplots(nrows=stg.freq[" + str(i) + "].shape[0], ncols=1, layout='constrained')")
fig, ax = plt.subplots(
nrows=stg.freq[i].shape[0], ncols=1, layout='constrained'
)
if stg.BS_noise_raw_data[i].shape != (0,):
for freq_ind, freq_val in enumerate(stg.freq[i]):
eval("self.ax" + str(i) + "[" + str(freq_ind) + "]" + ".cla()")
ax[freq_ind].cla()
val_min = np.nanmin(stg.BS_noise_raw_data[i][freq_ind, :, :])
val_max = np.nanmax(stg.BS_noise_raw_data[i][freq_ind, :, :])
if val_min == val_max:
exec("pcm = self.ax" + str(i) + "[" + str(freq_ind) + "]" + ".pcolormesh(" +
"stg.time_noise[" + str(i) + "][" + str(freq_ind) + ", :]," +
"-stg.depth_noise[" + str(i) + "][" + str(freq_ind) + ", :]," +
"stg.BS_noise_raw_data[" + str(i) + "][" + str(freq_ind) + ", :, :]," +
"cmap='hsv')")
else:
if val_min != val_max:
val_min = 0
val_max = 1e-5
exec("pcm = self.ax" + str(i) + "[" + str(freq_ind) + "]" + ".pcolormesh(" +
"stg.time_noise[" + str(i) + "][" + str(freq_ind) + ", :]," +
"-stg.depth_noise[" + str(i) + "][" + str(freq_ind) + ", :]," +
"stg.BS_noise_raw_data[" + str(i) + "][" + str(freq_ind) + ", :, :]," +
"cmap='hsv')")
eval("self.ax" + str(i) + "[" + str(freq_ind) + "]" + ".text(1, .70, stg.freq_text[" + str(i) +
"][" + str(freq_ind) + "]," +
"fontsize=10, fontweight='bold', fontname='DejaVu Sans', c='black', alpha=0.5," +
"horizontalalignment='right', verticalalignment='bottom'," +
"transform=self.ax" + str(i) + "[" + str(freq_ind) + "].transAxes)")
pcm = ax[freq_ind].pcolormesh(
stg.time_noise[i][freq_ind, :],
-stg.depth_noise[i][freq_ind, :],
stg.BS_noise_raw_data[i][freq_ind, :, :],
cmap='hsv'
)
exec("self.fig" + str(i) + ".supxlabel('Time (sec)', fontsize=10)")
exec("self.fig" + str(i) + ".supylabel('Depth (m)', fontsize=10)")
ax[freq_ind].text(
1, .70, stg.freq_text[i][freq_ind],
fontsize=10, fontweight='bold',
fontname='DejaVu Sans', c='black', alpha=0.5,
horizontalalignment='right', verticalalignment='bottom',
transform=ax[freq_ind].transAxes
)
exec("cbar = self.fig" + str(i) + ".colorbar(pcm, ax=self.ax" + str(i) + "[:] ," +
"shrink=1, location='right')")
eval("cbar.set_label(label='Noise signal (V)', rotation=270, labelpad=8)")
fig.supxlabel('Time (sec)', fontsize=10)
fig.supylabel('Depth (m)', fontsize=10)
exec("self.fig" + str(i) + ".canvas.draw_idle()")
cbar = fig.colorbar(
pcm, ax=ax[:], shrink=1, location='right'
)
cbar.set_label(label='Noise signal (V)', rotation=270, labelpad=8)
fig.canvas.draw_idle()
else:
canvas = FigureCanvas(fig)
toolbar = NavigationToolBar(canvas, self)
pass
scroll = QScrollArea()
scroll.setWidget(canvas)
exec("self.canvas" + str(i) + "= FigureCanvas(self.fig" + str(i) + ")")
exec("self.toolbar" + str(i) + "= NavigationToolBar(self.canvas" + str(i) + ", self)")
exec("self.scroll" + str(i) + "= QScrollArea()")
exec("self.scroll" + str(i) + ".setWidget(self.canvas" + str(i) + ")")
exec("self.verticalLayout_tab" + str(i) + ".addWidget(self.toolbar" + str(i) + ")")
exec("self.verticalLayout_tab" + str(i) + ".addWidget(self.scroll" + str(i) + ")")
verticalLayout.addWidget(toolbar)
verticalLayout.addWidget(scroll)

View File

@ -63,7 +63,9 @@ class SampleDataTab(QWidget):
def __init__(self, widget_tab):
super().__init__()
icon_folder = QIcon(os.path.join("icons", "folder.png"))
icon_folder = QIcon(os.path.join(
os.path.dirname(__file__), "..", "icons", "folder.png"
))
self._setup_attrs()
### --- General layout of widgets ---
@ -774,6 +776,9 @@ class SampleDataTab(QWidget):
self.combobox_acoustic_data.showPopup()
def fill_comboboxes_and_plot_transect(self):
if len(stg.acoustic_data) == 0:
return
self.combobox_acoustic_data.clear()
for n, m in enumerate(stg.noise_method):
if stg.noise_method[n] == 0:
@ -797,6 +802,7 @@ class SampleDataTab(QWidget):
if self.figure_plot_sample_position_on_transect is not None:
self.figure_plot_sample_position_on_transect.clear()
plt.close(self.figure_plot_sample_position_on_transect)
fig, axis = plt.subplots(nrows=1, ncols=1, layout="constrained")
@ -1425,6 +1431,7 @@ class SampleDataTab(QWidget):
if self.figure_total_concentration is not None:
self.figure_total_concentration.clear()
plt.close(self.figure_total_concentration)
self.figure_total_concentration, self.axis_total_concentration \
= plt.subplots(nrows=1, ncols=1, layout="constrained")
@ -1713,6 +1720,7 @@ class SampleDataTab(QWidget):
if self.figure_plot_PSD is not None:
self.figure_plot_PSD.clear()
plt.close(self.figure_plot_PSD)
self.figure_plot_PSD, self.axis_plot_PSD \
= plt.subplots(nrows=1, ncols=2, layout="constrained")

View File

@ -1040,6 +1040,7 @@ class SedimentCalibrationTab(QWidget):
if self.fig_BS is not None:
self.fig_BS.clear()
plt.close(self.fig_BS)
self.fig_BS, self.axis_BS = plt.subplots(
nrows=1, ncols=1, sharex=True, sharey=False,
@ -1407,6 +1408,7 @@ class SedimentCalibrationTab(QWidget):
if self.fig_Mfine is not None:
self.fig_Mfine.clear()
plt.close(self.fig_Mfine)
self.fig_Mfine, self.ax_Mfine = plt.subplots(1, 1, layout="constrained")
self.canvas_Mfine = FigureCanvas(self.fig_Mfine)
@ -1588,7 +1590,6 @@ class SedimentCalibrationTab(QWidget):
self.animaiton_groupbox_compute.start()
def import_calibration_file(self):
if self.combobox_acoustic_data_choice.count() == 0:
msgBox = QMessageBox()
msgBox.setWindowTitle("Calibration import error")
@ -1600,35 +1601,81 @@ class SedimentCalibrationTab(QWidget):
msgBox.setText("Update data before importing calibration")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
return
path = ""
if stg.path_calibration_file:
path = stg.path_calibration_file
elif self.combobox_acoustic_data_choice.count() > 0:
path = stg.path_BS_raw_data[-1]
file_type = {
"Calibration Files (*.csv *.ods *.xls *.xlsx)":
self.read_calibration_dispatch,
"CSV Files (*.csv)": self.read_calibration_csv,
"Excel Files (*.xlsx *.xls)": self.read_calibration_excel,
"LibreOffice Calc Files (*.ods)": self.read_calibration_ods,
}
filename, ftype = QFileDialog.getOpenFileName(
self, "Open calibration file", path,
";;".join(file_type),
options=QFileDialog.DontUseNativeDialog
)
if filename == '':
return
dir_name = os.path.dirname(filename)
name = os.path.basename(filename)
stg.path_calibration_file = dir_name
stg.filename_calibration_file = name
self.lineEdit_import_calibration.clear()
self.lineEdit_import_calibration.setText(name)
self.lineEdit_import_calibration.setToolTip(dir_name)
self.compute_depth_2D()
try:
parser = file_type[ftype]
data = parser(filename)
self.fill_calibration_select_frequencies(data)
self.fill_calibration_parameters(data)
except Exception as e:
logger.warning(f"read calibration failed: {str(e)}")
def read_calibration_dispatch(self, filename):
if ".csv" in filename:
return self.read_calibration_csv(filename)
elif ".ods" in filename:
return self.read_calibration_ods(filename)
else:
return self.read_calibration_excel(filename)
filename = QFileDialog.getOpenFileName(
self, "Open calibration",
[
stg.path_calibration_file
if stg.path_calibration_file
else stg.path_BS_raw_data[-1]
if self.combobox_acoustic_data_choice.count() > 0
else ""
][0],
"Calibration file (*.xls, *.ods, *csv)",
options=QFileDialog.DontUseNativeDialog
)
def read_calibration_csv(self, filename):
data = pd.read_csv(
filename, header=0, index_col=0,
)
logger.debug(f"Calibration data: {data}")
return data
dir_name = os.path.dirname(filename[0])
name = os.path.basename(filename[0])
def read_calibration_ods(self, filename):
data = pd.read_excel(
filename, header=0, index_col=0,
engine="odf"
)
logger.debug(f"Calibration data: {data}")
return data
stg.path_calibration_file = dir_name
stg.filename_calibration_file = name
self.lineEdit_import_calibration.clear()
self.lineEdit_import_calibration.setText(name)
self.lineEdit_import_calibration.setToolTip(dir_name)
self.compute_depth_2D()
self.read_calibration_file_and_fill_parameter()
def read_calibration_excel(self, filename):
data = pd.read_excel(
filename, header=0, index_col=0,
)
logger.debug(f"Calibration data: {data}")
return data
def update_label_freq1_for_calibration(self):
self.label_freq1.clear()
@ -1666,69 +1713,51 @@ class SedimentCalibrationTab(QWidget):
str('%.4f' % stg.kt_read[freq_2])
)
def read_calibration_file_and_fill_parameter(self):
def fill_calibration_select_frequencies(self, data):
if stg.filename_calibration_file == "":
return
# --- Read calibration file ---
data = pd.read_csv(
os.path.join(
stg.path_calibration_file,
stg.filename_calibration_file
), header=0, index_col=0
)
# --- Fill spinboxes of calibration parameter ---
self.label_temperature.clear()
self.label_temperature.setText(
"T = " + str(stg.temperature) + " °C"
)
self.label_freq1.clear()
self.label_freq1.setText(data.columns[0])
data_id = self.combobox_acoustic_data_choice.currentIndex()
stg.calib_acoustic_data = data_id
index_freq1 = np.where(
np.asarray(
stg.freq_text[data_id]
) == data.columns[0]
)[0][0]
stg.frequencies_for_calibration.clear()
stg.frequencies_for_calibration.append(
(
stg.freq[data_id][index_freq1],
index_freq1
for label, column in [
(self.label_freq1, 0),
(self.label_freq2, 1)
]:
label.clear()
label.setText(data.columns[0])
index = next(
map(
lambda e: e[0],
filter(
lambda e: e[1] == data.columns[column],
enumerate(stg.freq_text[data_id])
)
)
)
)
stg.calib_freq_1 = index_freq1
self.label_freq2.clear()
self.label_freq2.setText(data.columns[1])
index_freq2 = np.where(
np.asarray(
stg.freq_text[data_id]
) == data.columns[1]
)[0][0]
stg.frequencies_for_calibration.append(
(
stg.freq[data_id][index_freq2],
index_freq2
stg.frequencies_for_calibration.append(
(
stg.freq[data_id][index],
index
)
)
)
stg.calib_freq_2 = index_freq2
stg.frequency_for_inversion = tuple()
stg.frequency_for_inversion = (
stg.freq[data_id][index_freq2],
index_freq2
)
logger.debug(f"Select freq {index}: {stg.freq_text[data_id][index]}")
stg.calib_freq_1 = stg.frequencies_for_calibration[0][1]
stg.calib_freq_2 = stg.frequencies_for_calibration[1][1]
def fill_calibration_parameters(self, data):
self.lineEdit_ks_freq1.clear()
self.lineEdit_ks_freq1.setText(
str("%.5f" % float(data.iloc[0][0]))
@ -2302,6 +2331,7 @@ class SedimentCalibrationTab(QWidget):
if self.fig_FCB is not None:
self.fig_FCB.clear()
plt.close(self.fig_FCB)
self.fig_FCB, self.axis_FCB = plt.subplots(
nrows=1, ncols=1, layout="constrained"

View File

@ -498,7 +498,7 @@ class SignalProcessingTab(QWidget):
def _setup_icons(self):
def path_icon(icon):
return os.path.join(
"icons", icon
os.path.dirname(__file__), "..", "icons", icon
)
self.icon_folder = QIcon(path_icon("folder.png"))
@ -639,7 +639,6 @@ class SignalProcessingTab(QWidget):
self.remove_point_with_snr_filter()
self.compute_averaged_BS_data()
@trace
def compute_noise(self, data_id):
if self._is_correct_shape(stg.BS_stream_bed):
BS_data = stg.BS_stream_bed
@ -865,6 +864,7 @@ class SignalProcessingTab(QWidget):
if self.fig_profile_tail is not None:
self.fig_profile_tail.clear()
plt.close(self.fig_profile_tail)
self.fig_profile_tail, self.axis_profile_tail = \
plt.subplots(nrows=1, ncols=1, layout='constrained')
@ -1157,7 +1157,6 @@ class SignalProcessingTab(QWidget):
self.compute_noise_from_profile_tail_value_compute()
@trace
def compute_noise_from_profile_tail_value_compute(self):
data_id = max(0, self.combobox_acoustic_data_choice.currentIndex())
@ -1232,6 +1231,7 @@ class SignalProcessingTab(QWidget):
if self.fig_noise is not None:
self.fig_noise.clear()
plt.close(self.fig_noise)
self.fig_noise, self.axis_noise = plt.subplots(
nrows=1, ncols=1, layout="constrained"
@ -1285,6 +1285,7 @@ class SignalProcessingTab(QWidget):
if self.fig_SNR is not None:
self.fig_SNR.clear()
plt.close(self.fig_SNR)
self.fig_SNR, self.axis_SNR = plt.subplots(
nrows=stg.freq[data_id].shape[0], ncols=1,
@ -1468,6 +1469,7 @@ class SignalProcessingTab(QWidget):
if self.fig_BS is not None:
self.fig_BS.clear()
plt.close(self.fig_BS)
self.fig_BS, self.axis_BS = plt.subplots(
nrows=stg.freq[data_id].shape[0], ncols=1,
@ -1702,6 +1704,7 @@ class SignalProcessingTab(QWidget):
if self.figure_profile is not None:
self.figure_profile.clear()
plt.close(self.figure_profile)
self.figure_profile, self.axis_profile = plt.subplots(
nrows=1, ncols=1, layout="constrained"

62
packages/README.md Normal file
View File

@ -0,0 +1,62 @@
# Build Windows package on Linux
*This README as tested on Guix with Wine 10.*
## Setup
### Wine
Fist, you need to install Wine:
```shell
# Debian
apt install winehq-stable wine64 winetricks
# Guix
guix install wine64 winetricks
```
Init a new custom wine prefix:
```shell
export WINE_PREFIX=$PWD/wine
wine winecfg
# or use env-wine.sh
./env-wine.sh wine winecfg
```
In `winecfg`, set the windows version to Windows 10 and click ok.
### Install windows software
We need to install 7zip and Python into the wine prefix. You can
install 7zip with the command:
```shell
./env-wine.sh winetricks apps 7zip
```
To install Python, you need to download Python installer for windows
on version 3.10.2. Next use this command to run the installer:
```shell
./env-wine.sh wine <path-to-python-installer-exe>
```
And follow the installation procedure without forget to activate setup
Python PATH. Now this command will work and return 'Python 3.10.2'.
```shell
$ ./env-wine.sh wine python --version
Python 3.10.2
```
## Build package
Now, you can run the scripts to build the windows package:
```shell
$ ./env-wine.sh wine windows.bat
```

6
packages/env-wine.sh Executable file
View File

@ -0,0 +1,6 @@
#/bin/sh
export WINEPREFIX=$PWD/wine
export WINEDEBUG=-all
$@

View File

@ -8,20 +8,6 @@ rem Build windows version
mkdir acoused_packaging
pyinstaller --name "acoused" ..\main.py -y
rem Icons
mkdir acoused_packaging\icons
copy /y ..\icons\*.png acoused_packaging\icons
rem Logos
mkdir acoused_packaging\logos
copy /y ..\logos\* acoused_packaging\logos
rem Doc
copy /y ..\ABS_calibration_constant_kt.xlsx acoused_packaging
copy /y ..\AcouSed_UserManual.pdf acoused_packaging
copy /y ..\Acoustic_Inversion_theory.pdf acoused_packaging
copy /y ..\Tutorial_AQUAscat_software.pdf acoused_packaging
rem move exe
move /y dist\AcouSed\acoused.exe acoused_packaging
move /y dist\acoused\_internal acoused_packaging
@ -30,6 +16,21 @@ rmdir /s /q build
rmdir /s /q dist
del /q AcouSed.spec
rem Icons
mkdir acoused_packaging\_internal\icons
copy /y ..\icons\*.png acoused_packaging\_internal\icons
rem Logos
mkdir acoused_packaging\_internal\logos
copy /y ..\logos\* acoused_packaging\_internal\logos
rem Doc
copy /y ..\ABS_calibration_constant_kt.xlsx acoused_packaging
copy /y ..\Tuto_acoused.pdf acoused_packaging
copy /y ..\Acoustic_Inversion_theory.pdf acoused_packaging
copy /y ..\Tutorial_AQUAscat_software.pdf acoused_packaging
set PATH=%PATH%;C:\Program Files (x86)/7-Zip
7z a -tzip acoused_packaging.zip acoused_packaging
pause

View File

@ -10,6 +10,7 @@ python-dateutil==2.8.2
scikit-learn==1.2.1
scipy==1.10.0
odfpy==1.4.1
xlsxwriter==3.2.0
openpyxl==3.0.10
pyinstaller==6.12.0
pyqt_file_list_widget==0.0.1