feat: Added ElectronJS app to display the app

feat: Removed fullscreen dialogs to display them in popup window
This commit is contained in:
2024-06-28 13:42:41 +02:00
parent bdbb75cca8
commit 4b7f1f301e
26 changed files with 7512 additions and 570 deletions

BIN
3D_app/assets/settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

View File

@ -1,4 +1,5 @@
from dash import State, Output, Input, callback
from tkinter import NONE
from dash import State, Output, Input, callback, clientside_callback
import dash
import numpy as np
import plotly.graph_objects as go
@ -74,50 +75,19 @@ def get_callbacks():
)
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"),
],
# callback pour le plein écran du plot 3D
clientside_callback(
"""
function toggle_fullscreen_3dplot(n1) {
if (n1) {
window.open("fullscreen/3dplot", "", "width=800,height=600,popup=true");
}
}
""",
Output("js", "children", allow_duplicate=True),
[Input("fullscreen-button-3dplot", "n_clicks")],
prevent_initial_call=True,
)
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 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 les paramètres du plot 3D
@callback(
@ -152,8 +122,6 @@ def get_callbacks():
[
Output("iso-slider-container", "children"),
Output("y-slider-container", "children"),
Output("iso-slider-fullscreen-container", "children"),
Output("y-slider-fullscreen-container", "children"),
],
Input("3dplot-settings", "data"),
)
@ -197,47 +165,8 @@ def get_callbacks():
),
]
)
iso_slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Iso value: "), width="auto"),
dbc.Col(
dcc.Slider(
id="iso-slider-fullscreen",
min=0,
max=volume.max() / 2,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(
0,
int(volume.max() / 2) + 1,
int((volume.max() / 2) / 20),
)
},
)
),
]
)
y_slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Y crop: "), width="auto"),
dbc.Col(
dcc.RangeSlider(
id="y-slider-fullscreen",
min=0,
max=dim_y,
value=[0, dim_y],
marks={
str(i): str(i)
for i in range(0, dim_y + 1, max(1, int(dim_y / 20)))
},
)
),
]
)
if data is None:
return [None, None, None, None]
return [None, None]
else:
if (
data["card_settings"] is None
@ -246,22 +175,10 @@ def get_callbacks():
iso_slider = None
if data["card_settings"] is None or "y_slider" not in data["card_settings"]:
y_slider = None
if (
data["fullscreen_settings"] is None
or "iso_slider" not in data["fullscreen_settings"]
):
iso_slider_fullscreen = None
if (
data["fullscreen_settings"] is None
or "y_slider" not in data["fullscreen_settings"]
):
y_slider_fullscreen = None
return [
iso_slider,
y_slider,
iso_slider_fullscreen,
y_slider_fullscreen,
]
# ----------------------------------------------------------------------
@ -295,40 +212,19 @@ def get_callbacks():
return [fig, True]
# callback pour le A-scan en plein écran
@callback(
Output("heatmap-ascan-fullscreen", "figure"),
[
Input("layer-slider-x-ascan-fullscreen", "value"),
Input("layer-slider-z-ascan-fullscreen", "value"),
Input("crop-slider-fullscreen", "value"),
],
State("store-settings", "data"),
)
def update_heatmap_ascan_fullscreen(layer_x, layer_z, crop, settings):
y_min, y_max = crop or [0, dim_y]
layer_x = layer_x or 0
layer_z = layer_z or 0
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = px.line(
y=data[layer_x - 1, int(y_min) : int(y_max), layer_z], title="A-scan"
)
return fig
# callback pour le plein écran du A-scan
@callback(
Output("modal-ascan", "is_open"),
# callback pour le plein écran du plot 3D
clientside_callback(
"""
function toggle_fullscreen_ascant(n1) {
if (n1) {
window.open("fullscreen/ascan", "", "width=800,height=600,popup=true");
}
}
""",
Output("js", "children", allow_duplicate=True),
[Input("fullscreen-button-ascan", "n_clicks")],
[dash.dependencies.State("modal-ascan", "is_open")],
prevent_initial_call=True,
)
def toggle_fullscreen_ascan(n1, is_open):
if n1:
return not is_open
return is_open
# callback pour les paramètres du A-scan
@callback(
@ -362,9 +258,6 @@ def get_callbacks():
@callback(
[
Output("crop-slider-container", "children"),
Output("layer-slider-x-ascan-fullscreen-container", "children"),
Output("layer-slider-z-ascan-fullscreen-container", "children"),
Output("crop-slider-fullscreen-container", "children"),
],
Input("ascan-settings", "data"),
)
@ -390,92 +283,16 @@ def get_callbacks():
),
]
)
slider_x_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Layer X: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-x-ascan-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(0, dim_x, max(1, int(dim_x / 50)))
},
)
),
]
)
slider_z_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Layer Z: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-z-ascan-fullscreen",
min=1,
max=dim_z - 1,
value=1,
marks={
str(i): str(i)
for i in range(1, dim_z - 1, max(1, int(dim_z / 20)))
},
step=1,
)
),
]
)
crop_slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Crop: "), width="auto"),
dbc.Col(
dcc.RangeSlider(
id="crop-slider-fullscreen",
min=0,
max=dim_y,
value=[0, dim_y],
marks={
str(i): str(i)
for i in range(
0,
dim_y + 1,
max(1, int(dim_y / 20)),
)
},
step=1,
)
),
]
)
if data is None:
return [None, None, None, None]
return [None]
else:
if (
data["card_settings"] is None
or "crop_slider" not in data["card_settings"]
):
crop_slider = None
if (
data["fullscreen_settings"] is None
or "layer_slider_x" not in data["fullscreen_settings"]
):
slider_x_fullscreen = None
if (
data["fullscreen_settings"] is None
or "layer_slider_z" not in data["fullscreen_settings"]
):
slider_z_fullscreen = None
if (
data["fullscreen_settings"] is None
or "crop_slider" not in data["fullscreen_settings"]
):
crop_slider_fullscreen = None
return [
crop_slider,
slider_x_fullscreen,
slider_z_fullscreen,
crop_slider_fullscreen,
]
# -------------------------------------------------------------------------
@ -512,37 +329,19 @@ def get_callbacks():
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"),
State("store-settings", "data"),
)
def update_heatmap_bscan_zx_fullscreen(layer, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = px.imshow(
data[layer - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
)
return fig
# callback pour le plein écran du B-scan ZX
@callback(
Output("modal-bscan-zx", "is_open"),
clientside_callback(
"""
function toggle_fullscreen_bscan_zx(n1) {
if (n1) {
window.open("fullscreen/bscan-zx", "", "width=800,height=600,popup=true");
}
}
""",
Output("js", "children", allow_duplicate=True),
[Input("fullscreen-button-bscan-zx", "n_clicks")],
[dash.dependencies.State("modal-bscan-zx", "is_open")],
prevent_initial_call=True,
)
def toggle_fullscreen_bscan_zx(n1, is_open):
if n1:
return not is_open
return is_open
# callback pour les paramètres du B-scan ZX
@callback(
@ -576,7 +375,6 @@ def get_callbacks():
@callback(
[
Output("layer-slider-bscan-zx-container", "children"),
Output("layer-slider-bscan-zx-fullscreen-container", "children"),
],
Input("bscan-zx-settings", "data"),
)
@ -599,56 +397,14 @@ def get_callbacks():
),
]
)
x_slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("X layer: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-bscan-zx-fullscreen",
min=0,
max=dim_z,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(0, dim_z, max(1, int(dim_z / 50)))
},
)
),
]
)
y_slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Y layer: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-bscan-xy-fullscreen",
min=0,
max=dim_z,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(0, dim_z, max(1, int(dim_z / 50)))
},
)
),
]
)
if data is None:
return [None, None]
return [None]
else:
if data["card_settings"] is None or "x_slider" not in data["card_settings"]:
slider = None
if (
data["fullscreen_settings"] is None
or "layer_slider" not in data["fullscreen_settings"]
):
slider_fullscreen = None
return [
slider,
slider_fullscreen,
]
# -------------------------------------------------------------------------
@ -682,34 +438,20 @@ def get_callbacks():
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"),
State("store-settings", "data"),
)
def update_heatmap_bscan_xy_fullscreen(layer, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = go.Figure(data=go.Heatmap(z=data[:, :, layer], colorscale="Jet"))
fig.update_layout(title="B-scan XY")
return fig
# callback pour le plein écran du B-scan XY
@callback(
Output("modal-bscan-xy", "is_open"),
clientside_callback(
"""
function toggle_fullscreen_bscan_xy(n1) {
if (n1) {
window.open("fullscreen/bscan-xy", "", "width=800,height=600,popup=true");
}
}
""",
Output("js", "children", allow_duplicate=True),
[Input("fullscreen-button-bscan-xy", "n_clicks")],
[dash.dependencies.State("modal-bscan-xy", "is_open")],
prevent_initial_call=True,
)
def toggle_fullscreen_bscan_xy(n1, is_open):
if n1:
return not is_open
return is_open
@callback(
[
@ -758,7 +500,6 @@ def get_callbacks():
@callback(
[
Output("layer-slider-bscan-xy-container", "children"),
Output("layer-slider-bscan-xy-fullscreen-container", "children"),
],
Input("bscan-xy-settings", "data"),
)
@ -781,56 +522,14 @@ def get_callbacks():
),
]
)
x_slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("X layer: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-bscan-xy-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(0, dim_x, max(1, int(dim_x / 50)))
},
)
),
]
)
y_slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Y layer: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-bscan-zx-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(0, dim_x, max(1, int(dim_x / 50)))
},
)
),
]
)
if data is None:
return [None, None]
return [None]
else:
if data["card_settings"] is None or "x_slider" not in data["card_settings"]:
slider = None
if (
data["fullscreen_settings"] is None
or "layer_slider" not in data["fullscreen_settings"]
):
slider_fullscreen = None
return [
slider,
slider_fullscreen,
]
# ---------------------------------------------------------------------------------
@ -1107,9 +806,9 @@ def get_callbacks():
# Mettre à jour les graphiques
update_3dplot(0, [0, dim_y // 2], settings, False)
update_heatmap_ascan(0, 0, False, settings)
update_heatmap_bscan_zx(0, False, settings)
update_heatmap_bscan_xy(0, False, settings)
update_heatmap_ascan(0, 0, False, settings) # type: ignore
update_heatmap_bscan_zx(0, False, settings) # type: ignore
update_heatmap_bscan_xy(0, False, settings) # type: ignore
return None

View File

@ -4,6 +4,7 @@ from os import listdir
from os.path import isfile, join
import dash_bootstrap_components as dbc
def get_callbacks():
# callback pour le modal
@callback(
@ -16,7 +17,6 @@ def get_callbacks():
return not is_open
return is_open
@callback(
Output("settings-modal", "is_open"),
[Input("settings-open", "n_clicks"), Input("settings-close", "n_clicks")],
@ -27,7 +27,6 @@ def get_callbacks():
return not is_open
return is_open
# callback pour le navmenu
@callback(
Output("offcanvas-menu", "is_open"),
@ -39,10 +38,13 @@ def get_callbacks():
return not is_open
return is_open
@callback(
Output("open-modal", "is_open"),
[Input("open-button", "n_clicks"), Input("open-close", "n_clicks"), Input("open-refresh", "n_clicks")],
[
Input("open-button", "n_clicks"),
Input("open-close", "n_clicks"),
Input("open-refresh", "n_clicks"),
],
[dash.dependencies.State("open-modal", "is_open")],
)
def toggle_open(n1, n2, n3, is_open):
@ -52,7 +54,6 @@ def get_callbacks():
return True
return is_open
@callback(
Output("save-modal", "is_open"),
[
@ -67,7 +68,6 @@ def get_callbacks():
return not is_open
return is_open
@callback(
Output("file-list", "children"),
[Input("open-refresh", "n_clicks")],
@ -85,7 +85,6 @@ def get_callbacks():
if isfile(join("Dataset/saves", file))
]
@callback(
[
Output("open-modal", "is_open", allow_duplicate=True),
@ -105,7 +104,6 @@ def get_callbacks():
filename = filenames[file_index["index"]]
return [False, filename, f"Opened file: {filename}"]
@callback(
Output("save-format", "options"),
[Input("store-filters", "data")],
@ -121,3 +119,11 @@ def get_callbacks():
{"label": "Save filtered dataset", "value": "filt", "disabled": True},
]
@callback(
Output("navbar", "style"),
Input("loc", "pathname"),
)
def hide_navbar(pathname):
if not str.startswith(pathname, "/fullscreen"):
return {"display": "block"}
return {"display": "none"}

View File

@ -1,7 +1,7 @@
import dash
from dash import dcc, html, ALL, DiskcacheManager
import dash_bootstrap_components as dbc
from os import listdir, mkdir, path
from os import listdir, mkdir
from os.path import isfile, join
import diskcache
from json import load
@ -69,7 +69,7 @@ modal_overlay = dbc.Modal(
modal_settings = dbc.Modal(
[
dbc.ModalHeader("Settings"),
dbc.ModalHeader(dbc.ModalTitle("Settings")),
dbc.ModalBody(
[
dbc.Switch(
@ -146,7 +146,7 @@ modal_settings = dbc.Modal(
modal_open = dbc.Modal(
[
dbc.ModalHeader("Open a file"),
dbc.ModalHeader(dbc.ModalTitle("Open a file")),
dbc.ModalBody(
[
dbc.ListGroup(
@ -177,7 +177,7 @@ modal_open = dbc.Modal(
modal_save = dbc.Modal(
[
dbc.ModalHeader("Save a file"),
dbc.ModalHeader(dbc.ModalTitle("Save a file")),
dbc.ModalBody(
[
dbc.Input(id="save-input", placeholder="Filename"),
@ -383,6 +383,8 @@ nav_bar = dbc.Navbar(
style={"--bs-gutter-x": "0"},
),
dark=True,
style={"display": "none"},
id="navbar",
)
# on défini le layout de l'application
@ -408,8 +410,10 @@ app.layout = dbc.Container(
dcc.Store(id="3dplot-settings"),
dcc.Store(id="bscan-zx-settings"),
dcc.Store(id="bscan-xy-settings"),
html.Div(id="js", hidden=True),
],
id="app-container",
style={"paddingLeft": "0 !important", "paddingRight": "0 !important"},
fluid=True,
)
@ -418,5 +422,5 @@ get_callbacks()
# on lance l'application
if __name__ == "__main__":
app.run(
debug=config["debug"] or False, port=config["port"] or "8051", threaded=True
debug=config["debug"] or False, dev_tools_ui=config['debug'] or False, port=config["port"] or "8051", threaded=True
)

View File

@ -0,0 +1,194 @@
from dash import html, dcc, callback, Output, Input, clientside_callback
import dash_bootstrap_components as dbc
import numpy as np
import plotly.graph_objects as go
import plotly.io as pio
import dash
from callbacks.home import pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
dash.register_page(
__name__,
path="/fullscreen/3dplot",
title="3D Plot",
)
# 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,
}
layout = html.Div(
[
html.Div(id="3dplot-js", hidden=True),
dbc.Spinner(id="loading-3dplot", color="primary", fullscreen=True, fullscreen_style={"backgroundColor": "var(--bs-body-bg)"}),
dcc.Graph(
id="3dplot-fullscreen",
figure=fig,
config=config3DPlot,
style={"marginBottom": "15px", "height": "85vh"},
), # 'fig' is your 3D plotly figure
html.Div(
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()) / 20),
)
},
step=1,
),
id="iso-slider-fullscreen-container",
),
html.Div(
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 / 50)),
)
},
step=1,
),
id="y-slider-fullscreen-container",
),
]
)
# callback pour le plot 3D en plein écran
@callback(
[Output("3dplot-fullscreen", "figure"), Output("loading-3dplot", "children")],
[
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, html.Div()]
@callback(
[
Output("iso-slider-fullscreen-container", "children"),
Output("y-slider-fullscreen-container", "children"),
],
Input("3dplot-settings", "data"),
)
def update_3dplot_sliders(data):
print(data)
iso_slider = dbc.Row(
[
dbc.Col(html.Span("Iso value: "), width="auto"),
dbc.Col(
dcc.Slider(
id="iso-slider-fullscreen",
min=0,
max=volume.max() / 2,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(
0,
int(volume.max() / 2) + 1,
int((volume.max() / 2) / 20),
)
},
)
),
]
)
y_slider = dbc.Row(
[
dbc.Col(html.Span("Y crop: "), width="auto"),
dbc.Col(
dcc.RangeSlider(
id="y-slider-fullscreen",
min=0,
max=dim_y,
value=[0, dim_y],
marks={
str(i): str(i)
for i in range(0, dim_y + 1, max(1, int(dim_y / 20)))
},
)
),
]
)
if data is None:
return [None, None]
else:
if (
data["fullscreen_settings"] is None
or "iso_slider" not in data["fullscreen_settings"]
):
iso_slider = None
if (
data["fullscreen_settings"] is None
or "y_slider" not in data["fullscreen_settings"]
):
y_slider = None
return [
iso_slider,
y_slider,
]

View File

@ -0,0 +1,199 @@
import dash
from dash import dcc, html, Input, Output, State, callback
import dash_bootstrap_components as dbc
import plotly.express as px
from callbacks.home import pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
dash.register_page(__name__, path="/fullscreen/ascan", title="A-Scan")
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.Spinner(
id="loading-ascan",
color="primary",
fullscreen=True,
fullscreen_style={"backgroundColor": "var(--bs-body-bg)"},
),
dcc.Graph(
id="heatmap-ascan-fullscreen",
config=configAScan,
style={"marginBottom": "15px", "height": "85vh"},
), # 'fig' is your 2D plotly figure
html.Div(
dcc.Slider(
id="layer-slider-x-ascan-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(
0,
dim_x,
max(1, int(dim_x / 50)),
)
},
),
id="layer-slider-x-ascan-fullscreen-container",
),
html.Div(
dcc.Slider(
id="layer-slider-z-ascan-fullscreen",
min=1,
max=dim_z,
value=1,
step=1,
marks={
str(i): str(i)
for i in range(
1,
dim_z,
max(1, int(dim_z / 20)),
)
},
),
id="layer-slider-z-ascan-fullscreen-container",
),
html.Div(
dcc.RangeSlider(
id="crop-slider-fullscreen",
min=0,
max=dim_y,
value=[0, dim_y],
marks={
str(i): str(i)
for i in range(
0,
dim_y + 1,
max(1, int(dim_y / 20)),
)
},
step=1,
),
id="crop-slider-fullscreen-container",
),
]
)
# callback pour le A-scan en plein écran
@callback(
[Output("heatmap-ascan-fullscreen", "figure"), Output("loading-ascan", "children")],
[
Input("layer-slider-x-ascan-fullscreen", "value"),
Input("layer-slider-z-ascan-fullscreen", "value"),
Input("crop-slider-fullscreen", "value"),
],
State("store-settings", "data"),
)
def update_heatmap_ascan_fullscreen(layer_x, layer_z, crop, settings):
y_min, y_max = crop or [0, dim_y]
layer_x = layer_x or 0
layer_z = layer_z or 0
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = px.line(y=data[layer_x - 1, int(y_min) : int(y_max), layer_z], title="A-scan")
return [fig, html.Div()]
@callback(
[
Output("layer-slider-x-ascan-fullscreen-container", "children"),
Output("layer-slider-z-ascan-fullscreen-container", "children"),
Output("crop-slider-fullscreen-container", "children"),
],
Input("ascan-settings", "data"),
)
def update_sliders(data):
slider_x_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Layer X: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-x-ascan-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 50)))
},
)
),
]
)
slider_z_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Layer Z: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-z-ascan-fullscreen",
min=1,
max=dim_z - 1,
value=1,
marks={
str(i): str(i)
for i in range(1, dim_z - 1, max(1, int(dim_z / 20)))
},
step=1,
)
),
]
)
crop_slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("Crop: "), width="auto"),
dbc.Col(
dcc.RangeSlider(
id="crop-slider-fullscreen",
min=0,
max=dim_y,
value=[0, dim_y],
marks={
str(i): str(i)
for i in range(
0,
dim_y + 1,
max(1, int(dim_y / 20)),
)
},
step=1,
)
),
]
)
if data is None:
return [None, None, None]
else:
if (
data["fullscreen_settings"] is None
or "layer_slider_x" not in data["fullscreen_settings"]
):
slider_x_fullscreen = None
if (
data["fullscreen_settings"] is None
or "layer_slider_z" not in data["fullscreen_settings"]
):
slider_z_fullscreen = None
if (
data["fullscreen_settings"] is None
or "crop_slider" not in data["fullscreen_settings"]
):
crop_slider_fullscreen = None
return [slider_x_fullscreen, slider_z_fullscreen, crop_slider_fullscreen]

