V3 de la 3D App
This commit is contained in:
@ -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
|
||||
|
325
3D_app/main.py
325
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")
|
||||
|
BIN
3D_app/pages/__pycache__/ascan.cpython-312.pyc
Normal file
BIN
3D_app/pages/__pycache__/ascan.cpython-312.pyc
Normal file
Binary file not shown.
BIN
3D_app/pages/__pycache__/home.cpython-312.pyc
Normal file
BIN
3D_app/pages/__pycache__/home.cpython-312.pyc
Normal file
Binary file not shown.
78
3D_app/pages/ascan.py
Normal file
78
3D_app/pages/ascan.py
Normal file
@ -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
|
620
3D_app/pages/home.py
Normal file
620
3D_app/pages/home.py
Normal file
@ -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
|
||||
|
Reference in New Issue
Block a user