feat: Separate GUI callbacks for improved code readability

chore: Updated save/open function
This commit is contained in:
2024-06-14 11:27:17 +02:00
parent 129446b0ea
commit f611abde66
10 changed files with 1203 additions and 1053 deletions

View File

@ -29,3 +29,9 @@
* Ajout des GNG
* Ajout de config.json pour éditer la configuration de l'application plus facilement
* Ajustement des callback pour éviter les bugs
* Séparation des callbacks de la GUI pour faciliter la lecture du code
## V4.1
* Ajustement de la fonction d'enregistrement et d'ouverture des datasets
* Ajout d'un bouton de sauvegarde pour les datasets filtrés

View File

@ -1,3 +1,18 @@
# Test
# 3D App
Ceci est un test
## Pages description
**Home page**: On the home page, you will have the A-Scan, the two B-Scan and he 3D Plot. You can view them in fullscreen by clicking the fullscreen button on the top right of the card.
**A-Scan filters**: On this page, you can apply filters on the dataset with custom values and see the difference with the raw dataset on the A-Scan graph.
**GNG**: The GNG page is to reconstruct default of the dataset by neural network.
## Navbar description
**Settings**: Open the settings modal taht allows you to change the sampling values, if the filters must be applied on the entire dataset and the usage of real values of the dataset
**Open**: Open a dataset present in `Dataset/saves` folder (only .npy files)
**Save**: Save the current dataset in `Dataset/saves` folder

313
3D_app/callbacks/ascan.py Normal file
View File

@ -0,0 +1,313 @@
from re import I
from dash import callback, Input, Output, State
from selection_filtre import switch_case
import plotly.graph_objects as go
import plotly.express as px
from Bscan_Cscan_trait import Cscant, Bscant
from util import lire_fichier_csv
import numpy as np
# on définit le dossier et les fichiers à lire
dossier = "Dataset/Shear_Wave_Rot00_CSV_Data"
fichiers_selectionnes = [
"Shear_x001-x101_y{:03d}_Rot00.csv".format(i) for i in range(10, 13)
]
# on lit les fichiers et on les met dans un tableau
pre_volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes))
volume = pre_volume[:, :, :]
data_traits = volume
dim_x, dim_y, dim_z = volume.shape
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
def get_callbacks():
@callback(
Output("store-filters", "data"),
Input("button-validate-filter", "n_clicks"),
[
State("select-ascan-filter1", "value"),
State("select-ascan-filter2", "value"),
State("select-ascan-filter3", "value"),
State("input-ascan-solo-fs", "value"),
State("input-ascan-solo-cutoff", "value"),
State("input-ascan-solo-order", "value"),
State("input-ascan-solo-windowsize", "value"),
State("input-ascan-solo-fs-2", "value"),
State("input-ascan-solo-cutoff-2", "value"),
State("input-ascan-solo-order-2", "value"),
State("input-ascan-solo-windowsize-2", "value"),
],
)
def store_settings(
clicks,
select_filtre_1,
select_filtre_2,
select_filtre_3,
fs_filtre_1,
cutoff_filtre_1,
order_filtre_1,
windowsize_filtre_1,
fs_filtre_2,
cutoff_filtre_2,
order_filtre_2,
windowsize_filtre_2,
):
if clicks:
return {
"select_filtre_1": select_filtre_1,
"select_filtre_2": select_filtre_2,
"select_filtre_3": select_filtre_3,
"fs_filtre_1": fs_filtre_1,
"cutoff_filtre_1": cutoff_filtre_1,
"order_filtre_1": order_filtre_1,
"windowsize_filtre_1": windowsize_filtre_1,
"fs_filtre_2": fs_filtre_2,
"cutoff_filtre_2": cutoff_filtre_2,
"order_filtre_2": order_filtre_2,
"windowsize_filtre_2": windowsize_filtre_2,
}
# callback to update filter values
@callback(
[
Output("input-ascan-solo-fs", "disabled"),
Output("input-ascan-solo-cutoff", "disabled"),
Output("input-ascan-solo-order", "disabled"),
Output("input-ascan-solo-windowsize", "disabled"),
Output("input-ascan-solo-fs-2", "disabled"),
Output("input-ascan-solo-cutoff-2", "disabled"),
Output("input-ascan-solo-order-2", "disabled"),
Output("input-ascan-solo-windowsize-2", "disabled"),
],
[
Input("select-ascan-filter2", "value"),
Input("select-ascan-filter3", "value"),
],
)
def update_filter_values(select_filtre_1, select_filtre_2):
fs_1 = True
cutoff_1 = True
ordre_1 = True
windowsize_1 = True
fs_2 = True
cutoff_2 = True
ordre_2 = True
windowsize_2 = True
if int(select_filtre_1) == 3:
fs_1 = False
cutoff_1 = False
ordre_1 = False
if int(select_filtre_2) == 3:
fs_2 = False
cutoff_2 = False
ordre_2 = False
if int(select_filtre_1) in (4, 5, 6, 7):
windowsize_1 = False
if int(select_filtre_2) in (4, 5, 6, 7):
windowsize_2 = False
return [
fs_1,
cutoff_1,
ordre_1,
windowsize_1,
fs_2,
cutoff_2,
ordre_2,
windowsize_2,
]
# callback to update the heatmap
@callback(
[
Output("heatmap-ascan-solo", "figure"),
Output("heatmap-bscan-solo", "figure"),
Output("heatmap-fft-solo", "figure"),
Output("loading", "children"),
],
[
Input("layer-slider-ascan-solo-x", "value"),
Input("layer-slider-ascan-solo-y", "value"),
Input("layer-slider-ascan-solo-z", "value"),
Input("button-validate-filter", "n_clicks"),
],
[
State("select-ascan-filter1", "value"),
State("select-ascan-filter2", "value"),
State("select-ascan-filter3", "value"),
State("input-ascan-solo-fs", "value"),
State("input-ascan-solo-cutoff", "value"),
State("input-ascan-solo-order", "value"),
State("input-ascan-solo-windowsize", "value"),
State("input-ascan-solo-fs-2", "value"),
State("input-ascan-solo-cutoff-2", "value"),
State("input-ascan-solo-order-2", "value"),
State("input-ascan-solo-windowsize-2", "value"),
],
)
def update_heatmap_ascan(
select_ascan_x,
select_ascan_y,
select_ascan_z,
n_clicks,
selec_transforme_hilbert,
select_filtre_1,
select_filtre_2,
fs_filtre_1,
cutoff_filtre_1,
order_filtre_1,
windowsize_filtre_1,
fs_filtre_2,
cutoff_filtre_2,
order_filtre_2,
windowsize_filtre_2,
):
print("debut du traitement")
data_avec_traitement = volume[
int(select_ascan_y) - 1,
select_ascan_z[0] : select_ascan_z[1],
int(select_ascan_x) - 1,
]
data_sans_traitement = volume[
int(select_ascan_y) - 1,
select_ascan_z[0] : select_ascan_z[1],
int(select_ascan_x) - 1,
]
data_avec_traitement = switch_case(
data_avec_traitement, int(selec_transforme_hilbert)
)
data_sans_traitement = switch_case(
data_sans_traitement, int(selec_transforme_hilbert)
)
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_1),
float(fs_filtre_1),
float(cutoff_filtre_1),
int(order_filtre_1),
int(windowsize_filtre_1),
)
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_2),
float(fs_filtre_2),
float(cutoff_filtre_2),
int(order_filtre_2),
int(windowsize_filtre_2),
)
print("fin du traitement")
bouton = "Apply"
if n_clicks != None:
data_traits = Cscant(
volume,
int(selec_transforme_hilbert),
int(select_filtre_1),
int(select_filtre_2),
float(fs_filtre_1),
float(cutoff_filtre_1),
int(order_filtre_1),
int(windowsize_filtre_1),
float(fs_filtre_2),
float(cutoff_filtre_2),
int(order_filtre_2),
int(windowsize_filtre_2),
)
bouton = "Apply"
fig = px.line(title="A-scan")
new_trace = go.Scatter(y=data_avec_traitement, mode="lines", name="Ascan trait")
fig.add_trace(new_trace)
new_trace = go.Scatter(
y=data_sans_traitement, mode="lines", name="Ascan (hilbert)"
)
fig.add_trace(new_trace)
fig.update_layout(xaxis_title="Indix", yaxis_title="Amplitude")
data_bscan = Bscant(
volume[select_ascan_y - 1, select_ascan_z[0] : select_ascan_z[1], :],
int(selec_transforme_hilbert),
int(select_filtre_1),
int(select_filtre_2),
float(fs_filtre_1),
float(cutoff_filtre_1),
int(order_filtre_1),
int(windowsize_filtre_1),
float(fs_filtre_2),
float(cutoff_filtre_2),
int(order_filtre_2),
int(windowsize_filtre_2),
)
fig2 = px.imshow(
data_bscan,
color_continuous_scale="Jet",
aspect="auto",
title="B-scan XZ",
)
fig2.update_layout(xaxis_title="Z", yaxis_title=" X")
data_sans_traitement_fft = np.fft.fft(
volume[
int(select_ascan_y) - 1,
select_ascan_z[0] : select_ascan_z[1],
int(select_ascan_x) - 1,
]
)
fig3 = px.line(title="FFT")
trace3 = go.Scatter(
y=np.abs(data_sans_traitement_fft), mode="lines", name=" FFT "
)
fig3.add_trace(trace3)
fig3.update_layout(
xaxis_title="FFT indix", yaxis_title="FFT of signal (Mangnitude)"
)
return [fig, fig2, fig3, bouton]
@callback(
[
Output("select-ascan-filter1", "value"),
Output("select-ascan-filter2", "value"),
Output("select-ascan-filter3", "value"),
Output("input-ascan-solo-fs", "value"),
Output("input-ascan-solo-cutoff", "value"),
Output("input-ascan-solo-order", "value"),
Output("input-ascan-solo-windowsize", "value"),
Output("input-ascan-solo-fs-2", "value"),
Output("input-ascan-solo-cutoff-2", "value"),
Output("input-ascan-solo-order-2", "value"),
Output("input-ascan-solo-windowsize-2", "value"),
],
Input("store-filters", "data"),
)
def load_filters(data):
if data:
return [
data["select_filtre_1"],
data["select_filtre_2"],
data["select_filtre_3"],
data["fs_filtre_1"],
data["cutoff_filtre_1"],
data["order_filtre_1"],
data["windowsize_filtre_1"],
data["fs_filtre_2"],
data["cutoff_filtre_2"],
data["order_filtre_2"],
data["windowsize_filtre_2"],
]
return [1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1]
@callback(
[Output("modal-ascan-solo", "is_open"), Output("save-toast", "is_open", allow_duplicate=True)],
[Input("save-ascan-solo", "n_clicks"), Input("button-save-data", "n_clicks")],
[State("modal-ascan-solo", "is_open"), State("input-save-ascan", "value")],
prevent_initial_call=True,
)
def toggle_modal(n1, n2, is_open, filename):
if n1:
np.save(f"Dataset/saves/{filename}.npy", data_traits)
return [not is_open, True]
elif n2:
return [not is_open, False]
return [is_open, False]

