🚀 feat(data_processing.py): add function to calculate advanced data
🚀 feat(MainWindow.py): add support for calculating advanced data in a separate thread 🚀 feat(AdvancedDataWorker.py): add worker to calculate advanced data in a thread The `get_advanced_data` function was added to calculate advanced data from the discrete data. The `process_advanced_data` function was added to the `MainWindow` class to start a thread to calculate the advanced data. The `AdvancedDataWorker` class was added to calculate the advanced data in a separate thread. This allows the application to be more responsive and not freeze while the advanced data is being calculated.
This commit is contained in:
parent
2c2cae2d25
commit
dce613fd9e
@ -5,7 +5,8 @@ Created on Mon Apr 24 2023
|
||||
@auth: Djalim Simaila
|
||||
@e-mail: djalim.simaila@inrae.fr
|
||||
"""
|
||||
from utils.math import data_extraction
|
||||
from utils.math import data_extraction as de
|
||||
import numpy as np
|
||||
from utils.files.input import ScannedObject
|
||||
from utils.settings.SettingManager import SettingManager
|
||||
|
||||
@ -44,13 +45,13 @@ def get_raw_data(obj:ScannedObject, ndigits:int,delta_z:float=1,update_progress_
|
||||
|
||||
# Calculate the data for each discrete vertex
|
||||
for discrete_values in discrete_vertices:
|
||||
mean_x ,mean_y, mean_z = data_extraction.get_x_y_z_mean(discrete_values)
|
||||
mean_x ,mean_y, mean_z = de.get_x_y_z_mean(discrete_values)
|
||||
for x,y,z in discrete_values:
|
||||
data["X (en mm)"].append(round(x, ndigits))
|
||||
data["Y (en mm)"].append(round(y, ndigits))
|
||||
data["Z (en mm)"].append(round(z, ndigits))
|
||||
data["teta (en rad)"].append(round(data_extraction.get_teta_from_x_y(x,y,mean_x,mean_y), ndigits))
|
||||
data["rayon (en mm)"].append(round(data_extraction.get_radius_from_x_y(x,y,mean_x,mean_y), ndigits))
|
||||
data["teta (en rad)"].append(round(de.get_teta_from_x_y(x,y,mean_x,mean_y), ndigits))
|
||||
data["rayon (en mm)"].append(round(de.get_radius_from_x_y(x,y,mean_x,mean_y), ndigits))
|
||||
data["Xi-Xmoy"].append(round(x-mean_x, ndigits))
|
||||
data["Yi-Ymoy"].append(round(y-mean_y, ndigits))
|
||||
update_progress_bar(int(progress/len(discrete_vertices)*100))
|
||||
@ -82,16 +83,52 @@ def get_discrete_data(obj:ScannedObject, ndigits:int, delta_z:float=1, update_pr
|
||||
discrete_vertices = obj.get_discrete_vertices(delta_z)
|
||||
progress = 0
|
||||
for discrete_values in discrete_vertices:
|
||||
x,y,z = data_extraction.get_x_y_z_mean(discrete_values)
|
||||
x,y,z = de.get_x_y_z_mean(discrete_values)
|
||||
data["X moy (en mm)"].append(round(x, ndigits))
|
||||
data["Y moy (en mm)"].append(round(y, ndigits))
|
||||
data["Z moy (en mm)"].append(round(z, ndigits))
|
||||
first = discrete_values[0]
|
||||
last = discrete_values[-1]
|
||||
data["Discretisation(en mm)"].append(round(last[2]-first[2],ndigits))
|
||||
data["Rayon moyen (en mm)"].append(round(data_extraction.get_mean_radius(discrete_values), ndigits))
|
||||
data["Rayon ecart type (en mm)"].append(round(data_extraction.get_radius_std(discrete_values), ndigits))
|
||||
data["Rayon moyen (en mm)"].append(round(de.get_mean_radius(discrete_values), ndigits))
|
||||
data["Rayon ecart type (en mm)"].append(round(de.get_radius_std(discrete_values), ndigits))
|
||||
update_progress_bar(int(progress/len(discrete_vertices)*100))
|
||||
progress += 1
|
||||
return data
|
||||
|
||||
def get_advanced_data(discrete_data:dict, update_progress_bar= progressbar_placeholder):
|
||||
"""
|
||||
"""
|
||||
# Tortusity
|
||||
l = 0
|
||||
L = 0
|
||||
vertices = list(zip(discrete_data["X moy (en mm)"], discrete_data["Y moy (en mm)"], discrete_data["Z moy (en mm)"]))
|
||||
for i in range(len(vertices)-1):
|
||||
l += de.get_distance_between_two_vertices(vertices[i], vertices[i+1])
|
||||
L = de.get_distance_between_two_vertices(vertices[0], vertices[-1])
|
||||
T = l/L
|
||||
update_progress_bar(10)
|
||||
# Volume and surface
|
||||
H = discrete_data["Z moy (en mm)"][-1] - discrete_data["Z moy (en mm)"][0]
|
||||
R = de.get_mean([np.power(r,2) for r in discrete_data["Rayon moyen (en mm)"]])
|
||||
V = np.pi * R * H
|
||||
S = 2 * np.pi * R * H
|
||||
update_progress_bar(30)
|
||||
#
|
||||
R_mean = de.get_mean(discrete_data["Rayon moyen (en mm)"])
|
||||
R_mean_std = de.get_standard_deviation(discrete_data["Rayon moyen (en mm)"])
|
||||
mean_sigma_r_squared = de.get_mean([np.power(r,2) for r in discrete_data["Rayon ecart type (en mm)"]])
|
||||
sigma_r_tot = np.sqrt(np.power(R_mean_std,2) + mean_sigma_r_squared )
|
||||
MI_l = R_mean_std/R_mean
|
||||
MI_p = np.sqrt(mean_sigma_r_squared)/R_mean
|
||||
update_progress_bar(100)
|
||||
return {
|
||||
"Tortuosité":T,
|
||||
"Volume":V,
|
||||
"Surface":S,
|
||||
"Moyenne des rayons moyens":R_mean,
|
||||
"Ecart-type des rayons moyens":R_mean_std,
|
||||
"Sigma r tot":sigma_r_tot,
|
||||
"MI_l":MI_l,
|
||||
"MI_p":MI_p
|
||||
}
|
||||
|
||||
@ -10,9 +10,10 @@ from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QThread
|
||||
from PyQt5.QtWidgets import QFileDialog, QWidget
|
||||
from utils.files.input import ScannedObject
|
||||
from utils.gui.pyqt.main_window.Workers.AdvancedDataWorker import AdvancedDataWorker
|
||||
from utils.gui.pyqt.settings.Settings import Settings
|
||||
from utils.gui.pyqt.about.AboutThis import AboutThis
|
||||
from utils.math.data_extraction import get_radius_from_x_y, get_true_teta_from_x_y
|
||||
from utils.math.data_extraction import get_mean, get_radius_from_x_y, get_true_teta_from_x_y
|
||||
from utils.settings.SettingManager import SettingManager
|
||||
from utils.graph2D.visplot_render import cross_section, render2D
|
||||
from utils.graph3D.visplot_render import render3D
|
||||
@ -50,6 +51,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
"Coupe XZ",
|
||||
"Coupe YZ",
|
||||
"Evolution du rayon moyen",
|
||||
"Difference entre le rayon moyen et la moyenne des rayons",
|
||||
"Coupe de la couche",
|
||||
"Difference entre le rayon de chaque points et le rayon moyen de la couche"
|
||||
]
|
||||
@ -57,9 +59,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
self.obj = None
|
||||
self.raw_data= None
|
||||
self.discrete_data = None
|
||||
self.advanced_data = None
|
||||
|
||||
self.completed_tasks = 0
|
||||
self.total_tasks = 2
|
||||
self.total_tasks = 3
|
||||
|
||||
self.combo_boxes = [
|
||||
self.slot0ComboBox,
|
||||
@ -245,6 +248,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
self.processdiscrete_worker.status.connect(self.set_status)
|
||||
self.processdiscrete_worker.progress.connect(self.update_progress_bar)
|
||||
self.processdiscrete_worker.processedData.connect(self.set_discrete_data)
|
||||
self.processdiscrete_worker.processedData.connect(self.process_advanced_data)
|
||||
# Finished
|
||||
self.processdiscrete_worker.finished.connect(self.finish_analyse)
|
||||
self.processdiscrete_worker.finished.connect(self.processdiscrete_thread.quit)
|
||||
@ -254,6 +258,30 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
# Start the thread
|
||||
self.processdiscrete_thread.start()
|
||||
|
||||
def process_advanced_data(self, discrete_data:dict):
|
||||
"""
|
||||
Start the analyse, create the thread and connect the signals.
|
||||
"""
|
||||
self.advanced_data_thread = QThread()
|
||||
self.advanced_data_worker = AdvancedDataWorker("AdvancedDataProcessWorker",
|
||||
discrete_data)
|
||||
self.advanced_data_worker.moveToThread(self.advanced_data_thread)
|
||||
# Connect the signals
|
||||
# Start
|
||||
self.advanced_data_thread.started.connect(self.advanced_data_worker.run)
|
||||
# Progress
|
||||
self.advanced_data_worker.status.connect(self.set_status)
|
||||
self.advanced_data_worker.progress.connect(self.update_progress_bar)
|
||||
self.advanced_data_worker.processedData.connect(self.set_advanced_data)
|
||||
# Finished
|
||||
self.advanced_data_worker.finished.connect(self.finish_analyse)
|
||||
self.advanced_data_worker.finished.connect(self.advanced_data_thread.quit)
|
||||
self.advanced_data_worker.finished.connect(self.advanced_data_worker.deleteLater)
|
||||
self.advanced_data_thread.finished.connect(self.advanced_data_thread.deleteLater)
|
||||
|
||||
# Start the thread
|
||||
self.advanced_data_thread.start()
|
||||
|
||||
def set_obj(self,obj:ScannedObject):
|
||||
"""
|
||||
Set the obj to the main window
|
||||
@ -267,10 +295,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
self.discrete_data = discrete_data
|
||||
layer = [str(i) for i in range(len(discrete_data["X moy (en mm)"]))]
|
||||
layer.insert(0,"Aucune couche")
|
||||
self.layer_ComboBox.currentIndexChanged.disconnect(self.layer_changed)
|
||||
self.layer_ComboBox.clear()
|
||||
self.layer_ComboBox.addItems(layer)
|
||||
|
||||
|
||||
self.layer_ComboBox.currentIndexChanged.connect(self.layer_changed)
|
||||
|
||||
def set_raw_data(self,raw_data:dict):
|
||||
"""
|
||||
@ -278,6 +306,21 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
"""
|
||||
self.raw_data = raw_data
|
||||
|
||||
def set_advanced_data(self,advanced_data:dict):
|
||||
"""
|
||||
Set the advanced data to the main window
|
||||
"""
|
||||
self.advanced_data = advanced_data
|
||||
self.tortuosity.setValue(advanced_data["Tortuosité"])
|
||||
self.volume.setValue(advanced_data["Volume"])
|
||||
self.surface.setValue(advanced_data["Surface"])
|
||||
self.mean_r_mean.setValue(advanced_data["Moyenne des rayons moyens"])
|
||||
self.sigma_r_mean.setValue(advanced_data["Ecart-type des rayons moyens"])
|
||||
self.sigma_r_tot.setValue(advanced_data["Sigma r tot"])
|
||||
self.MI_l.setValue(advanced_data["MI_l"])
|
||||
self.MI_p.setValue(advanced_data["MI_p"])
|
||||
|
||||
|
||||
def save_model(self):
|
||||
"""
|
||||
Save the model to a file
|
||||
@ -339,21 +382,38 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
"Z (en mm)",
|
||||
False).native)
|
||||
if graph_type == "Evolution du rayon moyen":
|
||||
current_slot.addWidget(render2D(list(zip(discrete_data['Z moy (en mm)'],discrete_data['Rayon moyen (en mm)'])),
|
||||
current_slot.addWidget(render2D(list(zip(discrete_data['Rayon moyen (en mm)'],discrete_data['Z moy (en mm)'])),
|
||||
"Evolution du rayon moyen en fonction de Z",
|
||||
"Rayon moyen (en mm)",
|
||||
"Z (en mm)",
|
||||
False).native)
|
||||
if graph_type == "Difference entre le rayon moyen et la moyenne des rayons":
|
||||
r_mean= get_mean(discrete_data['Rayon moyen (en mm)'])
|
||||
current_slot.addWidget(render2D(list(zip(discrete_data['Rayon moyen (en mm)']-r_mean,discrete_data['Z moy (en mm)'])),
|
||||
"Difference entre le rayon moyen et la moyenne en fonction de Z",
|
||||
"Rayon moyen (en mm)",
|
||||
"Z (en mm)",
|
||||
"Rayon moyen (en mm)\n",
|
||||
False).native)
|
||||
self.set_status("Graphs rendered!")
|
||||
|
||||
def renderDiscreteGraphs(self,obj:ScannedObject,raw_data:dict,discrete_data:dict):
|
||||
"""
|
||||
"""
|
||||
self.set_status("Renderingc discretes graphs... this may take a moment")
|
||||
if self.layer_ComboBox.currentText() == 'Aucune couche':
|
||||
return
|
||||
layer_nb = int(self.layer_ComboBox.currentText())
|
||||
discretisation_value = self.discretisation_value_selector.value()
|
||||
|
||||
self.interval_size.setValue(self.discrete_data["Discretisation(en mm)"][layer_nb])
|
||||
self.x_mean.setValue(self.discrete_data["X moy (en mm)"][layer_nb])
|
||||
self.y_mean.setValue(self.discrete_data["Y moy (en mm)"][layer_nb])
|
||||
self.z_mean.setValue(self.discrete_data["Z moy (en mm)"][layer_nb])
|
||||
self.r_mean.setValue(self.discrete_data["Rayon moyen (en mm)"][layer_nb])
|
||||
self.sigma_r.setValue(self.discrete_data["Rayon ecart type (en mm)"][layer_nb])
|
||||
|
||||
if not self.show_graph_checkbox.isChecked():
|
||||
return
|
||||
self.set_status("Renderingc discretes graphs... this may take a moment")
|
||||
for slot in self.slots:
|
||||
current_slot = slot[0]
|
||||
graph_type = slot[1]
|
||||
|
||||
43
utils/gui/pyqt/main_window/Workers/AdvancedDataWorker.py
Normal file
43
utils/gui/pyqt/main_window/Workers/AdvancedDataWorker.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""
|
||||
Created on Wed Apr 26 2023
|
||||
@name: DiscreteDataWorker.py
|
||||
@desc: A module to process discrete data in a thread
|
||||
@auth: Djalim Simaila
|
||||
@e-mail: djalim.simaila@inrae.fr
|
||||
"""
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from utils.gui.pyqt.main_window.Workers.Worker import Worker
|
||||
from utils.data_processing.data_processing import get_advanced_data
|
||||
|
||||
class AdvancedDataWorker(Worker):
|
||||
"""
|
||||
Worker to calculate the discrete data in a thread
|
||||
|
||||
:param name: The name of the worker
|
||||
:param obj: The scanned object
|
||||
:param output_path: The path to save the output file
|
||||
:param output_file_prefix: The prefix of the output file
|
||||
:param delta_z: The delta z
|
||||
|
||||
:ivar obj: The scanned object
|
||||
:ivar delta_z: The delta z
|
||||
:ivar output_path: The path to save the output file
|
||||
:ivar output_file_prefix: The prefix of the output file
|
||||
:ivar processedData: The signal to emit the result
|
||||
"""
|
||||
processedData = pyqtSignal(dict)
|
||||
|
||||
def __init__(self,name:str, discrete_data:dict):
|
||||
super().__init__(name)
|
||||
self.discrete_data = discrete_data
|
||||
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Run the analyse
|
||||
"""
|
||||
self.set_status("Calculating advanced data...")
|
||||
advanced_data = get_advanced_data(self.discrete_data,self.update_progress)
|
||||
self.processedData.emit(advanced_data)
|
||||
self.set_status("Done")
|
||||
self.finished.emit()
|
||||
Loading…
Reference in New Issue
Block a user