View File

@ -0,0 +1,104 @@
import re
import dash
from dash import html, dcc, Input, Output, State, callback
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
from callbacks.home import pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
dash.register_page(__name__, path="/fullscreen/bscan-xy", title="B-Scan XY")
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,
}
layout = html.Div(
[
dbc.Spinner(
id="loading-bscan-xy",
color="primary",
fullscreen=True,
fullscreen_style={"backgroundColor": "var(--bs-body-bg)"},
),
dcc.Graph(
id="heatmap-bscan-xy-fullscreen",
config=configBScanXY,
style={"marginBottom": "15px", "height": "85vh"},
), # 'fig' is your 2D plotly figure
html.Div(
dcc.Slider(
id="layer-slider-bscan-xy-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 / 50)),
)
},
),
id="layer-slider-bscan-xy-fullscreen-container",
),
]
)
# callback pour les B-scan ZX en plein écran
@callback(
[Output("heatmap-bscan-xy-fullscreen", "figure"), Output("loading-bscan-xy", "children")],
Input("layer-slider-bscan-xy-fullscreen", "value"),
State("store-settings", "data"),
)
def update_heatmap_bscan_xy_fullscreen(layer, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = go.Figure(data=go.Heatmap(z=data[:, :, layer], colorscale="Jet"))
fig.update_layout(title="B-scan XY")
return [fig, html.Div()]
@callback(
Output("layer-slider-bscan-xy-fullscreen-container", "children"),
Input("bscan-xy-settings", "data"),
)
def update_sliders(data):
slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("X layer: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-bscan-xy-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i) for i in range(0, dim_x, max(1, int(dim_x / 50)))
},
)
),
]
)
if data is None:
return [None]
else:
if (
data["fullscreen_settings"] is None
or "layer_slider" not in data["fullscreen_settings"]
):
slider_fullscreen = None
return [slider_fullscreen]