82
3D_app/callbacks/gng.py Normal file
View File

@ -0,0 +1,82 @@
from dash import callback_context as ctx
from dash import callback, Output, Input
import numpy as np
import plotly.graph_objects as go
from GNG_3D import *
from pages.ascan import data_traits
def get_callbacks():
@callback(
[Output("gng-graph", "figure")],
[
Input("generate-gng", "n_clicks"),
Input("seuil", "value"),
Input("max_neurons", "value"),
Input("Iterations", "value"),
Input("Max_of_age", "value"),
Input("eb", "value"),
Input("en", "value"),
Input("alpha", "value"),
Input("beta", "value"),
Input("l", "value"),
],
)
def generate_gng(n_clicks, seuil, max_neurons, max_iter, max_age, eb, en, alpha, beta, l):
global clics
if n_clicks:
data=np.array(data_traits)
fig = go.Figure()
size_data=np.shape(data)
x1=[]
x2=[]
x3=[]
x4=[]
for i in range(0,size_data[0]):
res=data[i,:,:]
res=position_point_espace(data=res,seuil=200,y=i)
res = np.array(res)
x1.append(res)
gng = GrowingNeuralGas(int(max_neurons),int(max_iter),int(max_age), float(eb), float(en), float(alpha), float(beta),int(l), res)
gng_graph = gng.learn()
neuron_positions = np.array([vertex['weight'] for vertex in gng_graph.vs])
neuron_edge= np.array([(edge.source, edge.target) for edge in gng_graph.es])
for edge in gng_graph.es:
src, tgt = edge.source, edge.target
src_pos, tgt_pos = gng_graph.vs[src]['weight'], gng_graph.vs[tgt]['weight']
x3.append(src_pos)
x4.append(tgt_pos)
x2.append(neuron_positions)
res=np.vstack(x1)
neuron_positions=np.vstack(x2)
src_pos=np.vstack(x3)
tgt_pos=np.vstack(x4)
fig.add_trace(go.Scatter3d(
x=res[:, 0],
y=res[:, 1],
z=res[:, 2],
mode='markers',
marker=dict(size=1, color=res[:, 3], colorscale='Viridis', opacity=0.5),
name='Data'
))
fig.add_trace(go.Scatter3d(
x=neuron_positions[:, 0],
y=neuron_positions[:, 1],
z=neuron_positions[:, 2],
mode='markers',
marker=dict(size=4, color=neuron_positions[:,3]),
name='Neurons'
))
for src, tgt in zip(src_pos, tgt_pos):
fig.add_trace(go.Scatter3d(
x=[src[0], tgt[0]],
y=[src[1], tgt[1]],
z=[src[2], tgt[2]],
mode='lines',
line=dict(color="black", width=1),
showlegend=False,
))
clics = n_clicks
return [fig]
return [go.Figure().update_layout(title="No data", showlegend=False).update_xaxes(visible=False).update_yaxes(visible=False)]

532
3D_app/callbacks/home.py Normal file
View File

