From f611abde66f8efb0955789c4df17dfe77641b61c Mon Sep 17 00:00:00 2001 From: Le Stagiaire Date: Fri, 14 Jun 2024 11:27:17 +0200 Subject: [PATCH] feat: Separate GUI callbacks for improved code readability chore: Updated save/open function --- 3D_app/README.md | 6 + 3D_app/assets/modal.md | 19 +- 3D_app/callbacks/ascan.py | 313 +++++++++++++++++++ 3D_app/callbacks/gng.py | 82 +++++ 3D_app/callbacks/home.py | 532 +++++++++++++++++++++++++++++++++ 3D_app/callbacks/main.py | 120 ++++++++ 3D_app/main.py | 121 +------- 3D_app/pages/ascan.py | 363 ++++------------------ 3D_app/pages/gng.py | 87 +----- 3D_app/pages/home.py | 613 ++++---------------------------------- 10 files changed, 1203 insertions(+), 1053 deletions(-) create mode 100644 3D_app/callbacks/ascan.py create mode 100644 3D_app/callbacks/gng.py create mode 100644 3D_app/callbacks/home.py create mode 100644 3D_app/callbacks/main.py diff --git a/3D_app/README.md b/3D_app/README.md index 143835b..cc0aa84 100644 --- a/3D_app/README.md +++ b/3D_app/README.md @@ -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 diff --git a/3D_app/assets/modal.md b/3D_app/assets/modal.md index 7e7cbae..5681170 100644 --- a/3D_app/assets/modal.md +++ b/3D_app/assets/modal.md @@ -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 diff --git a/3D_app/callbacks/ascan.py b/3D_app/callbacks/ascan.py new file mode 100644 index 0000000..65da7c5 --- /dev/null +++ b/3D_app/callbacks/ascan.py @@ -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] diff --git a/3D_app/callbacks/gng.py b/3D_app/callbacks/gng.py new file mode 100644 index 0000000..47a2670 --- /dev/null +++ b/3D_app/callbacks/gng.py @@ -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)] diff --git a/3D_app/callbacks/home.py b/3D_app/callbacks/home.py new file mode 100644 index 0000000..04c7c3a --- /dev/null +++ b/3D_app/callbacks/home.py @@ -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 diff --git a/3D_app/callbacks/main.py b/3D_app/callbacks/main.py new file mode 100644 index 0000000..e1b3a04 --- /dev/null +++ b/3D_app/callbacks/main.py @@ -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}, + ] + diff --git a/3D_app/main.py b/3D_app/main.py index 928200d..31f0f65 100644 --- a/3D_app/main.py +++ b/3D_app/main.py @@ -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) \ No newline at end of file diff --git a/3D_app/pages/ascan.py b/3D_app/pages/ascan.py index 4b16907..92cad54 100644 --- a/3D_app/pages/ascan.py +++ b/3D_app/pages/ascan.py @@ -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() diff --git a/3D_app/pages/gng.py b/3D_app/pages/gng.py index 6238384..ed9666a 100644 --- a/3D_app/pages/gng.py +++ b/3D_app/pages/gng.py @@ -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() \ No newline at end of file diff --git a/3D_app/pages/home.py b/3D_app/pages/home.py index 2cbe34f..029362d 100644 --- a/3D_app/pages/home.py +++ b/3D_app/pages/home.py @@ -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() \ No newline at end of file