diff --git a/3D_app/README.md b/3D_app/README.md index 9bda7f9..fa7d93d 100644 --- a/3D_app/README.md +++ b/3D_app/README.md @@ -10,3 +10,9 @@ * Correction des dépendances obselètes * Ajustement des sliders avec des valeurs commençant par 1 et non 0 * Changement du thème en dark + +## V3 + +* Ajout d'un menu pour naviguer entre les pages +* Ajout des popups pour afficher les graphiques en plein écran +* Ajout de la page avec les filtres pour la A-scan diff --git a/3D_app/main.py b/3D_app/main.py index 1552013..0b62c24 100644 --- a/3D_app/main.py +++ b/3D_app/main.py @@ -1,196 +1,14 @@ import dash from dash import dcc, html from dash.dependencies import Input, Output -import plotly.graph_objects as go -import numpy as np -from util import * import dash_bootstrap_components as dbc -import plotly.express as px -import plotly.io as pio - -# 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) -] - -# dossier = "Dataset/Shear_Wave_Rot00_CSV_Data" -# fichiers_selectionnes = ['Shear_x001-x101_y{:03d}_Rot00.csv'.format(i) for i in range(10, 62)] - -# on lit les fichiers et on les met dans un tableau -pre_volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes)) -volume = pre_volume[:, ::32, :] -dim_x, dim_y, dim_z = volume.shape - -X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z] - -# on défini le thème de l'application -pio.templates.default = "plotly_dark" - -# on crée le plot 3D -fig = go.Figure( - data=go.Volume( - x=X.flatten(), - y=Y.flatten(), - z=Z.flatten(), - value=volume.flatten(), - isomin=5000, - isomax=volume.max(), - opacity=0.1, # needs to be small to see through all surfaces - surface_count=20, # needs to be a large number for good volume rendering - colorscale="Jet" - ) -) - -# on défini les configurations des plots -config3DPlot = { - "toImageButtonOptions": { - "format": "svg", # one of png, svg, jpeg, webp - "filename": "3D-Plot", - "height": 1000, - "width": 1400, - "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor - }, - "displaylogo": False -} - -configAScan = { - "toImageButtonOptions": { - "format": "svg", # one of png, svg, jpeg, webp - "filename": "A-Scan", - "height": 1000, - "width": 1400, - "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor - }, - "displaylogo": False -} - -configBScanXY = { - "toImageButtonOptions": { - "format": "svg", # one of png, svg, jpeg, webp - "filename": "B-Scan XY", - "height": 1000, - "width": 1400, - "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor - }, - "displaylogo": False -} - -configBScanZX = { - "toImageButtonOptions": { - "format": "svg", # one of png, svg, jpeg, webp - "filename": "B-Scan ZX", - "height": 1000, - "width": 1400, - "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor - }, - "displaylogo": False -} # on crée l'application -app = dash.Dash(__name__, external_stylesheets=[dbc.themes.DARKLY]) +app = dash.Dash(__name__, external_stylesheets=[dbc.themes.DARKLY, dbc.icons.BOOTSTRAP], use_pages=True) -# on crée les cartes -# carte pour le plot 3D -mesh_card = dbc.Card( - [ - dbc.CardBody( - [ - dcc.Graph(id="3dplot", figure=fig, config=config3DPlot, style={"height": "411px", "marginBottom": "15px"}), # 'fig' is your 3D plotly figure - dcc.Slider( - id="iso-slider", - min=volume.min(), - max=volume.max() / 2, - value=volume.min(), - marks={ - str(i): str(i) - for i in range( - int(volume.min()), - int(volume.max() / 2) + 1, - int((volume.max() / 2 - volume.min()) / 10), - ) - }, - step=1, - ), - dcc.RangeSlider( - id="y-slider", - min=0, - max=dim_y, - value=[0, dim_y / 2], - marks={ - str(i): str(i) - for i in range(0, int(dim_y) + 1, max(1, int(dim_y / 20))) - }, - step=1, - ), - ] - ) - ] -) +print('Reloading...') -# carte pour le A-scan -Ascan_card = dbc.Card( - [ - dbc.CardBody( - [ - dcc.Graph(id="heatmap-ascan", config=configAScan, style={"marginBottom": "15px"}), # 'fig' is your 2D plotly figure - dcc.Slider( - id="layer-slider-ascan", - min=1, - max=dim_x, - value=1, - step=1, - marks={ - str(i): str(i) for i in range(1, dim_x + 1, max(1, int(dim_x / 20))) - }, - ), - ] - ) - ] -) - -# carte pour le B-scan XY -Bscan_card_xy = dbc.Card( - [ - dbc.CardBody( - [ - dcc.Graph(id="heatmap-bscan-xy", config=configBScanXY, style={"marginBottom": "15px"}), # 'fig' is your 2D plotly figure - dcc.Slider( - id="layer-slider-bscan-xy", - min=1, - max=dim_x, - value=1, - step=1, - marks={ - str(i): str(i) for i in range(1, dim_x + 1, max(1, int(dim_x / 20))) - }, - ), - ] - ) - ] -) - -# carte pour le B-scan ZX -Bscan_card_zx = dbc.Card( - [ - dbc.CardBody( - [ - dcc.Graph(id="heatmap-bscan-zx", config=configBScanZX, style={"marginBottom": "15px"}), # 'fig' is your 2D plotly figure - dcc.Slider( - id="layer-slider-bscan-zx", - min=1, - max=dim_z - 1, - value=1, - step=1, - marks={ - str(i): str(i) for i in range(1, dim_z + 1, max(1, int(dim_z / 20))) - }, - ), - ] - ) - ] -) # on lit le fichier modal.md pour le tuto with open("assets/modal.md", "r") as f: @@ -224,6 +42,32 @@ button_howto = dbc.Button( style={"textTransform": "none", "marginRight": "10px"}, ) +navmenu = html.Div( + dbc.Offcanvas( + dbc.ListGroup( + [ + dbc.Nav( + [ + dbc.NavLink( + html.Div(page["name"], className="ms-2"), + href=page["path"], + active="exact", + ) + for page in dash.page_registry.values() + if not page["path"].startswith("/fullscreen") + ], + vertical=True, + pills=True, + className="bg-dark", + ) + ] + ), + id="offcanvas-menu", + title="3D App", + is_open=False, + ), +) + # on défini la navbar nav_bar = dbc.Navbar( dbc.Container( @@ -234,15 +78,27 @@ nav_bar = dbc.Navbar( dbc.Row( [ dbc.Col( - html.A( - html.Img( - src=app.get_asset_url( - "logo_IJL couleur.png" - ), - height="100px", + [ + dbc.Button( + html.Span(className="navbar-toggler-icon"), + outline=True, + color="secondary", + id="navbar-toggler", + style={ + "marginRight": "10px", + "marginLeft": "10px", + }, ), - href="https://ijl.univ-lorraine.fr/", - ), + html.A( + html.Img( + src=app.get_asset_url( + "logo_IJL couleur.png" + ), + height="64px", + ), + href="https://ijl.univ-lorraine.fr/", + ), + ], style={"width": "min-content"}, ), dbc.Col( @@ -263,7 +119,6 @@ nav_bar = dbc.Navbar( ), dbc.Col( [ - dbc.NavbarToggler(id="navbar-toggler"), dbc.Collapse( dbc.Nav( [dbc.NavItem(button_howto), dbc.NavItem(button_gh)], @@ -273,91 +128,29 @@ nav_bar = dbc.Navbar( id="navbar-collapse", navbar=True, ), - ], align="right" + ], + align="right", ), modal_overlay, + navmenu, ], align="center", style={"width": "100%"}, ), ], fluid=True, - style={"--bs-gutter-x": "0"} + style={"--bs-gutter-x": "0"}, ), dark=True, ) # on défini le layout de l'application app.layout = dbc.Container( - [ - nav_bar, - dbc.Row([dbc.Col(Ascan_card, width=6), dbc.Col(mesh_card, width=6)], style={"margin": "8px"}), - dbc.Row([dbc.Col(Bscan_card_xy, width=6), dbc.Col(Bscan_card_zx, width=6)], style={"margin": "8px"}) - ], + [nav_bar, dash.page_container], fluid=True, ) -# on défini les callbacks -# callback pour le plot 3D -@app.callback( - Output("3dplot", "figure"), - [Input("iso-slider", "value"), Input("y-slider", "value")], -) -def update_3dplot(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 -@app.callback(Output("heatmap-ascan", "figure"), [Input("layer-slider-ascan", "value")]) -def update_heatmap_ascan(layer): - fig = px.line(y=volume[layer - 1, :, 5], title="A-scan") - return fig - -# callback pour les B-scan XY -@app.callback( - Output("heatmap-bscan-xy", "figure"), [Input("layer-slider-bscan-xy", "value")] -) -def update_heatmap_bscan_xy(layer): - fig = px.imshow( - volume[layer - 1, :, :], - color_continuous_scale="Jet", - aspect="auto", - title="B-scan XY", - ) - - return fig - -# callback pour les B-scan ZX -@app.callback( - Output("heatmap-bscan-zx", "figure"), [Input("layer-slider-bscan-zx", "value")] -) -def update_heatmap_bscan_zx(layer): - fig = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet")) - - return fig - # callback pour le modal @app.callback( Output("modal", "is_open"), @@ -370,6 +163,18 @@ def toggle_modal(n1, n2, 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 + + # on lance l'application if __name__ == "__main__": app.run(debug=True, port="8051") diff --git a/3D_app/pages/__pycache__/ascan.cpython-312.pyc b/3D_app/pages/__pycache__/ascan.cpython-312.pyc new file mode 100644 index 0000000..1c0fa33 Binary files /dev/null and b/3D_app/pages/__pycache__/ascan.cpython-312.pyc differ diff --git a/3D_app/pages/__pycache__/home.cpython-312.pyc b/3D_app/pages/__pycache__/home.cpython-312.pyc new file mode 100644 index 0000000..e18a095 Binary files /dev/null and b/3D_app/pages/__pycache__/home.cpython-312.pyc differ diff --git a/3D_app/pages/ascan.py b/3D_app/pages/ascan.py new file mode 100644 index 0000000..6e263b1 --- /dev/null +++ b/3D_app/pages/ascan.py @@ -0,0 +1,78 @@ +import dash +from dash import html, callback, Input, Output, dcc +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 * + +dash.register_page(__name__, path="/ascan", title='A-Scan filters', name='A-Scan filters') + +# 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) +] + +# dossier = "Dataset/Shear_Wave_Rot00_CSV_Data" +# fichiers_selectionnes = ['Shear_x001-x101_y{:03d}_Rot00.csv'.format(i) for i in range(10, 62)] + +# on lit les fichiers et on les met dans un tableau +pre_volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes)) +volume = pre_volume[:, ::32, :] +dim_x, dim_y, dim_z = volume.shape + +X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z] + +configAScan = { + "toImageButtonOptions": { + "format": "svg", # one of png, svg, jpeg, webp + "filename": "A-Scan", + "height": 1000, + "width": 1400, + "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor + }, + "displaylogo": False, +} + +layout = html.Div( + [ + dbc.Select( + id="select-ascan-filter", + options=[ + {"label": "Option 1", "value": "1"}, + {"label": "Option 2", "value": "2"}, + ], + style={"margin-bottom": "15px"}, + ), + dcc.Graph( + id="heatmap-ascan-solo", + config=configAScan, + style={"marginBottom": "15px"}, + ), # 'fig' is your 2D plotly figure + dcc.Slider( + id="layer-slider-ascan-solo", + min=1, + max=dim_x, + value=1, + step=1, + marks={ + str(i): str(i) for i in range(1, dim_x + 1, max(1, int(dim_x / 20))) + }, + ), + ], + style={"padding": "20px"}, +) + + +# callback to update the heatmap +@callback( + Output("heatmap-ascan-solo", "figure"), + [Input("select-ascan-filter", "value"), Input("layer-slider-ascan-solo", "value")], +) +def update_heatmap_ascan(value, layer): + # TODO: implement the filter + + fig = px.line(y=volume[layer - 1, :, 5], title="A-scan") + return fig diff --git a/3D_app/pages/home.py b/3D_app/pages/home.py new file mode 100644 index 0000000..66b687f --- /dev/null +++ b/3D_app/pages/home.py @@ -0,0 +1,620 @@ +import dash +from dash import html, callback, Input, Output, dcc +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 * + +dash.register_page(__name__, path="/") + +# 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) +] + +# dossier = "Dataset/Shear_Wave_Rot00_CSV_Data" +# fichiers_selectionnes = ['Shear_x001-x101_y{:03d}_Rot00.csv'.format(i) for i in range(10, 62)] + +# on lit les fichiers et on les met dans un tableau +pre_volume = np.array(lire_fichier_csv(dossier, fichiers_selectionnes)) +volume = pre_volume[:, ::32, :] +dim_x, dim_y, dim_z = volume.shape + +X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z] + +# on défini le thème de l'application +pio.templates.default = "plotly_dark" + +# on crée le plot 3D +fig = go.Figure( + data=go.Volume( + x=X.flatten(), + y=Y.flatten(), + z=Z.flatten(), + value=volume.flatten(), + isomin=5000, + isomax=volume.max(), + opacity=0.1, # needs to be small to see through all surfaces + surface_count=20, # needs to be a large number for good volume rendering + colorscale="Jet", + ) +) + +# on défini les configurations des plots +config3DPlot = { + "toImageButtonOptions": { + "format": "svg", # one of png, svg, jpeg, webp + "filename": "3D-Plot", + "height": 1000, + "width": 1400, + "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor + }, + "displaylogo": False, +} + +configAScan = { + "toImageButtonOptions": { + "format": "svg", # one of png, svg, jpeg, webp + "filename": "A-Scan", + "height": 1000, + "width": 1400, + "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor + }, + "displaylogo": False, +} + +configBScanXY = { + "toImageButtonOptions": { + "format": "svg", # one of png, svg, jpeg, webp + "filename": "B-Scan XY", + "height": 1000, + "width": 1400, + "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor + }, + "displaylogo": False, +} + +configBScanZX = { + "toImageButtonOptions": { + "format": "svg", # one of png, svg, jpeg, webp + "filename": "B-Scan ZX", + "height": 1000, + "width": 1400, + "scale": 1, # Multiply title/legend/axis/canvas sizes by this factor + }, + "displaylogo": False, +} + + +# on crée les cartes +# carte pour le plot 3D +mesh_card = dbc.Card( + [ + dbc.CardBody( + [ + dbc.Row( + [ + dbc.Col( + html.H2( + "3D Plot", + className="card-title", + style={"textAlign": "left"}, + ), + width="4", + ), + dbc.Col( + dbc.Button( + html.I(className="bi bi-arrows-fullscreen"), + id="fullscreen-button-3dplot", + className="mb-3", + color="primary", + style={"marginBottom": "15px"}, + ), + ), + ], + ), + dcc.Graph( + id="3dplot", + figure=fig, + config=config3DPlot, + style={"height": "411px", "marginBottom": "15px"}, + ), # 'fig' is your 3D plotly figure + dcc.Slider( + id="iso-slider", + min=volume.min(), + max=volume.max() / 2, + value=volume.min(), + marks={ + str(i): str(i) + for i in range( + int(volume.min()), + int(volume.max() / 2) + 1, + int((volume.max() / 2 - volume.min()) / 10), + ) + }, + step=1, + ), + dcc.RangeSlider( + id="y-slider", + min=0, + max=dim_y, + value=[0, dim_y / 2], + marks={ + str(i): str(i) + for i in range(0, int(dim_y) + 1, max(1, int(dim_y / 20))) + }, + step=1, + ), + dbc.Modal( + [ + dbc.ModalHeader(dbc.ModalTitle("3D Plot")), + dbc.ModalBody( + [ + dcc.Graph( + id="3dplot-fullscreen", + figure=fig, + config=config3DPlot, + style={"marginBottom": "15px", "height": "90%"}, + ), # 'fig' is your 3D plotly figure + dcc.Slider( + id="iso-slider-fullscreen", + min=volume.min(), + max=volume.max() / 2, + value=volume.min(), + marks={ + str(i): str(i) + for i in range( + int(volume.min()), + int(volume.max() / 2) + 1, + int((volume.max() / 2 - volume.min()) / 10), + ) + }, + step=1, + ), + dcc.RangeSlider( + id="y-slider-fullscreen", + min=0, + max=dim_y, + value=[0, dim_y / 2], + marks={ + str(i): str(i) + for i in range( + 0, int(dim_y) + 1, max(1, int(dim_y / 20)) + ) + }, + step=1, + ), + ] + ), + ], + id="modal-3dplot", + fullscreen=True, + ), + ] + ) + ] +) + +# carte pour le A-scan +Ascan_card = dbc.Card( + [ + dbc.CardBody( + [ + dbc.Row( + [ + dbc.Col( + html.H2( + "A-scan", + className="card-title", + style={"textAlign": "left"}, + ), + width="4", + ), + dbc.Col( + dbc.Button( + html.I(className="bi bi-arrows-fullscreen"), + id="fullscreen-button-ascan", + className="mb-3", + color="primary", + style={"marginBottom": "15px"}, + ), + ), + ], + ), + dcc.Graph( + id="heatmap-ascan", + config=configAScan, + style={"marginBottom": "15px"}, + ), # 'fig' is your 2D plotly figure + dcc.Slider( + id="layer-slider-ascan", + min=1, + max=dim_x, + value=1, + step=1, + marks={ + str(i): str(i) + for i in range(1, dim_x + 1, max(1, int(dim_x / 20))) + }, + ), + dbc.Modal( + [ + dbc.ModalHeader(dbc.ModalTitle("A-Scan")), + dbc.ModalBody( + [ + dcc.Graph( + id="heatmap-ascan-fullscreen", + config=configAScan, + style={"marginBottom": "15px"}, + ), # 'fig' is your 2D plotly figure + dcc.Slider( + id="layer-slider-ascan-fullscreen", + min=1, + max=dim_x, + value=1, + step=1, + marks={ + str(i): str(i) + for i in range( + 1, dim_x + 1, max(1, int(dim_x / 20)) + ) + }, + ), + ] + ), + ], + id="modal-ascan", + fullscreen=True, + ), + ] + ) + ] +) + +# carte pour le B-scan XY +Bscan_card_xy = dbc.Card( + [ + dbc.CardBody( + [ + dbc.Row( + [ + dbc.Col( + html.H2( + "B-scan XY", + className="card-title", + style={"textAlign": "left"}, + ), + width="4", + ), + dbc.Col( + dbc.Button( + html.I(className="bi bi-arrows-fullscreen"), + id="fullscreen-button-bscan-xy", + className="mb-3", + color="primary", + style={"marginBottom": "15px"}, + ), + ), + ], + ), + dcc.Graph( + id="heatmap-bscan-xy", + config=configBScanXY, + style={"marginBottom": "15px"}, + ), # 'fig' is your 2D plotly figure + dcc.Slider( + id="layer-slider-bscan-xy", + min=1, + max=dim_x, + value=1, + step=1, + marks={ + str(i): str(i) + for i in range(1, dim_x + 1, max(1, int(dim_x / 20))) + }, + ), + dbc.Modal( + [ + dbc.ModalHeader(dbc.ModalTitle("B-Scan XY")), + dbc.ModalBody( + [ + dcc.Graph( + id="heatmap-bscan-xy-fullscreen", + config=configBScanXY, + style={"marginBottom": "15px"}, + ), # 'fig' is your 2D plotly figure + dcc.Slider( + id="layer-slider-bscan-xy-fullscreen", + min=1, + max=dim_x, + value=1, + step=1, + marks={ + str(i): str(i) + for i in range( + 1, dim_x + 1, max(1, int(dim_x / 20)) + ) + }, + ), + ] + ), + ], + id="modal-bscan-xy", + fullscreen=True, + ), + ] + ) + ] +) + +# carte pour le B-scan ZX +Bscan_card_zx = dbc.Card( + [ + dbc.CardBody( + [ + dbc.Row( + [ + dbc.Col( + html.H2( + "B-scan ZX", + className="card-title", + style={"textAlign": "left"}, + ), + width="4", + ), + dbc.Col( + dbc.Button( + html.I(className="bi bi-arrows-fullscreen"), + id="fullscreen-button-bscan-zx", + className="mb-3", + color="primary", + style={"marginBottom": "15px"}, + ), + ), + ], + ), + dcc.Graph( + id="heatmap-bscan-zx", + config=configBScanZX, + style={"marginBottom": "15px"}, + ), # 'fig' is your 2D plotly figure + dcc.Slider( + id="layer-slider-bscan-zx", + min=1, + max=dim_z - 1, + value=1, + step=1, + marks={ + str(i): str(i) + for i in range(1, dim_z + 1, max(1, int(dim_z / 20))) + }, + ), + dbc.Modal( + [ + dbc.ModalHeader(dbc.ModalTitle("B-Scan XY")), + dbc.ModalBody( + [ + dcc.Graph( + id="heatmap-bscan-zx-fullscreen", + config=configBScanZX, + style={"marginBottom": "15px"}, + ), # 'fig' is your 2D plotly figure + dcc.Slider( + id="layer-slider-bscan-zx-fullscreen", + min=1, + max=dim_z - 1, + value=1, + step=1, + marks={ + str(i): str(i) + for i in range( + 1, dim_z + 1, max(1, int(dim_z / 20)) + ) + }, + ), + ], + ), + ], + id="modal-bscan-xy", + fullscreen=True, + ), + ] + ) + ] +) + +layout = html.Div( + [ + dbc.Row( + [dbc.Col(Ascan_card, width=6), dbc.Col(mesh_card, width=6)], + style={"margin": "8px"}, + ), + dbc.Row( + [dbc.Col(Bscan_card_xy, width=6), dbc.Col(Bscan_card_zx, width=6)], + style={"margin": "8px"}, + ), + ] +) + + +# on défini les callbacks +# callback pour le plot 3D +@callback( + Output("3dplot", "figure"), + [Input("iso-slider", "value"), Input("y-slider", "value")], +) +def update_3dplot(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 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"), + Input("layer-slider-ascan", "value"), +) +def update_heatmap_ascan(layer): + fig = px.line(y=volume[layer - 1, :, 5], 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-xy", "figure"), Input("layer-slider-bscan-xy", "value")) +def update_heatmap_bscan_xy(layer): + fig = px.imshow( + volume[layer - 1, :, :], + color_continuous_scale="Jet", + aspect="auto", + title="B-scan XY", + ) + + return fig + + +# callback pour les B-scan XY 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 = px.imshow( + volume[layer - 1, :, :], + color_continuous_scale="Jet", + aspect="auto", + title="B-scan XY", + ) + + return fig + + +# callback pour les B-scan ZX +@callback(Output("heatmap-bscan-zx", "figure"), Input("layer-slider-bscan-zx", "value")) +def update_heatmap_bscan_zx(layer): + fig = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet")) + + return fig + + +# 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 = go.Figure(data=go.Heatmap(z=volume[:, :, layer], colorscale="Jet")) + + 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 +