View File

@ -0,0 +1,107 @@
import dash
from dash import html, dcc, Input, Output, State, callback
import plotly.express as px
import dash_bootstrap_components as dbc
from callbacks.home import pre_volume, volume, dim_x, dim_y, dim_z, X, Y, Z
dash.register_page(__name__, path="/fullscreen/bscan-zx", title="B-Scan ZX")
configBScanXY = {
"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,
}
layout = html.Div(
[
dbc.Spinner(
id="loading-bscan-zx",
color="primary",
fullscreen=True,
fullscreen_style={"backgroundColor": "var(--bs-body-bg)"},
),
dcc.Graph(
id="heatmap-bscan-zx-fullscreen",
config=configBScanXY,
style={"marginBottom": "15px", "height": "85vh"},
), # 'fig' is your 2D plotly figure
html.Div(
dcc.Slider(
id="layer-slider-bscan-zx-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(
0,
dim_x + 1,
max(1, int(dim_x / 50)),
)
},
),
id="layer-slider-bscan-zx-fullscreen-container",
),
]
)
# callback pour les B-scan ZX en plein écran
@callback(
[Output("heatmap-bscan-zx-fullscreen", "figure"), Output("loading-bscan-zx", "children")],
Input("layer-slider-bscan-zx-fullscreen", "value"),
State("store-settings", "data"),
)
def update_heatmap_bscan_zx_fullscreen(layer, settings):
if settings["apply_sampling_everywhere"]:
data = volume
else:
data = pre_volume
fig = px.imshow(
data[layer - 1, :, :],
color_continuous_scale="Jet",
aspect="auto",
title="B-scan ZX",
)
return [fig, html.Div()]
@callback(
Output("layer-slider-bscan-zx-fullscreen-container", "children"),
Input("bscan-zx-settings", "data"),
)
def update_sliders(data):
slider_fullscreen = dbc.Row(
[
dbc.Col(html.Span("X layer: "), width="auto"),
dbc.Col(
dcc.Slider(
id="layer-slider-bscan-zx-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(0, dim_x, max(1, int(dim_x / 50)))
},
)
),
]
)
if data is None:
return None
else:
if (
data["fullscreen_settings"] is None
or "layer_slider" not in data["fullscreen_settings"]
):
slider_fullscreen = None
return slider_fullscreen