@ -0,0 +1,532 @@
from dash import State, Output, Input, callback
import dash
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
from os.path import join
from util import lire_fichier_csv
from selection_filtre import switch_case
# on définit le dossier et les fichiers à lire
dossier = "Dataset/Shear_transform"
fichiers_selectionnes = [
"Shear_x001-x101_y{:03d}_Rot00_transform.csv".format(i) for i in range(10, 14)
]
# valeurs d'échantillonage
echantillonage_x = 1
echantillonage_y = 32
echantillonage_z = 1
pre_volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes))
volume = pre_volume[::echantillonage_x, ::echantillonage_y, ::echantillonage_z]
dim_x, dim_y, dim_z = volume.shape
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
def get_callbacks():
@callback(
[Output("3dplot", "figure"), Output("fade-3dplot", "is_in")],
[
Input("iso-slider", "value"),
Input("y-slider", "value"),
Input("store-settings", "data"),
],
[dash.dependencies.State("fade-3dplot", "is_in")],
)
def update_3dplot(iso_value, y_values, settings, is_in):
if settings["use_real_values"]:
y_min, y_max = y_values
selected_volume = volume[0:dim_x, int(y_min) : int(y_max), 0:dim_z]
X, Y, Z = [
np.load("Dataset/npy/{}-values.npy".format(i)) for i in ["x", "y", "z"]
]
else:
y_min, y_max = y_values
selected_volume = volume[0:dim_x, int(y_min) : int(y_max), 0:dim_z]
X, Y, Z = np.mgrid[
0 : selected_volume.shape[0],
0 : selected_volume.shape[1],
0 : selected_volume.shape[2],
]
fig = go.Figure(
data=go.Volume(
x=X.flatten(),
y=Y.flatten(),
z=Z.flatten(),
value=selected_volume.flatten(),
isomin=iso_value,
isomax=selected_volume.max(),
opacity=0.1,
surface_count=20,
colorscale="Jet",
)
)
return [fig, True]
# callback pour le plot 3D en plein écran
@callback(
Output("3dplot-fullscreen", "figure"),
[
Input("iso-slider-fullscreen", "value"),
Input("y-slider-fullscreen", "value"),
],
)
def update_3dplot_fullscreen(iso_value, y_values):
y_min, y_max = y_values
selected_volume = volume[0:dim_x, int(y_min) : int(y_max), 0:dim_z]
X, Y, Z = np.mgrid[
0 : selected_volume.shape[0],
0 : selected_volume.shape[1],
0 : selected_volume.shape[2],
]
fig = go.Figure(
data=go.Volume(
x=X.flatten(),
y=Y.flatten(),
z=Z.flatten(),
value=selected_volume.flatten(),
isomin=iso_value,
isomax=selected_volume.max(),
opacity=0.1,
surface_count=20,
colorscale="Jet",
)
)
return fig
# callback pour le A-scan
@callback(
[Output("heatmap-ascan", "figure"), Output("fade-ascan", "is_in")],
[
Input("layer-slider-bscan-zx", "value"),
Input("layer-slider-bscan-xy", "value"),
],
[dash.dependencies.State("fade-ascan", "is_in")],
prevent_initial_call=True,
)
def update_heatmap_ascan(layer, layer1, is_in):
fig = px.line(y=volume[layer - 1, :, layer1], title="A-scan")
return [fig, True]
# callback pour le A-scan en plein écran
@callback(
Output("heatmap-ascan-fullscreen", "figure"),
Input("layer-slider-ascan-fullscreen", "value"),
)
def update_heatmap_ascan_fullscreen(layer):
fig = px.line(y=volume[layer - 1, :, 5], title="A-scan")
return fig
# callback pour les B-scan XY
@callback(
[
Output("heatmap-bscan-zx", "figure"),
Output("store-bscan-zx-layer", "data"),
Output("fade-bscan-xy", "is_in"),
],
[Input("layer-slider-bscan-zx", "value")],
[dash.dependencies.State("fade-bscan-zx", "is_in")],
prevent_initial_call=True,
)
def update_heatmap_bscan_zx(layer, is_in):
fig = px.imshow(
volume[layer - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
)
return [fig, layer, True]
# callback pour les B-scan ZX en plein écran
@callback(
Output("heatmap-bscan-zx-fullscreen", "figure"),
Input("layer-slider-bscan-zx-fullscreen", "value"),
)
def update_heatmap_bscan_zx_fullscreen(layer):
fig = px.imshow(
volume[layer - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
)
return fig
# callback pour les B-scan ZX
@callback(
[
Output("heatmap-bscan-xy", "figure"),
Output("store-bscan-xy-layer", "data"),
Output("fade-bscan-zx", "is_in"),
],
[Input("layer-slider-bscan-xy", "value")],
[dash.dependencies.State("fade-bscan-xy", "is_in")],
prevent_initial_call=True,
)
def update_heatmap_bscan_xy(layer, is_in):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet"))
fig.update_layout(title="B-scan XY")
return [fig, layer, True]
# callback pour les B-scan ZX en plein écran
@callback(
Output("heatmap-bscan-xy-fullscreen", "figure"),
Input("layer-slider-bscan-xy-fullscreen", "value"),
)
def update_heatmap_bscan_xy_fullscreen(layer):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet"))
fig.update_layout(title="B-scan XY")
return fig
# callback pour le plein écran du plot 3D
@callback(
Output("modal-3dplot", "is_open"),
[Input("fullscreen-button-3dplot", "n_clicks")],
[dash.dependencies.State("modal-3dplot", "is_open")],
)
def toggle_fullscreen_3dplot(n1, is_open):
if n1:
return not is_open
return is_open
# callback pour le plein écran du A-scan
@callback(
Output("modal-ascan", "is_open"),
[Input("fullscreen-button-ascan", "n_clicks")],
[dash.dependencies.State("modal-ascan", "is_open")],
)
def toggle_fullscreen_ascan(n1, is_open):
if n1:
return not is_open
return is_open
# callback pour le plein écran du B-scan XY
@callback(
Output("modal-bscan-xy", "is_open"),
[Input("fullscreen-button-bscan-xy", "n_clicks")],
[dash.dependencies.State("modal-bscan-xy", "is_open")],
)
def toggle_fullscreen_bscan_xy(n1, is_open):
if n1:
return not is_open
return is_open
# callback pour le plein écran du B-scan ZX
@callback(
Output("modal-bscan-zx", "is_open"),
[Input("fullscreen-button-bscan-zx", "n_clicks")],
[dash.dependencies.State("modal-bscan-zx", "is_open")],
)
def toggle_fullscreen_bscan_zx(n1, is_open):
if n1:
return not is_open
return is_open
@callback(
[
Output("3dplot", "clickData"),
Output("layer-slider-bscan-xy", "value"),
Output("layer-slider-bscan-zx", "value"),
],
Input("3dplot", "clickData"),
)
def display_3dplot_click_data(clickData):
if clickData is None:
return [None, 1, 1]
bscan_xy = clickData["points"][0]["z"]
bscan_zx = clickData["points"][0]["x"]
return [clickData, bscan_xy, bscan_zx]
@callback(
[
Output("heatmap-bscan-xy", "clickData"),
Output("layer-slider-bscan-zx", "value", allow_duplicate=True),
],
[Input("heatmap-bscan-xy", "clickData")],
prevent_initial_call=True,
)
def display_bscan_xy_click_data(clickData):
if clickData is None:
return [None, 1]
bscan_zx = clickData["points"][0]["y"]
return [clickData, bscan_zx]
@callback(
[
Output("heatmap-bscan-zx", "clickData"),
Output("layer-slider-bscan-xy", "value", allow_duplicate=True),
],
[Input("heatmap-bscan-zx", "clickData")],
prevent_initial_call=True,
)
def display_bscan_zx_click_data(clickData):
if clickData is None:
return [None, 0]
bscan_xy = clickData["points"][0]["x"]
return [clickData, bscan_xy]
@callback(
[
Output("heatmap-bscan-xy", "figure", allow_duplicate=True),
Output("heatmap-bscan-zx", "figure", allow_duplicate=True),
Output("heatmap-ascan", "figure", allow_duplicate=True),
],
[Input("store-bscan-xy-layer", "data"), Input("store-bscan-zx-layer", "data")],
prevent_initial_call=True,
)
def update_bscan_layers(bscan_xy, bscan_zx):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, bscan_xy], colorscale="Jet"))
fig.add_shape(
type="line",
x0=0 - 1,
y0=bscan_zx,
x1=dim_y,
y1=bscan_zx,
line=dict(color="white", width=1),
)
fig.update_layout(title="B-scan XY")
fig2 = px.imshow(
volume[bscan_zx - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
)
fig2.add_shape(
type="line",
x0=bscan_xy,
y0=0,
x1=bscan_xy,
y1=dim_y,
line=dict(color="white", width=1),
)
fig3 = px.line(y=volume[bscan_zx - 1, :, bscan_xy], title="A-scan")
return [fig, fig2, fig3]
@callback(
[Output("store-settings", "data"), Output("settings-apply", "n_clicks")],
[
Input("settings-apply", "n_clicks"),
],
[
State("use-real-values", "value"),
State("apply-filters-everywhere", "value"),
State("echantillonage-x", "value"),
State("echantillonage-y", "value"),
State("echantillonage-z", "value"),
],
prevent_initial_call=True,
)
def update_settings(
clicks,
use_real_values,
apply_filters,
echantillonage_x_value,
echantillonage_y_value,
echantillonage_z_value,
):
if clicks != None and clicks == 1:
return [
{
"use_real_values": use_real_values,
"use_filters": apply_filters,
"echantillonage_x": echantillonage_x_value,
"echantillonage_y": echantillonage_y_value,
"echantillonage_z": echantillonage_z_value,
},
0,
]
@callback(
[
Output("layer-slider-bscan-zx", "max"),
Output("layer-slider-bscan-zx", "marks"),
Output("layer-slider-bscan-xy", "max"),
Output("layer-slider-bscan-xy", "marks"),
Output("iso-slider", "min"),
Output("iso-slider", "max"),
Output("iso-slider", "marks"),
Output("y-slider", "max"),
Output("y-slider", "marks"),
Output("layer-slider-ascan-fullscreen", "max"),
Output("layer-slider-ascan-fullscreen", "marks"),
Output("layer-slider-bscan-xy-fullscreen", "max"),
Output("layer-slider-bscan-xy-fullscreen", "marks"),
Output("layer-slider-bscan-zx-fullscreen", "max"),
Output("layer-slider-bscan-zx-fullscreen", "marks"),
Output("iso-slider-fullscreen", "min"),
Output("iso-slider-fullscreen", "max"),
Output("iso-slider-fullscreen", "marks"),
Output("y-slider-fullscreen", "max"),
Output("y-slider-fullscreen", "marks"),
Output("settings-spinner", "children"),
],
Input("store-settings", "data"),
prevent_initial_call=True,
)
def redef_data(data):
global volume, pre_volume, dim_x, dim_y, dim_z, X, Y, Z
volume = pre_volume[
:: data["echantillonage_x"],
:: data["echantillonage_y"],
:: data["echantillonage_z"],
]
dim_x, dim_y, dim_z = volume.shape
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
return [
dim_x - 1,
{str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 20)))},
dim_z - 1,
{str(i): str(i) for i in range(1, dim_z + 1, max(1, int(dim_z / 20)))},
volume.min(),
volume.max() / 2,
{
str(i): str(i)
for i in range(
int(volume.min()),
int(volume.max() / 2) + 1,
int((volume.max() / 2 - volume.min()) / 10),
)
},
dim_y,
{str(i): str(i) for i in range(0, int(dim_y) + 1, max(1, int(dim_y / 20)))},
dim_x - 1,
{str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 20)))},
dim_x - 1,
{str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 20)))},
dim_z - 1,
{str(i): str(i) for i in range(1, dim_z + 1, max(1, int(dim_z / 20)))},
volume.min(),
volume.max() / 2,
{
str(i): str(i)
for i in range(
int(volume.min()),
int(volume.max() / 2) + 1,
int((volume.max() / 2 - volume.min()) / 10),
)
},
dim_y,
{str(i): str(i) for i in range(0, int(dim_y) + 1, max(1, int(dim_y / 20)))},
"Apply",
]
@callback(
Output("store-filters", "data", allow_duplicate=True),
[Input("store-filters", "data"), Input("store-settings", "data")],
prevent_initial_call=True,
)
def apply_filters(data, settings):
global volume, pre_volume
if settings["use_filters"]:
select_filtre_1 = data["select_filtre_2"]
select_filtre_2 = data["select_filtre_3"]
fs_filtre_1 = data["fs_filtre_1"]
cutoff_filtre_1 = data["cutoff_filtre_1"]
order_filtre_1 = data["order_filtre_1"]
windowsize_filtre_1 = data["windowsize_filtre_1"]
fs_filtre_2 = data["fs_filtre_2"]
cutoff_filtre_2 = data["cutoff_filtre_2"]
order_filtre_2 = data["order_filtre_2"]
windowsize_filtre_2 = data["windowsize_filtre_2"]
selec_transforme_hilbert = data["select_filtre_1"]
volume = pre_volume[
:: settings["echantillonage_x"],
:: settings["echantillonage_y"],
:: settings["echantillonage_z"],
]
data_avec_traitement = switch_case(volume, int(selec_transforme_hilbert))
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_1),
int(fs_filtre_1),
int(cutoff_filtre_1),
int(order_filtre_1),
int(windowsize_filtre_1),
)
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_2),
int(fs_filtre_2),
int(cutoff_filtre_2),
int(order_filtre_2),
int(windowsize_filtre_2),
)
volume = data_avec_traitement
redef_data(settings)
else:
volume = pre_volume[
:: settings["echantillonage_x"],
:: settings["echantillonage_y"],
:: settings["echantillonage_z"],
]
return data
@callback(
Output("store-files", "data", allow_duplicate=True),
Input("store-files", "data"),
State("store-settings", "data"),
prevent_initial_call=True,
)
def update_files(data, settings):
global pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
if data is None or data == "":
return None
# Charger le nouveau volume
pre_volume = np.load(join("Dataset/saves", data))
print("New volume loaded:", pre_volume.shape)
# Appliquer les nouveaux paramètres d'échantillonnage
volume = pre_volume[
::settings["echantillonage_x"],
::settings["echantillonage_y"],
::settings["echantillonage_z"],
]
dim_x, dim_y, dim_z = volume.shape
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
print("Volume updated with new dimensions:", volume.shape)
# Mettre à jour les graphiques
update_3dplot(0, [0, dim_y // 2], settings, False)
update_heatmap_ascan(0, 0, False)
update_heatmap_bscan_zx(0, False)
update_heatmap_bscan_xy(0, False)
return None
@callback(
Output("save-toast", "is_open"),
Input("save-save", "n_clicks"),
[
State("save-input", "value"),
State("save-format", "value"),
],
)
def save_data(n_clicks, filename, format):
if n_clicks is None:
return False
if format == "raw":
np.save(join("Dataset/saves", filename), pre_volume)
else:
np.save(join("Dataset/saves", filename), volume)
return True

120
3D_app/callbacks/main.py Normal file
View File

@ -0,0 +1,120 @@
from dash import Input, Output, State, ALL, callback
import dash
from os import listdir
from os.path import isfile, join
import dash_bootstrap_components as dbc
def get_callbacks():
# callback pour le modal
@callback(
Output("modal", "is_open"),
[Input("howto-open", "n_clicks"), Input("howto-close", "n_clicks")],
[dash.dependencies.State("modal", "is_open")],
)
def toggle_modal(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
@callback(
Output("settings-modal", "is_open"),
[Input("settings-open", "n_clicks"), Input("settings-close", "n_clicks")],
[dash.dependencies.State("settings-modal", "is_open")],
)
def toggle_settings(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
# callback pour le navmenu
@callback(
Output("offcanvas-menu", "is_open"),
[Input("navbar-toggler", "n_clicks")],
[dash.dependencies.State("offcanvas-menu", "is_open")],
)
def toggle_offcanvas(n, is_open):
if n:
return not is_open
return is_open
@callback(
Output("open-modal", "is_open"),
[Input("open-button", "n_clicks"), Input("open-close", "n_clicks")],
[dash.dependencies.State("open-modal", "is_open")],
)
def toggle_open(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
@callback(
Output("save-modal", "is_open"),
[
Input("save-button", "n_clicks"),
Input("save-close", "n_clicks"),
Input("save-save", "n_clicks"),
],
[dash.dependencies.State("save-modal", "is_open")],
)
def toggle_save(n1, n2, n3, is_open):
if n1 or n2 or n3:
return not is_open
return is_open
@callback(
Output("file-list", "children"),
[Input("open-refresh", "n_clicks")],
)
def refresh_files(n):
files = listdir("Dataset/saves")
return [
dbc.ListGroupItem(
f"{file}",
action=True,
style={"cursor": "pointer"},
id={"type": "file-item", "index": i},
)
for i, file in enumerate(files)
if isfile(join("Dataset/saves", file))
]
@callback(
[
Output("open-modal", "is_open", allow_duplicate=True),
Output("store-files", "data"),
],
Input({"type": "file-item", "index": ALL}, "n_clicks"),
State({"type": "file-item", "index": ALL}, "children"),
prevent_initial_call=True,
)
def open_file(n, filenames):
ctx = dash.callback_context
if not ctx.triggered or all(click is None for click in n):
return [None, ""]
file_index = ctx.triggered[0]["prop_id"].split(".")[0]
file_index = eval(file_index)
filename = filenames[file_index["index"]]
return [False, filename]
@callback(
Output("save-format", "options"),
[Input("store-filters", "data")],
)
def update_save_format(filters):
if filters != {}:
return [
{"label": "Save raw dataset", "value": "raw"},
{"label": "Save filtered dataset", "value": "filt"},
]
return [
{"label": "Save raw dataset", "value": "raw"},
{"label": "Save filtered dataset", "value": "filt", "disabled": True},
]

View File

@ -1,11 +1,11 @@
import dash
from dash import dcc, html, ALL, DiskcacheManager
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
from os import listdir, mkdir, getenv
from os import listdir, mkdir
from os.path import isfile, join
import diskcache
from json import load
from callbacks.main import *
# on crée l'application
@ -373,121 +373,8 @@ app.layout = dbc.Container(
fluid=True,
)
# callback pour le modal
@app.callback(
Output("modal", "is_open"),
[Input("howto-open", "n_clicks"), Input("howto-close", "n_clicks")],
[dash.dependencies.State("modal", "is_open")],
)
def toggle_modal(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
@app.callback(
Output("settings-modal", "is_open"),
[Input("settings-open", "n_clicks"), Input("settings-close", "n_clicks")],
[dash.dependencies.State("settings-modal", "is_open")],
)
def toggle_settings(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
# callback pour le navmenu
@app.callback(
Output("offcanvas-menu", "is_open"),
[Input("navbar-toggler", "n_clicks")],
[dash.dependencies.State("offcanvas-menu", "is_open")],
)
def toggle_offcanvas(n, is_open):
if n:
return not is_open
return is_open
@app.callback(
Output("open-modal", "is_open"),
[Input("open-button", "n_clicks"), Input("open-close", "n_clicks")],
[dash.dependencies.State("open-modal", "is_open")],
)
def toggle_open(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
@app.callback(
Output("save-modal", "is_open"),
[
Input("save-button", "n_clicks"),
Input("save-close", "n_clicks"),
Input("save-save", "n_clicks"),
],
[dash.dependencies.State("save-modal", "is_open")],
)
def toggle_save(n1, n2, n3, is_open):
if n1 or n2 or n3:
return not is_open
return is_open
@app.callback(
Output("file-list", "children"),
[Input("open-refresh", "n_clicks")],
)
def refresh_files(n):
files = listdir("Dataset/saves")
return [
dbc.ListGroupItem(
f"{file}",
action=True,
style={"cursor": "pointer"},
id={"type": "file-item", "index": i},
)
for i, file in enumerate(files)
if isfile(join("Dataset/saves", file))
]
@app.callback(
[
Output("open-modal", "is_open", allow_duplicate=True),
Output("store-files", "data"),
],
Input({"type": "file-item", "index": ALL}, "n_clicks"),
State({"type": "file-item", "index": ALL}, "children"),
prevent_initial_call=True,
)
def open_file(n, filenames):
ctx = dash.callback_context
if not ctx.triggered or all(click is None for click in n):
return [None, ""]
file_index = ctx.triggered[0]["prop_id"].split(".")[0]
file_index = eval(file_index)
filename = filenames[file_index["index"]]
return [False, filename]
@app.callback(
Output("save-format", "options"),
[Input("store-filters", "data")],
)
def update_save_format(filters):
if filters != {}:
return [
{"label": "Save raw dataset", "value": "raw"},
{"label": "Save filtered dataset", "value": "filt"},
]
return [
{"label": "Save raw dataset", "value": "raw"},
{"label": "Save filtered dataset", "value": "filt", "disabled": True},
]
get_callbacks()
# on lance l'application
if __name__ == "__main__":
app.run(debug=config["debug"] or False, port=config["port"] or "8051", threaded=True)
app.run(debug=config["debug"] or False, port=config["port"] or "8051", threaded=True)

View File

@ -9,10 +9,15 @@ from util import *
from filtrage import *
from selection_filtre import *
from Bscan_Cscan_trait import *
from callbacks.ascan import get_callbacks
dash.register_page(
__name__, path="/ascan", title="A-Scan filters", name="A-Scan filters"
__name__,
path="/ascan",
title="A-Scan filters",
name="A-Scan filters",
description="Apply filters on the dataset",
)
# on définit le dossier et les fichiers à lire
@ -26,7 +31,7 @@ pre_volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes))
volume = pre_volume[:, :, :]
data_traits = volume
dim_x, dim_y, dim_z = volume.shape
click=None
click = None
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
# on définit le thème de l'application
pio.templates.default = "plotly_dark"
@ -43,6 +48,25 @@ configAScan = {
}
layout = html.Div(
[
dbc.Modal(
[
dbc.ModalHeader("Save data"),
dbc.ModalBody(
dbc.Input(
id="input-save-ascan", placeholder="Filename", type="text"
),
),
dbc.ModalFooter(
[
dbc.Button("Save", id="save-ascan-solo", className="ml-auto"),
dbc.Button("Close", id="close-ascan-solo", className="ml-auto"),
]
),
],
id="modal-ascan-solo",
centered=True,
is_open=False,
),
dbc.Row(
[
dbc.Col(
@ -50,29 +74,29 @@ layout = html.Div(
dbc.Select(
id="select-ascan-filter1",
options=[
{"label": "transformer du Hilbert", "value": "1"},
{"label": "Transformer du Hilbert", "value": "1"},
],
value=1,
style={"margin-bottom": "15px"},
),
],
width=2,
width=3,
),
dbc.Col(
[
dbc.Select(
id="select-ascan-filter2",
options=[
{"label": "sans filtre ", "value": "2"},
{"label": "filtre passe bas ", "value": "3"},
{"label": "filtre de moyenne mobile", "value": "4"},
{"label": "filtre adaptatif (wiener)", "value": "5"},
{"label": "No filter ", "value": "2"},
{"label": "Filtre passe bas ", "value": "3"},
{"label": "Filtre de moyenne mobile", "value": "4"},
{"label": "Filtre adaptatif (wiener)", "value": "5"},
{
"label": "filtre à réponse impulsionnelle infinie",
"label": "Filtre à réponse impulsionnelle infinie",
"value": "6",
},
{
"label": "filtre à réponse impulsionnelle finie",
"label": "Filtre à réponse impulsionnelle finie",
"value": "7",
},
],
@ -80,23 +104,23 @@ layout = html.Div(
style={"margin-bottom": "15px"},
),
],
width=2,
width=3,
),
dbc.Col(
[
dbc.Select(
id="select-ascan-filter3",
options=[
{"label": "sans filtre ", "value": "2"},
{"label": "filtre passe bas ", "value": "3"},
{"label": "filtre de moyenne mobile", "value": "4"},
{"label": "filtre adaptatif (wiener)", "value": "5"},
{"label": "No filter ", "value": "2"},
{"label": "Filtre passe bas ", "value": "3"},
{"label": "Filtre de moyenne mobile", "value": "4"},
{"label": "Filtre adaptatif (wiener)", "value": "5"},
{
"label": "filtre à réponse impulsionnelle infinie",
"label": "Filtre à réponse impulsionnelle infinie",
"value": "6",
},
{
"label": "filtre à réponse impulsionnelle finie",
"label": "Filtre à réponse impulsionnelle finie",
"value": "7",
},
],
@ -104,12 +128,12 @@ layout = html.Div(
style={"margin-bottom": "15px"},
),
],
width=2,
width=3,
),
dbc.Col(
[
dbc.Label(
"apply the filters",
"Apply the filters",
style={"marginRight": "5px"},
),
dbc.Button(
@ -132,26 +156,26 @@ layout = html.Div(
dbc.Button(
id="button-save-data",
children=dbc.Spinner(
html.Div("save", id="save"), show_initially=False
html.Div("Save", id="save"), show_initially=False
),
color="primary",
style={"marginBottom": "15px"},
),
],
width=2,
width=1,
),
]
),
dbc.Row(
[
dbc.Col(
[html.Br(), html.B(" paramètre du 1er filtre ")],
[html.Br(), html.B("Parameters of the 1st filter")],
width=2,
style={"textAlign": "center"},
),
dbc.Col(
[
dbc.Label("Fs ", html_for="Fs "),
dbc.Label("Fs", html_for="Fs "),
dbc.Input(
id="input-ascan-solo-fs",
type="number",
@ -164,11 +188,11 @@ layout = html.Div(
),
dbc.Col(
[
dbc.Label("cut off ", html_for="cut off"),
dbc.Label("Cut off", html_for="cut off"),
dbc.Input(
id="input-ascan-solo-cutoff",
type="number",
placeholder="cut_off",
placeholder="Cut off",
value=1,
step=0.1,
),
@ -177,11 +201,11 @@ layout = html.Div(
),
dbc.Col(
[
dbc.Label("order ", html_for="order"),
dbc.Label("Order", html_for="order"),
dbc.Input(
id="input-ascan-solo-order",
type="number",
placeholder="order",
placeholder="Order",
value=1,
step=1,
),
@ -190,11 +214,11 @@ layout = html.Div(
),
dbc.Col(
[
dbc.Label("window size ", html_for="window size"),
dbc.Label("Window size", html_for="window size"),
dbc.Input(
id="input-ascan-solo-windowsize",
type="number",
placeholder="window_size",
placeholder="Window size",
value=1,
step=1,
),
@ -202,13 +226,13 @@ layout = html.Div(
width=1,
),
dbc.Col(
[html.Br(), html.B(" paramètre du 2e filtre ")],
[html.Br(), html.B("Parameters of the 2nd filter")],
width=2,
style={"textAlign": "center"},
),
dbc.Col(
[
dbc.Label("Fs ", html_for="Fs "),
dbc.Label("Fs", html_for="Fs "),
dbc.Input(
id="input-ascan-solo-fs-2",
type="number",
@ -221,11 +245,11 @@ layout = html.Div(
),
dbc.Col(
[
dbc.Label("cut off ", html_for="cut off"),
dbc.Label("Cut off", html_for="cut off"),
dbc.Input(
id="input-ascan-solo-cutoff-2",
type="number",
placeholder="cut_off",
placeholder="Cut off",
value=1,
step=0.1,
),
@ -234,11 +258,11 @@ layout = html.Div(
),
dbc.Col(
[
dbc.Label("order ", html_for="order"),
dbc.Label("Order", html_for="order"),
dbc.Input(
id="input-ascan-solo-order-2",
type="number",
placeholder="order",
placeholder="Order",
value=1,
step=1,
),
@ -247,11 +271,11 @@ layout = html.Div(
),
dbc.Col(
[
dbc.Label("window size ", html_for="window size"),
dbc.Label("Window size", html_for="window size"),
dbc.Input(
id="input-ascan-solo-windowsize-2",
type="number",
placeholder="window_size",
placeholder="Window size",
value=1,
step=1,
),
@ -325,267 +349,4 @@ layout = html.Div(
style={"padding": "20px"},
)
@callback(
Output("store-filters", "data"),
[
Input("select-ascan-filter1", "value"),
Input("select-ascan-filter2", "value"),
Input("select-ascan-filter3", "value"),
Input("input-ascan-solo-fs", "value"),
Input("input-ascan-solo-cutoff", "value"),
Input("input-ascan-solo-order", "value"),
Input("input-ascan-solo-windowsize", "value"),
Input("input-ascan-solo-fs-2", "value"),
Input("input-ascan-solo-cutoff-2", "value"),
Input("input-ascan-solo-order-2", "value"),
Input("input-ascan-solo-windowsize-2", "value"),
],
)
def store_settings(
select_filtre_1,
select_filtre_2,
select_filtre_3,
fs_filtre_1,
cutoff_filtre_1,
order_filtre_1,
windowsize_filtre_1,
fs_filtre_2,
cutoff_filtre_2,
order_filtre_2,
windowsize_filtre_2,
):
return {
"select_filtre_1": select_filtre_1,
"select_filtre_2": select_filtre_2,
"select_filtre_3": select_filtre_3,
"fs_filtre_1": fs_filtre_1,
"cutoff_filtre_1": cutoff_filtre_1,
"order_filtre_1": order_filtre_1,
"windowsize_filtre_1": windowsize_filtre_1,
"fs_filtre_2": fs_filtre_2,
"cutoff_filtre_2": cutoff_filtre_2,
"order_filtre_2": order_filtre_2,
"windowsize_filtre_2": windowsize_filtre_2,
}
# callback to update filter values
@callback(
[
Output("input-ascan-solo-fs", "disabled"),
Output("input-ascan-solo-cutoff", "disabled"),
Output("input-ascan-solo-order", "disabled"),
Output("input-ascan-solo-windowsize", "disabled"),
Output("input-ascan-solo-fs-2", "disabled"),
Output("input-ascan-solo-cutoff-2", "disabled"),
Output("input-ascan-solo-order-2", "disabled"),
Output("input-ascan-solo-windowsize-2", "disabled"),
],
[
Input("select-ascan-filter2", "value"),
Input("select-ascan-filter3", "value"),
],
)
def update_filter_values(select_filtre_1, select_filtre_2):
fs_1 = True
cutoff_1 = True
ordre_1 = True
windowsize_1 = True
fs_2 = True
cutoff_2 = True
ordre_2 = True
windowsize_2 = True
if int(select_filtre_1) == 3:
fs_1 = False
cutoff_1 = False
ordre_1 = False
if int(select_filtre_2) == 3:
fs_2 = False
cutoff_2 = False
ordre_2 = False
if int(select_filtre_1) in (4, 5, 6, 7):
windowsize_1 = False
if int(select_filtre_2) in (4, 5, 6, 7):
windowsize_2 = False
return [
fs_1,
cutoff_1,
ordre_1,
windowsize_1,
fs_2,
cutoff_2,
ordre_2,
windowsize_2,
]
@callback(
Output("loading", "children"),
Input("button-validate-filter", "n_clicks"),
[
State("select-ascan-filter1", "value"),
State("select-ascan-filter2", "value"),
State("select-ascan-filter3", "value"),
State("input-ascan-solo-fs", "value"),
State("input-ascan-solo-cutoff", "value"),
State("input-ascan-solo-order", "value"),
State("input-ascan-solo-windowsize", "value"),
State("input-ascan-solo-fs-2", "value"),
State("input-ascan-solo-cutoff-2", "value"),
State("input-ascan-solo-order-2", "value"),
State("input-ascan-solo-windowsize-2", "value"),
]
)
def load_button(n_clicks,
selec_transforme_hilbert,
select_filtre_1,select_filtre_2,
fs_filtre_1,cutoff_filtre_1,
order_filtre_1,windowsize_filtre_1,
fs_filtre_2,cutoff_filtre_2,order_filtre_2,windowsize_filtre_2,
):
bouton = "Valider"
global data_traits,click
if n_clicks != click:
data_traits=Cscant(data_input=data_traits,
sel1=int(selec_transforme_hilbert),sel2=int(select_filtre_1),
sel3=int(select_filtre_2),
fs_1=int(fs_filtre_1),cut_off_1=float(cutoff_filtre_1),
order_1=int(order_filtre_1),window_size_1=int(windowsize_filtre_1),
fs_2=int(fs_filtre_2),cut_off_2=float(cutoff_filtre_2),
order_2=int(order_filtre_2),window_size2=int(windowsize_filtre_2))
bouton = "Valider"
click=n_clicks
return bouton
@callback(
Output("save", "children"),
Input("button-save-data","n_clicks"),
)
def save_data(n_clicks):
bouton = "save"
global data_traits
if n_clicks!=None:
np.save('Dataset/saves/datat.npy',data_traits)
bouton = "save"
return bouton
# callback to update the heatmap
@callback(
[
Output("heatmap-ascan-solo", "figure"),
Output("heatmap-bscan-solo", "figure"),
Output("heatmap-fft-solo", "figure"),
],
[
Input("layer-slider-ascan-solo-x", "value"),
Input("layer-slider-ascan-solo-y", "value"),
Input("layer-slider-ascan-solo-z", "value"),
Input("button-validate-filter", "n_clicks"),
],
[
State("select-ascan-filter1", "value"),
State("select-ascan-filter2", "value"),
State("select-ascan-filter3", "value"),
State("input-ascan-solo-fs", "value"),
State("input-ascan-solo-cutoff", "value"),
State("input-ascan-solo-order", "value"),
State("input-ascan-solo-windowsize", "value"),
State("input-ascan-solo-fs-2", "value"),
State("input-ascan-solo-cutoff-2", "value"),
State("input-ascan-solo-order-2", "value"),
State("input-ascan-solo-windowsize-2", "value"),
]
)
def update_heatmap_ascan(
select_ascan_x,
select_ascan_y,
select_ascan_z,
n_clicks,
selec_transforme_hilbert,
select_filtre_1,
select_filtre_2,
fs_filtre_1,
cutoff_filtre_1,
order_filtre_1,
windowsize_filtre_1,
fs_filtre_2,
cutoff_filtre_2,
order_filtre_2,
windowsize_filtre_2,
):
# TODO: implement the filter
print("debut du traitement")
data_avec_traitement = volume[
int(select_ascan_y) - 1,
select_ascan_z[0] : select_ascan_z[1],
int(select_ascan_x) - 1,
]
data_sans_traitement = volume[
int(select_ascan_y) - 1,
select_ascan_z[0] : select_ascan_z[1],
int(select_ascan_x) - 1,
]
data_avec_traitement = switch_case(
data_avec_traitement, int(selec_transforme_hilbert)
)
data_sans_traitement = switch_case(
data_sans_traitement, int(selec_transforme_hilbert)
)
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_1),
float(fs_filtre_1),
float(cutoff_filtre_1),
int(order_filtre_1),
int(windowsize_filtre_1),
)
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_2),
float(fs_filtre_2),
float(cutoff_filtre_2),
int(order_filtre_2),
int(windowsize_filtre_2),
)
print("fin du traitement")
fig = px.line(title="A-scan")
new_trace = go.Scatter(y=data_avec_traitement, mode="lines", name=" Ascan trait ")
fig.add_trace(new_trace)
new_trace = go.Scatter(
y=data_sans_traitement, mode="lines", name=" Ascan (hilbert) "
)
fig.add_trace(new_trace)
fig.update_layout(xaxis_title="indix", yaxis_title="amplitude")
data_bscan=Bscant(volume[select_ascan_y - 1, select_ascan_z[0] : select_ascan_z[1], :],int(selec_transforme_hilbert),int(select_filtre_1),int(select_filtre_2),float(fs_filtre_1),
float(cutoff_filtre_1),int(order_filtre_1),int(windowsize_filtre_1),float(fs_filtre_2),float(cutoff_filtre_2),int(order_filtre_2),int(windowsize_filtre_2),)
fig2 = px.imshow(
data_bscan,
color_continuous_scale="Jet",
aspect="auto",
title="B-scan XZ",
)
fig2.update_layout(xaxis_title="Z", yaxis_title=" X")
data_sans_traitement_fft = np.fft.fft(
volume[
int(select_ascan_y) - 1,
int(select_ascan_z[0]) : int(select_ascan_z[1]),
int(select_ascan_x) - 1,
]
)
fig3 = px.line(title="FFT")
trace3 = go.Scatter(y=np.abs(data_sans_traitement_fft[int(select_ascan_z[0]) :int(int(select_ascan_z[1])/2)]), mode="lines", name=" FFT ")
fig3.add_trace(trace3)
fig3.update_layout(
xaxis_title="FFT indix", yaxis_title="FFT of signal (Mangnitude)"
)
return [fig, fig2, fig3]
get_callbacks()

View File

@ -1,18 +1,11 @@
import dash
import plotly.graph_objects as go
from dash import html, dcc, callback, Input, Output
from dash import html, dcc
import dash_bootstrap_components as dbc
import numpy as np
from GNG_3D import *
from sklearn import datasets as sk
from pages.ascan import data_traits
from callbacks.gng import get_callbacks
dash.register_page(__name__, path="/gng", title="GNG", name="GNG")
dash.register_page(__name__, path="/gng", title="GNG", name="GNG", description="Growing Neural Gas")
clics = None
# Create and fit the GNG model
layout = html.Div(
[
@ -138,76 +131,4 @@ layout = html.Div(
)
@callback(
[Output("gng-graph", "figure")],
[
Input("generate-gng", "n_clicks"),
Input("seuil", "value"),
Input("max_neurons", "value"),
Input("Iterations", "value"),
Input("Max_of_age", "value"),
Input("eb", "value"),
Input("en", "value"),
Input("alpha", "value"),
Input("beta", "value"),
Input("l", "value"),
],
)
def generate_gng(n_clicks, seuil, max_neurons, max_iter, max_age, eb, en, alpha, beta, l):
global clics
if n_clicks != clics:
data=np.array(data_traits)
fig = go.Figure()
size_data=np.shape(data)
x1=[]
x2=[]
x3=[]
x4=[]
for i in range(0,size_data[0]):
res=data[i,:,:]
res=position_point_espace(data=res,seuil=200,y=i)
res = np.array(res)
x1.append(res)
gng = GrowingNeuralGas(int(max_neurons),int(max_iter),int(max_age), float(eb), float(en), float(alpha), float(beta),int(l), res)
gng_graph = gng.learn()
neuron_positions = np.array([vertex['weight'] for vertex in gng_graph.vs])
neuron_edge= np.array([(edge.source, edge.target) for edge in gng_graph.es])
for edge in gng_graph.es:
src, tgt = edge.source, edge.target
src_pos, tgt_pos = gng_graph.vs[src]['weight'], gng_graph.vs[tgt]['weight']
x3.append(src_pos)
x4.append(tgt_pos)
x2.append(neuron_positions)
res=np.vstack(x1)
neuron_positions=np.vstack(x2)
src_pos=np.vstack(x3)
tgt_pos=np.vstack(x4)
fig.add_trace(go.Scatter3d(
x=res[:, 0],
y=res[:, 1],
z=res[:, 2],
mode='markers',
marker=dict(size=1, color=res[:, 3], colorscale='Viridis', opacity=0.5),
name='Data'
))
fig.add_trace(go.Scatter3d(
x=neuron_positions[:, 0],
y=neuron_positions[:, 1],
z=neuron_positions[:, 2],
mode='markers',
marker=dict(size=4, color=neuron_positions[:,3]),
name='Neurons'
))
for src, tgt in zip(src_pos, tgt_pos):
fig.add_trace(go.Scatter3d(
x=[src[0], tgt[0]],
y=[src[1], tgt[1]],
z=[src[2], tgt[2]],
mode='lines',
line=dict(color="black", width=1),
showlegend=False,
))
clics = n_clicks
return [fig]
get_callbacks()

View File

@ -1,19 +1,27 @@
import dash
from dash import html, callback, Input, Output, dcc, State, DiskcacheManager
from dash import html, dcc, DiskcacheManager
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
import numpy as np
import plotly.express as px
import plotly.io as pio
from util import *
from selection_filtre import *
from os.path import join
import diskcache
from pages.ascan import data_traits, pre_volume
from callbacks.home import get_callbacks
from pages.ascan import pre_volume
dash.register_page(__name__, path="/", description="The home page of the web app")
# on définit le dossier et les fichiers à lire
dossier = "Dataset/Shear_transform"
fichiers_selectionnes = [
"Shear_x001-x101_y{:03d}_Rot00_transform.csv".format(i) for i in range(10, 14)
]
dash.register_page(__name__, path="/")
cache = diskcache.Cache("./cache")
background_callback_manager = DiskcacheManager(cache)
# on charge le fichier numpy
# fichiers = np.load("Dataset/npy/export.npy")
# valeurs d'échantillonage
echantillonage_x = 1
@ -97,26 +105,22 @@ mesh_card = dbc.Fade(
[
dbc.CardBody(
[
dbc.Row(
html.Div(
[
dbc.Col(
html.H2(
"3D Plot",
className="card-title",
style={"textAlign": "left"},
),
width="4",
html.H2(
"3D Plot",
className="card-title",
style={"textAlign": "left"},
),
dbc.Col(
dbc.Button(
html.I(className="bi bi-arrows-fullscreen"),
id="fullscreen-button-3dplot",
className="mb-3",
color="primary",
style={"marginBottom": "15px"},
),
dbc.Button(
html.I(className="bi bi-arrows-fullscreen"),
id="fullscreen-button-3dplot",
className="mb-3",
color="primary",
style={"marginBottom": "15px"},
),
],
style={"display": "flex", "justifyContent": "space-between"},
),
dcc.Graph(
id="3dplot",
@ -215,26 +219,22 @@ Ascan_card = dbc.Fade(
[
dbc.CardBody(
[
dbc.Row(
html.Div(
[
dbc.Col(
html.H2(
"A-scan",
className="card-title",
style={"textAlign": "left"},
),
width="4",
html.H2(
"A-scan",
className="card-title",
style={"textAlign": "left"},
),
dbc.Col(
dbc.Button(
html.I(className="bi bi-arrows-fullscreen"),
id="fullscreen-button-ascan",
className="mb-3",
color="primary",
style={"marginBottom": "15px"},
),
dbc.Button(
html.I(className="bi bi-arrows-fullscreen"),
id="fullscreen-button-ascan",
className="mb-3",
color="primary",
style={"marginBottom": "15px"},
),
],
style={"display": "flex", "justifyContent": "space-between"},
),
dcc.Graph(
id="heatmap-ascan",
@ -286,26 +286,22 @@ Bscan_card_xy = dbc.Fade(
[
dbc.CardBody(
[
dbc.Row(
html.Div(
[
dbc.Col(
html.H2(
"B-scan ZX",
className="card-title",
style={"textAlign": "left"},
),
width="4",
html.H2(
"B-scan ZX",
className="card-title",
style={"textAlign": "left"},
),
dbc.Col(
dbc.Button(
html.I(className="bi bi-arrows-fullscreen"),
id="fullscreen-button-bscan-zx",
className="mb-3",
color="primary",
style={"marginBottom": "15px"},
),
dbc.Button(
html.I(className="bi bi-arrows-fullscreen"),
id="fullscreen-button-bscan-zx",
className="mb-3",
color="primary",
style={"marginBottom": "15px"},
),
],
style={"display": "flex", "justifyContent": "space-between"},
),
dcc.Graph(
id="heatmap-bscan-zx",
@ -367,26 +363,22 @@ Bscan_card_zx = dbc.Fade(
[
dbc.CardBody(
[
dbc.Row(
html.Div(
[
dbc.Col(
html.H2(
"B-scan XY",
className="card-title",
style={"textAlign": "left"},
),
width="4",
html.H2(
"B-scan XY",
className="card-title",
style={"textAlign": "left"},
),
dbc.Col(
dbc.Button(
html.I(className="bi bi-arrows-fullscreen"),
id="fullscreen-button-bscan-xy",
className="mb-3",
color="primary",
style={"marginBottom": "15px"},
),
dbc.Button(
html.I(className="bi bi-arrows-fullscreen"),
id="fullscreen-button-bscan-xy",
className="mb-3",
color="primary",
style={"marginBottom": "15px"},
),
],
style={"display": "flex", "justifyContent": "space-between"},
),
dcc.Graph(
id="heatmap-bscan-xy",
@ -457,483 +449,4 @@ layout = html.Div(
]
)
# on défini les callbacks
# callback pour le plot 3D
@callback(
[Output("3dplot", "figure")],
[
Input("iso-slider", "value"),
Input("y-slider", "value"),
Input("store-settings", "data"),
],
[dash.dependencies.State("fade-3dplot", "is_in")],
running=[
(Output("fade-3dplot", "is_in"), False, True),
],
)
### a revoir###
def update_3dplot(iso_value, y_values, settings, is_in):
if settings["use_real_values"]:
y_min, y_max = y_values
selected_volume = volume[0:dim_x, int(y_min) : int(y_max), 0:dim_z]
X, Y, Z = [
np.load("Dataset/npy/{}-values.npy".format(i)) for i in ["x", "y", "z"]
]
else:
y_min, y_max = y_values
selected_volume = volume[0:dim_x, int(y_min) : int(y_max), 0:dim_z]
X, Y, Z = np.mgrid[
0 : selected_volume.shape[0],
0 : selected_volume.shape[1],
0 : selected_volume.shape[2],
]
fig = go.Figure(
data=go.Volume(
x=X.flatten(),
y=Y.flatten(),
z=Z.flatten(),
value=selected_volume.flatten(),
isomin=iso_value,
isomax=selected_volume.max(),
opacity=0.1,
surface_count=20,
colorscale="Jet",
)
)
return [fig]
# callback pour le plot 3D en plein écran
@callback(
Output("3dplot-fullscreen", "figure"),
[Input("iso-slider-fullscreen", "value"), Input("y-slider-fullscreen", "value")],
)
### à revoir ###
def update_3dplot_fullscreen(iso_value, y_values):
y_min, y_max = y_values
selected_volume = volume[0:dim_x, int(y_min) : int(y_max), 0:dim_z]
X, Y, Z = np.mgrid[
0 : selected_volume.shape[0],
0 : selected_volume.shape[1],
0 : selected_volume.shape[2],
]
fig = go.Figure(
data=go.Volume(
x=X.flatten(),
y=Y.flatten(),
z=Z.flatten(),
value=selected_volume.flatten(),
isomin=iso_value,
isomax=selected_volume.max(),
opacity=0.1,
surface_count=20,
colorscale="Jet",
)
)
return fig
# callback pour le A-scan
@callback(
[Output("heatmap-ascan", "figure")],
[Input("layer-slider-bscan-zx", "value"), Input("layer-slider-bscan-xy", "value")],
[dash.dependencies.State("fade-ascan", "is_in")],
running=[
(Output("fade-ascan", "is_in"), False, True),
],
prevent_initial_call=True,
)
def update_heatmap_ascan(layer, layer1, is_in):
fig = px.line(y=volume[layer - 1, :, layer1], title="A-scan")
return [fig]
# callback pour le A-scan en plein écran
@callback(
Output("heatmap-ascan-fullscreen", "figure"),
Input("layer-slider-ascan-fullscreen", "value"),
)
def update_heatmap_ascan_fullscreen(layer):
fig = px.line(y=volume[layer - 1, :, 5], title="A-scan")
return fig
# callback pour les B-scan XY
@callback(
[
Output("heatmap-bscan-zx", "figure"),
Output("store-bscan-zx-layer", "data"),
],
[Input("layer-slider-bscan-zx", "value")],
[dash.dependencies.State("fade-bscan-zx", "is_in")],
running=[
(Output("fade-bscan-xy", "is_in"), False, True),
],
prevent_initial_call=True,
)
def update_heatmap_bscan_zx(layer, is_in):
fig = px.imshow(
volume[layer - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
)
return [fig, layer]
# callback pour les B-scan ZX en plein écran
@callback(
Output("heatmap-bscan-zx-fullscreen", "figure"),
Input("layer-slider-bscan-zx-fullscreen", "value"),
)
def update_heatmap_bscan_zx_fullscreen(layer):
fig = px.imshow(
volume[layer - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
)
return fig
# callback pour les B-scan ZX
@callback(
[Output("heatmap-bscan-xy", "figure"), Output("store-bscan-xy-layer", "data")],
[Input("layer-slider-bscan-xy", "value")],
[dash.dependencies.State("fade-bscan-xy", "is_in")],
running=[
(Output("fade-bscan-zx", "is_in"), False, True),
],
prevent_initial_call=True,
)
def update_heatmap_bscan_xy(layer, is_in):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet"))
fig.update_layout(title="B-scan XY")
return [fig, layer]
# callback pour les B-scan ZX en plein écran
@callback(
Output("heatmap-bscan-xy-fullscreen", "figure"),
Input("layer-slider-bscan-xy-fullscreen", "value"),
)
def update_heatmap_bscan_xy_fullscreen(layer):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet"))
fig.update_layout(title="B-scan XY")
return fig
# callback pour le plein écran du plot 3D
@callback(
Output("modal-3dplot", "is_open"),
[Input("fullscreen-button-3dplot", "n_clicks")],
[dash.dependencies.State("modal-3dplot", "is_open")],
)
def toggle_fullscreen_3dplot(n1, is_open):
if n1:
return not is_open
return is_open
# callback pour le plein écran du A-scan
@callback(
Output("modal-ascan", "is_open"),
[Input("fullscreen-button-ascan", "n_clicks")],
[dash.dependencies.State("modal-ascan", "is_open")],
)
def toggle_fullscreen_ascan(n1, is_open):
if n1:
return not is_open
return is_open
# callback pour le plein écran du B-scan XY
@callback(
Output("modal-bscan-xy", "is_open"),
[Input("fullscreen-button-bscan-xy", "n_clicks")],
[dash.dependencies.State("modal-bscan-xy", "is_open")],
)
def toggle_fullscreen_bscan_xy(n1, is_open):
if n1:
return not is_open
return is_open
# callback pour le plein écran du B-scan ZX
@callback(
Output("modal-bscan-zx", "is_open"),
[Input("fullscreen-button-bscan-zx", "n_clicks")],
[dash.dependencies.State("modal-bscan-zx", "is_open")],
)
def toggle_fullscreen_bscan_zx(n1, is_open):
if n1:
return not is_open
return is_open
@callback(
[
Output("3dplot", "clickData"),
Output("layer-slider-bscan-xy", "value"),
Output("layer-slider-bscan-zx", "value"),
],
Input("3dplot", "clickData"),
)
def display_3dplot_click_data(clickData):
if clickData is None:
return [None, 1, 1]
bscan_xy = clickData["points"][0]["z"]
bscan_zx = clickData["points"][0]["x"]
return [clickData, bscan_xy, bscan_zx]
@callback(
[
Output("heatmap-bscan-xy", "clickData"),
Output("layer-slider-bscan-zx", "value", allow_duplicate=True),
],
[Input("heatmap-bscan-xy", "clickData")],
prevent_initial_call=True,
)
def display_bscan_xy_click_data(clickData):
if clickData is None:
return [None, 1]
bscan_zx = clickData["points"][0]["y"]
return [clickData, bscan_zx]
@callback(
[
Output("heatmap-bscan-zx", "clickData"),
Output("layer-slider-bscan-xy", "value", allow_duplicate=True),
],
[Input("heatmap-bscan-zx", "clickData")],
prevent_initial_call=True,
)
def display_bscan_zx_click_data(clickData):
if clickData is None:
return [None, 0]
bscan_xy = clickData["points"][0]["x"]
return [clickData, bscan_xy]
@callback(
[
Output("heatmap-bscan-xy", "figure", allow_duplicate=True),
Output("heatmap-bscan-zx", "figure", allow_duplicate=True),
Output("heatmap-ascan", "figure", allow_duplicate=True),
],
[Input("store-bscan-xy-layer", "data"), Input("store-bscan-zx-layer", "data")],
prevent_initial_call=True,
)
def update_bscan_layers(bscan_xy, bscan_zx):
fig = go.Figure(data=go.Heatmap(z=volume[:, :, bscan_xy], colorscale="Jet"))
fig.add_shape(
type="line",
x0=0 - 1,
y0=bscan_zx,
x1=dim_y,
y1=bscan_zx,
line=dict(color="white", width=1),
)
fig.update_layout(title="B-scan XY")
fig2 = px.imshow(
volume[bscan_zx - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
)
fig2.add_shape(
type="line",
x0=bscan_xy,
y0=0,
x1=bscan_xy,
y1=dim_y,
line=dict(color="white", width=1),
)
fig3 = px.line(y=volume[bscan_zx - 1, :, bscan_xy], title="A-scan")
return [fig, fig2, fig3]
@callback(
[Output("store-settings", "data"), Output("settings-apply", "n_clicks")],
[
Input("settings-apply", "n_clicks"),
],
[
State("use-real-values", "value"),
State("apply-filters-everywhere", "value"),
State("echantillonage-x", "value"),
State("echantillonage-y", "value"),
State("echantillonage-z", "value"),
],
prevent_initial_call=True,
)
def update_settings(
clicks,
use_real_values,
apply_filters,
echantillonage_x_value,
echantillonage_y_value,
echantillonage_z_value,
):
if clicks != None and clicks == 1:
return [
{
"use_real_values": use_real_values,
"use_filters": apply_filters,
"echantillonage_x": echantillonage_x_value,
"echantillonage_y": echantillonage_y_value,
"echantillonage_z": echantillonage_z_value,
},
0,
]
@callback(
[
Output("layer-slider-bscan-zx", "max"),
Output("layer-slider-bscan-zx", "marks"),
Output("layer-slider-bscan-xy", "max"),
Output("layer-slider-bscan-xy", "marks"),
Output("iso-slider", "min"),
Output("iso-slider", "max"),
Output("iso-slider", "marks"),
Output("y-slider", "max"),
Output("y-slider", "marks"),
Output("settings-spinner", "children"),
],
Input("store-settings", "data"),
prevent_initial_call=True,
)
def redef_data(data):
global volume, dim_x, dim_y, dim_z, X, Y, Z
volume = pre_volume[
:: data["echantillonage_x"],
:: data["echantillonage_y"],
:: data["echantillonage_z"],
]
dim_x, dim_y, dim_z = volume.shape
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
return [
dim_x - 1,
{str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 20)))},
dim_z - 1,
{str(i): str(i) for i in range(1, dim_z + 1, max(1, int(dim_z / 20)))},
volume.min(),
volume.max() / 2,
{
str(i): str(i)
for i in range(
int(volume.min()),
int(volume.max() / 2) + 1,
int((volume.max() / 2 - volume.min()) / 10),
)
},
dim_y,
{str(i): str(i) for i in range(0, int(dim_y) + 1, max(1, int(dim_y / 20)))},
"Apply",
]
"""
@callback(
[Input("store-filters", "data"), Input("store-settings", "data")],
)
def apply_filters(data, settings):
global volume
if settings["use_filters"]:
select_filtre_1 = data["select_filtre_2"]
select_filtre_2 = data["select_filtre_3"]
fs_filtre_1 = data["fs_filtre_1"]
cutoff_filtre_1 = data["cutoff_filtre_1"]
order_filtre_1 = data["order_filtre_1"]
windowsize_filtre_1 = data["windowsize_filtre_1"]
fs_filtre_2 = data["fs_filtre_2"]
cutoff_filtre_2 = data["cutoff_filtre_2"]
order_filtre_2 = data["order_filtre_2"]
windowsize_filtre_2 = data["windowsize_filtre_2"]
selec_transforme_hilbert = data["select_filtre_1"]
volume = pre_volume[
:: settings["echantillonage_x"],
:: settings["echantillonage_y"],
:: settings["echantillonage_z"],
]
data_avec_traitement = switch_case(volume, int(selec_transforme_hilbert))
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_1),
int(fs_filtre_1),
int(cutoff_filtre_1),
int(order_filtre_1),
int(windowsize_filtre_1),
)
data_avec_traitement = switch_case(
data_avec_traitement,
int(select_filtre_2),
int(fs_filtre_2),
int(cutoff_filtre_2),
int(order_filtre_2),
int(windowsize_filtre_2),
)
volume = data_avec_traitement
else:
volume = pre_volume[
:: settings["echantillonage_x"],
:: settings["echantillonage_y"],
:: settings["echantillonage_z"],
]
return None
"""
@callback(
Output("store-files", "data", allow_duplicate=True),
Input("store-files", "data"),
State("store-settings", "data"),
prevent_initial_call=True,
)
def update_files(data, settings):
global pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
if data is None or data == "":
return None
# Charger le nouveau volume
pre_volume = np.load(join("Dataset/saves", data))
print("New volume loaded:", pre_volume.shape)
# Appliquer les nouveaux paramètres d'échantillonnage
volume = pre_volume[
::settings["echantillonage_x"],
::settings["echantillonage_y"],
::settings["echantillonage_z"],
]
dim_x, dim_y, dim_z = volume.shape
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
print("Volume updated with new dimensions:", volume.shape)
# Mettre à jour les graphiques
update_3dplot(0, [0, dim_y // 2], settings, False)
update_heatmap_ascan(0, 0, False)
update_heatmap_bscan_zx(0, False)
update_heatmap_bscan_xy(0, False)
return None
get_callbacks()