View File

@ -1,5 +1,5 @@
import dash
from dash import html, dcc, DiskcacheManager
from dash import html, dcc, DiskcacheManager, get_asset_url
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
import numpy as np
@ -178,66 +178,7 @@ mesh_card = dbc.Fade(
),
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
html.Div(
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()
)
/ 20
),
)
},
step=1,
),
id="iso-slider-fullscreen-container",
),
html.Div(
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 / 50)),
)
},
step=1,
),
id="y-slider-fullscreen-container",
),
]
),
],
id="modal-3dplot",
fullscreen=True,
),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("3D plot settings")),
dbc.ModalHeader([html.Img(src=get_asset_url("settings.png"), height="32px", style={"marginRight": "5px"}), dbc.ModalTitle("3D plot settings")]),
dbc.ModalBody(
[
html.Span("Card display: "),
@ -352,77 +293,7 @@ Ascan_card = dbc.Fade(
),
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
html.Div(
dcc.Slider(
id="layer-slider-x-ascan-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(
0,
dim_x,
max(1, int(dim_x / 50)),
)
},
),
id="layer-slider-x-ascan-fullscreen-container",
),
html.Div(
dcc.Slider(
id="layer-slider-z-ascan-fullscreen",
min=1,
max=dim_z,
value=1,
step=1,
marks={
str(i): str(i)
for i in range(
1,
dim_z,
max(1, int(dim_z / 20)),
)
},
),
id="layer-slider-z-ascan-fullscreen-container",
),
html.Div(
dcc.RangeSlider(
id="crop-slider-fullscreen",
min=0,
max=dim_y,
value=[0, dim_y],
marks={
str(i): str(i)
for i in range(
0,
dim_y + 1,
max(1, int(dim_y / 20)),
)
},
step=1,
),
id="crop-slider-fullscreen-container",
),
]
),
],
id="modal-ascan",
fullscreen=True,
),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("A-Scan settings")),
dbc.ModalHeader([html.Img(src=get_asset_url("settings.png"), height="32px", style={"marginRight": "5px"}), dbc.ModalTitle("A-Scan settings")]),
dbc.ModalBody(
[
html.Span("Card display: "),
@ -537,41 +408,7 @@ Bscan_card_xy = dbc.Fade(
),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("B-Scan ZX")),
dbc.ModalBody(
[
dcc.Graph(
id="heatmap-bscan-zx-fullscreen",
config=configBScanXY,
style={"marginBottom": "15px", "height": "90%"},
), # 'fig' is your 2D plotly figure
html.Div(
dcc.Slider(
id="layer-slider-bscan-zx-fullscreen",
min=0,
max=dim_x,
value=0,
step=1,
marks={
str(i): str(i)
for i in range(
0,
dim_x + 1,
max(1, int(dim_x / 50)),
)
},
),
id="layer-slider-bscan-zx-fullscreen-container",
),
]
),
],
id="modal-bscan-zx",
fullscreen=True,
),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("B-Scan ZX settings")),
dbc.ModalHeader([html.Img(src=get_asset_url("settings.png"), height="32px", style={"marginRight": "5px"}), dbc.ModalTitle("B-Scan ZX settings")]),
dbc.ModalBody(
[
html.Span("Card display: "),
@ -689,41 +526,7 @@ Bscan_card_zx = dbc.Fade(
),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("B-Scan XY")),
dbc.ModalBody(
[
dcc.Graph(
id="heatmap-bscan-xy-fullscreen",
config=configBScanXY,
style={"marginBottom": "15px", "height": "90%"},
), # 'fig' is your 2D plotly figure
html.Div(
dcc.Slider(
id="layer-slider-bscan-xy-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 / 50)),
)
},
),
id="layer-slider-bscan-xy-fullscreen-container",
),
],
),
],
id="modal-bscan-xy",
fullscreen=True,
),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("B-Scan XY settings")),
dbc.ModalHeader([html.Img(src=get_asset_url("settings.png"), height="32px", style={"marginRight": "5px"}), dbc.ModalTitle("B-Scan XY settings")]),
dbc.ModalBody(
[
html.Span("Card display: "),

View File

@ -1,5 +1,6 @@
dash==2.17.0
dash_bootstrap_components==1.6.0
dash_extensions==1.0.16
diskcache==5.6.3
matplotlib==3.8.4
numpy==2.0.0
@ -7,5 +8,5 @@ pandas==2.2.2
plotly==5.22.0
progress==1.6
python_igraph==0.11.5
scipy==1.13.1
scipy==1.14.0
tqdm==4.66.4