V4.2
chore: Refactor home callbacks to be more readable. feat: Implementation of slider control
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@
|
||||
/.vscode/
|
||||
/3D_app.old/
|
||||
3D_app/data.sqlite
|
||||
1acquisition-ultrasons-cale-tofd_2024-06-07_0851/
|
||||
|
258
3D_app/GNG_3D.py
258
3D_app/GNG_3D.py
@ -1,31 +1,29 @@
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
import numpy as np
|
||||
from sklearn.datasets import make_swiss_roll
|
||||
import igraph as ig
|
||||
from numpy.linalg import norm
|
||||
from sklearn.datasets import make_moons
|
||||
import igraph as ig
|
||||
from numpy.linalg import norm
|
||||
from tqdm import tqdm
|
||||
from sys import stdout
|
||||
|
||||
# import cupy as np
|
||||
|
||||
|
||||
class GrowingNeuralGas:
|
||||
|
||||
|
||||
def __init__(self, max_neurons, max_iter, max_age, eb, en, alpha, beta, l, dataset):
|
||||
|
||||
'''
|
||||
"""
|
||||
---------------------------------------------
|
||||
Growing Neural Gas' Parameter Declarations
|
||||
---------------------------------------------
|
||||
1. max_iter ; Maximum # of iterations the
|
||||
2. max_age ; Maximum # of age
|
||||
1. max_iter ; Maximum # of iterations the
|
||||
2. max_age ; Maximum # of age
|
||||
3. eb ; fraction of distance betweeen nearest neuron and input signal
|
||||
4. en ; fraction of distance betweeen neighboring neurons and input signal
|
||||
5. alpha ; multiplying scalar for local error
|
||||
6. beta ; multiplying scalar for global error
|
||||
7. l
|
||||
7. l
|
||||
8. dataset
|
||||
'''
|
||||
|
||||
"""
|
||||
|
||||
# Parameters declared by user
|
||||
self.max_neurons = max_neurons
|
||||
self.max_iter = max_iter
|
||||
@ -37,15 +35,15 @@ class GrowingNeuralGas:
|
||||
self.l = l
|
||||
self.dataset_original = dataset.copy()
|
||||
self.dataset = dataset.copy()
|
||||
|
||||
|
||||
# Variable for tracking learning evolution
|
||||
self.verts_evolve = []
|
||||
self.edges_evolve = []
|
||||
|
||||
|
||||
def initialize_gng(self):
|
||||
'''
|
||||
"""
|
||||
Initialize Growing Neural Gas
|
||||
'''
|
||||
"""
|
||||
# Get random datapoints from target dataset
|
||||
t0 = np.random.randint(0, int(self.dataset.shape[0] / 2))
|
||||
t1 = np.random.randint(int(self.dataset.shape[0] / 2), self.dataset.shape[0])
|
||||
@ -54,45 +52,60 @@ class GrowingNeuralGas:
|
||||
self.gng.add_vertex(weight=self.dataset[t0, :].astype(np.float64), error=0)
|
||||
self.gng.add_vertex(weight=self.dataset[t1, :].astype(np.float64), error=0)
|
||||
self.gng.add_edge(0, 1, age=0)
|
||||
|
||||
|
||||
def learning_position(self):
|
||||
for _ in range(self.l):
|
||||
# Step 1. Get a random datapoint from target dataset
|
||||
t = np.random.randint(0, self.dataset.shape[0])
|
||||
random_input = self.dataset[t, :]
|
||||
|
||||
|
||||
# Step 2. Find 2 nearest neuron from random_input
|
||||
nearest_index = np.array([norm(weight[:2] - random_input[:2])**2 for weight in self.gng.vs['weight']]).argsort()
|
||||
nearest_index = np.array(
|
||||
[
|
||||
norm(weight[:2] - random_input[:2]) ** 2
|
||||
for weight in self.gng.vs["weight"]
|
||||
]
|
||||
).argsort()
|
||||
neuron_s1 = self.gng.vs[nearest_index[0]]
|
||||
neuron_s2 = self.gng.vs[nearest_index[1]]
|
||||
neuron_s2 = self.gng.vs[nearest_index[1]]
|
||||
|
||||
# Step 3. Increase the age of all neighboring edges from nearest neuron (neuron_s1)
|
||||
for edge_id in self.gng.incident(neuron_s1.index):
|
||||
self.gng.es[edge_id]['age'] += 1
|
||||
self.gng.es[edge_id]["age"] += 1
|
||||
|
||||
# Step 4. Add error to the nearest neuron
|
||||
self.gng.vs[neuron_s1.index]['error'] += norm(neuron_s1['weight'][:2] - random_input[:2])
|
||||
self.gng.vs[neuron_s1.index]["error"] += norm(
|
||||
neuron_s1["weight"][:2] - random_input[:2]
|
||||
)
|
||||
|
||||
# Step 5.1. Update position of nearest neuron
|
||||
neuron_s1['weight'][:2] += (self.eb * (random_input[:2] - neuron_s1['weight'][:2]))
|
||||
neuron_s1['weight'][2] += (self.eb * (random_input[2] - neuron_s1['weight'][2]))
|
||||
neuron_s1["weight"][:2] += self.eb * (
|
||||
random_input[:2] - neuron_s1["weight"][:2]
|
||||
)
|
||||
neuron_s1["weight"][2] += self.eb * (
|
||||
random_input[2] - neuron_s1["weight"][2]
|
||||
)
|
||||
# Step 5.2. Update position of nearest neuron's neighbors
|
||||
for neuron in self.gng.vs[self.gng.neighbors(neuron_s1.index)]:
|
||||
neuron['weight'][:2] += (self.en * (random_input[:2] - neuron['weight'][:2]))
|
||||
neuron['weight'][2] += (self.en * (random_input[2] - neuron['weight'][2]))
|
||||
neuron["weight"][:2] += self.en * (
|
||||
random_input[:2] - neuron["weight"][:2]
|
||||
)
|
||||
neuron["weight"][2] += self.en * (random_input[2] - neuron["weight"][2])
|
||||
|
||||
# Step 6. Update edge of nearest neurons
|
||||
EDGE_FLAG = self.gng.get_eid(neuron_s1.index, neuron_s2.index, directed=False, error=False)
|
||||
EDGE_FLAG = self.gng.get_eid(
|
||||
neuron_s1.index, neuron_s2.index, directed=False, error=False
|
||||
)
|
||||
if EDGE_FLAG == -1:
|
||||
self.gng.add_edge(neuron_s1.index, neuron_s2.index, age=0)
|
||||
else:
|
||||
self.gng.es[EDGE_FLAG]['age'] = 0
|
||||
self.gng.es[EDGE_FLAG]["age"] = 0
|
||||
|
||||
# Step 7.1. Delete aging edge
|
||||
for edge in self.gng.es:
|
||||
src = edge.source
|
||||
tgt = edge.target
|
||||
if edge['age'] > self.max_age:
|
||||
if edge["age"] > self.max_age:
|
||||
self.gng.delete_edges(edge.index)
|
||||
|
||||
# Step 7.2. Delete isolated neuron
|
||||
@ -102,7 +115,7 @@ class GrowingNeuralGas:
|
||||
|
||||
# Step 8. Reduce global error
|
||||
for neuron in self.gng.vs:
|
||||
neuron['error'] *= self.beta
|
||||
neuron["error"] *= self.beta
|
||||
|
||||
# Step 9.1. Remove generated random input from target dataset
|
||||
self.dataset = np.delete(self.dataset, t, axis=0)
|
||||
@ -114,13 +127,20 @@ class GrowingNeuralGas:
|
||||
# Adding new neuron from previous learning
|
||||
# Get neuron q and f
|
||||
if len(self.gng.vs) <= self.max_neurons:
|
||||
error_index = np.array([error for error in self.gng.vs['error']]).argsort()
|
||||
error_index = np.array([error for error in self.gng.vs["error"]]).argsort()
|
||||
neuron_q = self.gng.vs[error_index[-1]]
|
||||
error = np.array([(neuron['error'], neuron.index) for neuron in self.gng.vs[self.gng.neighbors(neuron_q.index)]])
|
||||
error = np.array(
|
||||
[
|
||||
(neuron["error"], neuron.index)
|
||||
for neuron in self.gng.vs[self.gng.neighbors(neuron_q.index)]
|
||||
]
|
||||
)
|
||||
error = np.sort(error, axis=0)
|
||||
neuron_f = self.gng.vs[int(error[-1, 1])]
|
||||
# Add neuron between neuron q and f
|
||||
self.gng.add_vertex(weight=(neuron_q['weight'] + neuron_f['weight']) / 2, error=0)
|
||||
self.gng.add_vertex(
|
||||
weight=(neuron_q["weight"] + neuron_f["weight"]) / 2, error=0
|
||||
)
|
||||
neuron_r = self.gng.vs[len(self.gng.vs) - 1]
|
||||
# Delete edge between neuron q and f
|
||||
self.gng.delete_edges(self.gng.get_eid(neuron_q.index, neuron_f.index))
|
||||
@ -128,24 +148,30 @@ class GrowingNeuralGas:
|
||||
self.gng.add_edge(neuron_q.index, neuron_r.index, age=0)
|
||||
self.gng.add_edge(neuron_r.index, neuron_f.index, age=0)
|
||||
# Update neuron error
|
||||
neuron_q['error'] *= self.alpha
|
||||
neuron_f['error'] *= self.alpha
|
||||
neuron_r['error'] = neuron_q['error']
|
||||
|
||||
neuron_q["error"] *= self.alpha
|
||||
neuron_f["error"] *= self.alpha
|
||||
neuron_r["error"] = neuron_q["error"]
|
||||
|
||||
def learn(self):
|
||||
# Initialize GNG
|
||||
self.initialize_gng()
|
||||
# GNG learning iteration
|
||||
for iter, _ in zip(range(0, self.max_iter), tqdm(range(self.max_iter))):
|
||||
# Track evolution
|
||||
self.verts_evolve.append(np.array([neuron['weight'] for neuron in self.gng.vs]))
|
||||
self.edges_evolve.append(np.array([(neuron.source + 1, neuron.target + 1) for neuron in self.gng.es]))
|
||||
self.verts_evolve.append(
|
||||
np.array([neuron["weight"] for neuron in self.gng.vs])
|
||||
)
|
||||
self.edges_evolve.append(
|
||||
np.array(
|
||||
[(neuron.source + 1, neuron.target + 1) for neuron in self.gng.es]
|
||||
)
|
||||
)
|
||||
# Learn new posititon
|
||||
self.learning_position()
|
||||
self.update_neuron()
|
||||
self.update_neuron()
|
||||
return self.gng
|
||||
|
||||
def plot_gng(self, active1,active2, data_point_size=1, neuron_size=30):
|
||||
|
||||
def plot_gng(self, active1, active2, data_point_size=1, neuron_size=30):
|
||||
"""
|
||||
Function to plot the neurons and connections of the GNG in 3D space, with color representing the intensity.
|
||||
Parameters:
|
||||
@ -153,67 +179,103 @@ class GrowingNeuralGas:
|
||||
- neuron_size: Size of the neurons in the plot.
|
||||
"""
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
|
||||
ax = fig.add_subplot(111, projection="3d")
|
||||
|
||||
# Plot the original data points
|
||||
if (active1==True):
|
||||
scatter = ax.scatter(self.dataset_original[:, 0], self.dataset_original[:, 1], self.dataset_original[:, 2], c=self.dataset_original[:, 3], s=data_point_size, cmap='viridis', alpha=0.5, label='Data')
|
||||
|
||||
if active1 == True:
|
||||
scatter = ax.scatter(
|
||||
self.dataset_original[:, 0],
|
||||
self.dataset_original[:, 1],
|
||||
self.dataset_original[:, 2],
|
||||
c=self.dataset_original[:, 3],
|
||||
s=data_point_size,
|
||||
cmap="viridis",
|
||||
alpha=0.5,
|
||||
label="Data",
|
||||
)
|
||||
|
||||
# Plot the neurons
|
||||
neuron_positions = np.array([neuron['weight'] for neuron in self.gng.vs])
|
||||
scatter=ax.scatter(neuron_positions[:, 0], neuron_positions[:, 1], neuron_positions[:, 2], c=neuron_positions[:, 3], s=neuron_size, cmap='viridis', label='Neurons')
|
||||
fig.colorbar(scatter, ax=ax, label='Intensity')
|
||||
neuron_positions = np.array([neuron["weight"] for neuron in self.gng.vs])
|
||||
scatter = ax.scatter(
|
||||
neuron_positions[:, 0],
|
||||
neuron_positions[:, 1],
|
||||
neuron_positions[:, 2],
|
||||
c=neuron_positions[:, 3],
|
||||
s=neuron_size,
|
||||
cmap="viridis",
|
||||
label="Neurons",
|
||||
)
|
||||
fig.colorbar(scatter, ax=ax, label="Intensity")
|
||||
# Plot the connections
|
||||
if(active2==True):
|
||||
if active2 == True:
|
||||
for edge in self.gng.es:
|
||||
src, tgt = edge.source, edge.target
|
||||
src_pos, tgt_pos = self.gng.vs[src]['weight'], self.gng.vs[tgt]['weight']
|
||||
ax.plot([src_pos[0], tgt_pos[0]], [src_pos[1], tgt_pos[1]], [src_pos[2], tgt_pos[2]], 'k-', alpha=0.5)
|
||||
src_pos, tgt_pos = (
|
||||
self.gng.vs[src]["weight"],
|
||||
self.gng.vs[tgt]["weight"],
|
||||
)
|
||||
ax.plot(
|
||||
[src_pos[0], tgt_pos[0]],
|
||||
[src_pos[1], tgt_pos[1]],
|
||||
[src_pos[2], tgt_pos[2]],
|
||||
"k-",
|
||||
alpha=0.5,
|
||||
)
|
||||
|
||||
ax.set_title('Growing Neural Gas Result')
|
||||
ax.legend()
|
||||
plt.show()
|
||||
|
||||
|
||||
|
||||
|
||||
def plot_gng(x1,x2,active2, neuron_size=30):
|
||||
"""
|
||||
Function to plot the neurons and connections of the GNG in 3D space, with color representing the intensity.
|
||||
Parameters:
|
||||
- data_point_size: Size of the data points in the plot.
|
||||
- neuron_size: Size of the neurons in the plot.
|
||||
"""
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
|
||||
# Plot the original data points
|
||||
#if (active1==True):
|
||||
#scatter = ax.scatter(self.dataset_original[:, 0], self.dataset_original[:, 1], self.dataset_original[:, 2], c=self.dataset_original[:, 3], s=data_point_size, cmap='viridis', alpha=0.5, label='Data')
|
||||
|
||||
# Plot the neurons
|
||||
neuron_positions = x1
|
||||
scatter=ax.scatter(neuron_positions[:, 0], neuron_positions[:, 1], neuron_positions[:, 2], c=neuron_positions[:, 3], s=neuron_size, cmap='viridis', label='Neurons')
|
||||
fig.colorbar(scatter, ax=ax, label='Intensity')
|
||||
# Plot the connections
|
||||
if(active2==True):
|
||||
for edge in x2:
|
||||
src, tgt = edge[0], edge[1]
|
||||
src_pos, tgt_pos = x1[src][:], x1[tgt][:]
|
||||
ax.plot([src_pos[0], tgt_pos[0]], [src_pos[1], tgt_pos[1]], [src_pos[2], tgt_pos[2]], 'k-', alpha=0.5)
|
||||
|
||||
|
||||
|
||||
ax.set_title('Growing Neural Gas Result')
|
||||
ax.set_title("Growing Neural Gas Result")
|
||||
ax.legend()
|
||||
plt.show()
|
||||
|
||||
|
||||
def position_point_espace(data, seuil,y):
|
||||
tab = []
|
||||
size_data = np.shape(data)
|
||||
for i in range(size_data[0]):
|
||||
for j in range(size_data[1]):
|
||||
if data[i, j] > seuil:
|
||||
tab.append([y,i, j, data[i, j]])
|
||||
return tab
|
||||
def plot_gng(x1, x2, active2, neuron_size=30):
|
||||
"""
|
||||
Function to plot the neurons and connections of the GNG in 3D space, with color representing the intensity.
|
||||
Parameters:
|
||||
- data_point_size: Size of the data points in the plot.
|
||||
- neuron_size: Size of the neurons in the plot.
|
||||
"""
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111, projection="3d")
|
||||
|
||||
# Plot the original data points
|
||||
# if (active1==True):
|
||||
# scatter = ax.scatter(self.dataset_original[:, 0], self.dataset_original[:, 1], self.dataset_original[:, 2], c=self.dataset_original[:, 3], s=data_point_size, cmap='viridis', alpha=0.5, label='Data')
|
||||
|
||||
# Plot the neurons
|
||||
neuron_positions = x1
|
||||
scatter = ax.scatter(
|
||||
neuron_positions[:, 0],
|
||||
neuron_positions[:, 1],
|
||||
neuron_positions[:, 2],
|
||||
c=neuron_positions[:, 3],
|
||||
s=neuron_size,
|
||||
cmap="viridis",
|
||||
label="Neurons",
|
||||
)
|
||||
fig.colorbar(scatter, ax=ax, label="Intensity")
|
||||
# Plot the connections
|
||||
if active2 == True:
|
||||
for edge in x2:
|
||||
src, tgt = edge[0], edge[1]
|
||||
src_pos, tgt_pos = x1[src][:], x1[tgt][:]
|
||||
ax.plot(
|
||||
[src_pos[0], tgt_pos[0]],
|
||||
[src_pos[1], tgt_pos[1]],
|
||||
[src_pos[2], tgt_pos[2]],
|
||||
"k-",
|
||||
alpha=0.5,
|
||||
)
|
||||
|
||||
ax.set_title("Growing Neural Gas Result")
|
||||
ax.legend()
|
||||
plt.show()
|
||||
|
||||
|
||||
def position_point_espace(data, seuil, y):
|
||||
tab = []
|
||||
size_data = np.shape(data)
|
||||
for i in range(size_data[0]):
|
||||
for j in range(size_data[1]):
|
||||
if data[i, j] > seuil:
|
||||
tab.append([y, i, j, data[i, j]])
|
||||
return tab
|
||||
|
@ -35,3 +35,8 @@
|
||||
|
||||
* Ajustement de la fonction d'enregistrement et d'ouverture des datasets
|
||||
* Ajout d'un bouton de sauvegarde pour les datasets filtrés
|
||||
|
||||
# V4.2
|
||||
|
||||
- Réorganisation des callbacks de `home.py`
|
||||
- Ajout de popups pour contrôler l'affichage des sliders
|
||||
|
@ -7,6 +7,8 @@ from os.path import join
|
||||
from util import lire_fichier_csv
|
||||
from selection_filtre import switch_case
|
||||
from callbacks.ascan import data_traits
|
||||
from dash import dcc, html
|
||||
import dash_bootstrap_components as dbc
|
||||
|
||||
# on définit le dossier et les fichiers à lire
|
||||
dossier = "Dataset/Shear_transform"
|
||||
@ -27,6 +29,11 @@ X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
|
||||
|
||||
|
||||
def get_callbacks():
|
||||
# -----------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour le 3D plot ----------------------
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# callback pour le plot 3D
|
||||
@callback(
|
||||
[Output("3dplot", "figure"), Output("fade-3dplot", "is_in")],
|
||||
[
|
||||
@ -38,13 +45,13 @@ def get_callbacks():
|
||||
)
|
||||
def update_3dplot(iso_value, y_values, settings, is_in):
|
||||
if settings["use_real_values"]:
|
||||
y_min, y_max = y_values
|
||||
y_min, y_max = y_values or [0, dim_y]
|
||||
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
|
||||
y_min, y_max = y_values or [0, dim_y]
|
||||
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],
|
||||
@ -65,7 +72,6 @@ def get_callbacks():
|
||||
colorscale="Jet",
|
||||
)
|
||||
)
|
||||
|
||||
return [fig, True]
|
||||
|
||||
# callback pour le plot 3D en plein écran
|
||||
@ -75,6 +81,7 @@ def get_callbacks():
|
||||
Input("iso-slider-fullscreen", "value"),
|
||||
Input("y-slider-fullscreen", "value"),
|
||||
],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def update_3dplot_fullscreen(iso_value, y_values):
|
||||
y_min, y_max = y_values
|
||||
@ -101,6 +108,166 @@ def get_callbacks():
|
||||
|
||||
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(
|
||||
Output("modal-settings-3dplot", "is_open"),
|
||||
[
|
||||
Input("settings-button-3dplot", "n_clicks"),
|
||||
Input("save-settings-3dplot", "n_clicks"),
|
||||
],
|
||||
[dash.dependencies.State("modal-settings-3dplot", "is_open")],
|
||||
)
|
||||
def toggle_settings_3dplot(n1, n2, is_open):
|
||||
if n1 or n2:
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
@callback(
|
||||
Output("3dplot-settings", "data"),
|
||||
Input("save-settings-3dplot", "n_clicks"),
|
||||
[
|
||||
State("checklist-3dplot-card-settings", "value"),
|
||||
State("checklist-3dplot-fullscreen-settings", "value"),
|
||||
],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def save_settings_3dplot(n_clicks, card_settings, fullscreen_settings):
|
||||
return {
|
||||
"card_settings": card_settings,
|
||||
"fullscreen_settings": fullscreen_settings,
|
||||
}
|
||||
|
||||
@callback(
|
||||
[
|
||||
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"),
|
||||
)
|
||||
def update_3dplot_sliders(data):
|
||||
iso_slider = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Iso value: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="iso-slider",
|
||||
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",
|
||||
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)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
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]
|
||||
else:
|
||||
if (
|
||||
data["card_settings"] is None
|
||||
or "iso_slider" not in data["card_settings"]
|
||||
):
|
||||
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,
|
||||
]
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour le A-Scan ----------------------
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# callback pour le A-scan
|
||||
@callback(
|
||||
[Output("heatmap-ascan", "figure"), Output("fade-ascan", "is_in")],
|
||||
@ -108,33 +275,213 @@ def get_callbacks():
|
||||
Input("layer-slider-bscan-zx", "value"),
|
||||
Input("layer-slider-bscan-xy", "value"),
|
||||
],
|
||||
[State("fade-ascan", "is_in"), State("store-settings", "data")],
|
||||
[
|
||||
State("crop-slider", "value"),
|
||||
State("fade-ascan", "is_in"),
|
||||
State("store-settings", "data"),
|
||||
],
|
||||
)
|
||||
def update_heatmap_ascan(layer, layer1, is_in, settings):
|
||||
def update_heatmap_ascan(layer, layer1, crop_values, is_in, settings):
|
||||
y_min, y_max = crop_values or [0, dim_y]
|
||||
layer = layer or 1
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = px.line(y=data[layer - 1, :, layer1], title="A-scan")
|
||||
|
||||
fig = px.line(
|
||||
y=data[layer - 1, int(y_min) : int(y_max), 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"),
|
||||
State("store-settings", "data")
|
||||
[
|
||||
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, settings):
|
||||
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 - 1, :, 5], title="A-scan")
|
||||
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"),
|
||||
[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 les paramètres du A-scan
|
||||
@callback(
|
||||
Output("modal-settings-ascan", "is_open"),
|
||||
[
|
||||
Input("settings-button-ascan", "n_clicks"),
|
||||
Input("save-settings-ascan", "n_clicks"),
|
||||
],
|
||||
[dash.dependencies.State("modal-settings-ascan", "is_open")],
|
||||
)
|
||||
def toggle_settings_ascan(n1, n2, is_open):
|
||||
if n1 or n2:
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
@callback(
|
||||
Output("ascan-settings", "data"),
|
||||
Input("save-settings-ascan", "n_clicks"),
|
||||
[
|
||||
State("checklist-ascan-card-settings", "value"),
|
||||
State("checklist-ascan-fullscreen-settings", "value"),
|
||||
],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def save_settings_ascan(n_clicks, card_settings, fullscreen_settings):
|
||||
return {
|
||||
"card_settings": card_settings,
|
||||
"fullscreen_settings": fullscreen_settings,
|
||||
}
|
||||
|
||||
@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"),
|
||||
)
|
||||
def update_ascan_sliders(data):
|
||||
crop_slider = dbc.Row(
|
||||
[
|
||||
dbc.Col(
|
||||
html.Span("Crop: ", className="mr-2"),
|
||||
width="auto",
|
||||
),
|
||||
dbc.Col(
|
||||
dcc.RangeSlider(
|
||||
id="crop-slider",
|
||||
min=0,
|
||||
max=dim_y,
|
||||
step=1,
|
||||
value=[0, dim_y],
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_y + 1, max(1, int(dim_y / 20)))
|
||||
},
|
||||
),
|
||||
),
|
||||
]
|
||||
)
|
||||
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]
|
||||
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,
|
||||
]
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour le B-Scan ZX ----------------------
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# callback pour les B-scan XY
|
||||
@callback(
|
||||
[
|
||||
@ -143,16 +490,21 @@ def get_callbacks():
|
||||
Output("fade-bscan-xy", "is_in"),
|
||||
],
|
||||
[Input("layer-slider-bscan-zx", "value")],
|
||||
[State("fade-bscan-zx", "is_in"), State("store-settings", "data")],
|
||||
[
|
||||
State("crop-slider", "value"),
|
||||
State("fade-bscan-zx", "is_in"),
|
||||
State("store-settings", "data"),
|
||||
],
|
||||
)
|
||||
def update_heatmap_bscan_zx(layer, is_in, settings):
|
||||
def update_heatmap_bscan_zx(layer, crop_values, is_in, settings):
|
||||
y_min, y_max = crop_values or [0, dim_y]
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = px.imshow(
|
||||
data[layer - 1, :, :],
|
||||
data[layer - 1, int(y_min) : int(y_max), :],
|
||||
color_continuous_scale="Jet",
|
||||
aspect="auto",
|
||||
title="B-scan ZX",
|
||||
@ -164,7 +516,7 @@ def get_callbacks():
|
||||
@callback(
|
||||
Output("heatmap-bscan-zx-fullscreen", "figure"),
|
||||
Input("layer-slider-bscan-zx-fullscreen", "value"),
|
||||
State("store-settings", "data")
|
||||
State("store-settings", "data"),
|
||||
)
|
||||
def update_heatmap_bscan_zx_fullscreen(layer, settings):
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
@ -181,6 +533,128 @@ def get_callbacks():
|
||||
|
||||
return fig
|
||||
|
||||
# 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 pour les paramètres du B-scan ZX
|
||||
@callback(
|
||||
Output("modal-settings-bscan-zx", "is_open"),
|
||||
[
|
||||
Input("settings-button-bscan-zx", "n_clicks"),
|
||||
Input("save-settings-bscan-zx", "n_clicks"),
|
||||
],
|
||||
[dash.dependencies.State("modal-settings-bscan-zx", "is_open")],
|
||||
)
|
||||
def toggle_settings_bscan_zx(n1, n2, is_open):
|
||||
if n1 or n2:
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
@callback(
|
||||
Output("bscan-zx-settings", "data"),
|
||||
Input("save-settings-bscan-zx", "n_clicks"),
|
||||
[
|
||||
State("checklist-bscan-zx-card-settings", "value"),
|
||||
State("checklist-bscan-zx-fullscreen-settings", "value"),
|
||||
],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def save_settings_bscan_zx(n_clicks, card_settings, fullscreen_settings):
|
||||
return {
|
||||
"card_settings": card_settings,
|
||||
"fullscreen_settings": fullscreen_settings,
|
||||
}
|
||||
|
||||
@callback(
|
||||
[
|
||||
Output("layer-slider-bscan-zx-container", "children"),
|
||||
Output("layer-slider-bscan-zx-fullscreen-container", "children"),
|
||||
],
|
||||
Input("bscan-zx-settings", "data"),
|
||||
)
|
||||
def update_bscan_zx_sliders(data):
|
||||
slider = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Layer: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-zx",
|
||||
min=0,
|
||||
max=dim_x - 1,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_x, max(1, int(dim_x / 20)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
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]
|
||||
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,
|
||||
]
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour le B-Scan XY ----------------------
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# callback pour les B-scan ZX
|
||||
@callback(
|
||||
[
|
||||
@ -189,15 +663,22 @@ def get_callbacks():
|
||||
Output("fade-bscan-zx", "is_in"),
|
||||
],
|
||||
[Input("layer-slider-bscan-xy", "value")],
|
||||
[State("fade-bscan-xy", "is_in"), State("store-settings", "data")],
|
||||
[
|
||||
State("crop-slider", "value"),
|
||||
State("fade-bscan-xy", "is_in"),
|
||||
State("store-settings", "data"),
|
||||
],
|
||||
)
|
||||
def update_heatmap_bscan_xy(layer, is_in, settings):
|
||||
def update_heatmap_bscan_xy(layer, crop_values, is_in, settings):
|
||||
y_min, y_max = crop_values or [0, dim_y]
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = go.Figure(data=go.Heatmap(z=data[:, :, layer], colorscale="Jet"))
|
||||
fig = go.Figure(
|
||||
data=go.Heatmap(z=data[:, int(y_min) : int(y_max), layer], colorscale="Jet")
|
||||
)
|
||||
fig.update_layout(title="B-scan XY")
|
||||
|
||||
return [fig, layer, True]
|
||||
@ -219,28 +700,6 @@ def get_callbacks():
|
||||
|
||||
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"),
|
||||
@ -252,17 +711,6 @@ def get_callbacks():
|
||||
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("heatmap-bscan-xy", "clickData"),
|
||||
@ -278,6 +726,118 @@ def get_callbacks():
|
||||
bscan_zx = clickData["points"][0]["y"]
|
||||
return [clickData, bscan_zx]
|
||||
|
||||
# callback pour les paramètres du B-scan XY
|
||||
@callback(
|
||||
Output("modal-settings-bscan-xy", "is_open"),
|
||||
[
|
||||
Input("settings-button-bscan-xy", "n_clicks"),
|
||||
Input("save-settings-bscan-xy", "n_clicks"),
|
||||
],
|
||||
[dash.dependencies.State("modal-settings-bscan-xy", "is_open")],
|
||||
)
|
||||
def toggle_settings_bscan_xy(n1, n2, is_open):
|
||||
if n1 or n2:
|
||||
return not is_open
|
||||
return is_open
|
||||
|
||||
@callback(
|
||||
Output("bscan-xy-settings", "data"),
|
||||
Input("save-settings-bscan-xy", "n_clicks"),
|
||||
[
|
||||
State("checklist-bscan-xy-card-settings", "value"),
|
||||
State("checklist-bscan-xy-fullscreen-settings", "value"),
|
||||
],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def save_settings_bscan_xy(n_clicks, card_settings, fullscreen_settings):
|
||||
return {
|
||||
"card_settings": card_settings,
|
||||
"fullscreen_settings": fullscreen_settings,
|
||||
}
|
||||
|
||||
@callback(
|
||||
[
|
||||
Output("layer-slider-bscan-xy-container", "children"),
|
||||
Output("layer-slider-bscan-xy-fullscreen-container", "children"),
|
||||
],
|
||||
Input("bscan-xy-settings", "data"),
|
||||
)
|
||||
def update_bscan_xy_sliders(data):
|
||||
slider = dbc.Row(
|
||||
[
|
||||
dbc.Col(html.Span("Layer: "), width="auto"),
|
||||
dbc.Col(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-xy",
|
||||
min=1,
|
||||
max=dim_z - 1,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(1, dim_z, max(1, int(dim_z / 20)))
|
||||
},
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
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]
|
||||
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,
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour la selection de data ----------------------
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# callback pour la selection de data sur le B-scan ZX
|
||||
@callback(
|
||||
[
|
||||
Output("heatmap-bscan-zx", "clickData"),
|
||||
@ -293,6 +853,7 @@ def get_callbacks():
|
||||
bscan_xy = clickData["points"][0]["x"]
|
||||
return [clickData, bscan_xy]
|
||||
|
||||
# callback pour la selection de data sur le B-scan XY
|
||||
@callback(
|
||||
[
|
||||
Output("heatmap-bscan-xy", "figure", allow_duplicate=True),
|
||||
@ -308,7 +869,7 @@ def get_callbacks():
|
||||
type="line",
|
||||
x0=0 - 1,
|
||||
y0=bscan_zx,
|
||||
x1=dim_y,
|
||||
x1=pre_volume.shape[1],
|
||||
y1=bscan_zx,
|
||||
line=dict(color="white", width=1),
|
||||
)
|
||||
@ -325,7 +886,7 @@ def get_callbacks():
|
||||
x0=bscan_xy,
|
||||
y0=0,
|
||||
x1=bscan_xy,
|
||||
y1=dim_y,
|
||||
y1=pre_volume.shape[1],
|
||||
line=dict(color="white", width=1),
|
||||
)
|
||||
|
||||
@ -333,6 +894,10 @@ def get_callbacks():
|
||||
|
||||
return [fig, fig2, fig3]
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour la gestion des parametres ----------------------
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
@callback(
|
||||
[Output("store-settings", "data"), Output("settings-apply", "n_clicks")],
|
||||
[
|
||||
@ -372,6 +937,8 @@ def get_callbacks():
|
||||
|
||||
@callback(
|
||||
[
|
||||
Output("crop-slider", "max"),
|
||||
Output("crop-slider", "marks"),
|
||||
Output("layer-slider-bscan-zx", "max"),
|
||||
Output("layer-slider-bscan-zx", "marks"),
|
||||
Output("layer-slider-bscan-xy", "max"),
|
||||
@ -381,8 +948,8 @@ def get_callbacks():
|
||||
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-x-ascan-fullscreen", "max"),
|
||||
Output("layer-slider-x-ascan-fullscreen", "marks"),
|
||||
Output("layer-slider-bscan-xy-fullscreen", "max"),
|
||||
Output("layer-slider-bscan-xy-fullscreen", "marks"),
|
||||
Output("layer-slider-bscan-zx-fullscreen", "max"),
|
||||
@ -399,15 +966,21 @@ def get_callbacks():
|
||||
)
|
||||
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"],
|
||||
]
|
||||
if data["apply_sampling_everywhere"]:
|
||||
volume = pre_volume[
|
||||
:: data["echantillonage_x"],
|
||||
:: data["echantillonage_y"],
|
||||
:: data["echantillonage_z"],
|
||||
]
|
||||
else:
|
||||
volume = pre_volume
|
||||
|
||||
dim_x, dim_y, dim_z = volume.shape
|
||||
X, Y, Z = np.mgrid[0:dim_x, 0:dim_y, 0:dim_z]
|
||||
|
||||
return [
|
||||
dim_y - 1,
|
||||
{str(i): str(i) for i in range(1, 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_z - 1,
|
||||
@ -445,6 +1018,10 @@ def get_callbacks():
|
||||
"Apply",
|
||||
]
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour les filtres ----------------------
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@callback(
|
||||
Output("store-filters", "data", allow_duplicate=True),
|
||||
[Input("store-filters", "data"), Input("store-settings", "data")],
|
||||
@ -499,6 +1076,10 @@ def get_callbacks():
|
||||
]
|
||||
return data
|
||||
|
||||
# ------------------------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour la gestion des fichiers ----------------------
|
||||
# ------------------------------------------------------------------------------------
|
||||
|
||||
@callback(
|
||||
Output("store-files", "data", allow_duplicate=True),
|
||||
Input("store-files", "data"),
|
||||
@ -516,9 +1097,9 @@ def get_callbacks():
|
||||
|
||||
# Appliquer les nouveaux paramètres d'échantillonnage
|
||||
volume = pre_volume[
|
||||
::settings["echantillonage_x"],
|
||||
::settings["echantillonage_y"],
|
||||
::settings["echantillonage_z"],
|
||||
:: 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]
|
||||
@ -526,9 +1107,9 @@ def get_callbacks():
|
||||
|
||||
# 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)
|
||||
update_heatmap_ascan(0, 0, False, settings)
|
||||
update_heatmap_bscan_zx(0, False, settings)
|
||||
update_heatmap_bscan_xy(0, False, settings)
|
||||
|
||||
return None
|
||||
|
||||
@ -548,3 +1129,65 @@ def get_callbacks():
|
||||
else:
|
||||
np.save(join("Dataset/saves", filename), data_traits)
|
||||
return True
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
# ---------------------- Callbacks pour la gestion des données ------------------------
|
||||
# -------------------------------------------------------------------------------------
|
||||
|
||||
@callback(
|
||||
[
|
||||
Output("heatmap-ascan", "figure", allow_duplicate=True),
|
||||
Output("heatmap-bscan-xy", "figure", allow_duplicate=True),
|
||||
Output("heatmap-bscan-zx", "figure", allow_duplicate=True),
|
||||
],
|
||||
Input("crop-slider", "value"),
|
||||
[
|
||||
State("store-bscan-zx-layer", "data"),
|
||||
State("store-bscan-xy-layer", "data"),
|
||||
State("store-settings", "data"),
|
||||
],
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def update_scans(layer, layer1, layer2, settings):
|
||||
y_min, y_max = layer
|
||||
if settings["apply_sampling_everywhere"]:
|
||||
data = volume
|
||||
else:
|
||||
data = pre_volume
|
||||
|
||||
fig = px.line(
|
||||
y=data[layer1 - 1, int(y_min) : int(y_max), layer2], title="A-scan"
|
||||
)
|
||||
fig2 = go.Figure(
|
||||
data=go.Heatmap(
|
||||
z=data[:, int(y_min) : int(y_max), layer2], colorscale="Jet"
|
||||
)
|
||||
)
|
||||
fig2.add_shape(
|
||||
type="line",
|
||||
x0=0 - 1,
|
||||
y0=layer1,
|
||||
x1=y_max,
|
||||
y1=layer1,
|
||||
line=dict(color="white", width=1),
|
||||
)
|
||||
fig2.update_layout(
|
||||
title="B-scan XY", autosize=True, dragmode="zoom", clickmode="event+select"
|
||||
)
|
||||
fig3 = px.imshow(
|
||||
data[layer1 - 1, int(y_min) : int(y_max), :],
|
||||
color_continuous_scale="Jet",
|
||||
aspect="auto",
|
||||
title="B-scan ZX",
|
||||
)
|
||||
fig3.add_shape(
|
||||
type="line",
|
||||
x0=layer2,
|
||||
y0=0,
|
||||
x1=layer2,
|
||||
y1=y_max,
|
||||
line=dict(color="white", width=1),
|
||||
)
|
||||
fig3.update_layout(autosize=True, dragmode="zoom", clickmode="event+select")
|
||||
|
||||
return [fig, fig2, fig3]
|
||||
|
@ -49,4 +49,33 @@ db.close()
|
||||
timestamp_end = datetime.datetime.now()
|
||||
totaltime = timestamp_end - timestamp_start
|
||||
|
||||
print('Done in', totaltime.microseconds / 1000, 'ms!')
|
||||
print('Done in', totaltime.microseconds / 1000, 'ms!')
|
||||
|
||||
if input("Do you want to display the 3D volume? (y/n) ") == "y":
|
||||
import plotly.graph_objects as go
|
||||
|
||||
# on récupère les données de la base de données pour les afficher
|
||||
db = sqlite3.connect('data.sqlite')
|
||||
cursor = db.cursor()
|
||||
cursor.execute('SELECT * FROM volume')
|
||||
rows = cursor.fetchall()
|
||||
db.close()
|
||||
|
||||
volume = np.zeros((dim_x, dim_y, dim_z))
|
||||
for row in rows:
|
||||
x, y, z, value = row
|
||||
volume[x, y, z] = value
|
||||
|
||||
fig = go.Figure(data=go.Volume(
|
||||
x=X.flatten(),
|
||||
y=Y.flatten(),
|
||||
z=Z.flatten(),
|
||||
value=volume.flatten(),
|
||||
isomin=0,
|
||||
isomax=volume.max(),
|
||||
opacity=0.1, # needs to be small to see through all surfaces
|
||||
surface_count=21, # needs to be a large number for good volume rendering
|
||||
))
|
||||
fig.show()
|
||||
|
||||
input("Press Enter to continue...")
|
@ -1,7 +1,7 @@
|
||||
import dash
|
||||
from dash import dcc, html, ALL, DiskcacheManager
|
||||
import dash_bootstrap_components as dbc
|
||||
from os import listdir, mkdir
|
||||
from os import listdir, mkdir, path
|
||||
from os.path import isfile, join
|
||||
import diskcache
|
||||
from json import load
|
||||
@ -351,7 +351,13 @@ nav_bar = dbc.Navbar(
|
||||
dbc.NavItem(button_settings),
|
||||
dbc.NavItem(button_open),
|
||||
dbc.NavItem(button_save),
|
||||
dbc.Label(id="opened-file", style={"marginLeft": "10px", "padding": "0 auto"}),
|
||||
dbc.Label(
|
||||
id="opened-file",
|
||||
style={
|
||||
"marginLeft": "10px",
|
||||
"padding": "0 auto",
|
||||
},
|
||||
),
|
||||
],
|
||||
className="ml-auto",
|
||||
navbar=True,
|
||||
@ -367,7 +373,7 @@ nav_bar = dbc.Navbar(
|
||||
modal_open,
|
||||
modal_save,
|
||||
navmenu,
|
||||
save_toast
|
||||
save_toast,
|
||||
],
|
||||
align="center",
|
||||
style={"width": "100%"},
|
||||
@ -382,6 +388,7 @@ nav_bar = dbc.Navbar(
|
||||
# on défini le layout de l'application
|
||||
app.layout = dbc.Container(
|
||||
[
|
||||
dcc.Location(id="loc", refresh=False),
|
||||
nav_bar,
|
||||
dash.page_container,
|
||||
dcc.Store(
|
||||
@ -397,7 +404,12 @@ app.layout = dbc.Container(
|
||||
),
|
||||
dcc.Store(id="store-filters", data={}),
|
||||
dcc.Store(id="store-files"),
|
||||
dcc.Store(id="ascan-settings"),
|
||||
dcc.Store(id="3dplot-settings"),
|
||||
dcc.Store(id="bscan-zx-settings"),
|
||||
dcc.Store(id="bscan-xy-settings"),
|
||||
],
|
||||
id="app-container",
|
||||
fluid=True,
|
||||
)
|
||||
|
||||
@ -405,4 +417,6 @@ 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
|
||||
)
|
||||
|
@ -74,7 +74,7 @@ layout = html.Div(
|
||||
dbc.Select(
|
||||
id="select-ascan-filter1",
|
||||
options=[
|
||||
{"label": "Transformer du Hilbert", "value": "1"},
|
||||
{"label": "Transformée de Hilbert", "value": "1"},
|
||||
],
|
||||
value=1,
|
||||
style={"margin-bottom": "15px"},
|
||||
|
@ -112,12 +112,26 @@ mesh_card = dbc.Fade(
|
||||
className="card-title",
|
||||
style={"textAlign": "left"},
|
||||
),
|
||||
dbc.Button(
|
||||
html.I(className="bi bi-arrows-fullscreen"),
|
||||
id="fullscreen-button-3dplot",
|
||||
className="mb-3",
|
||||
color="primary",
|
||||
style={"marginBottom": "15px"},
|
||||
html.Div(
|
||||
[
|
||||
dbc.Button(
|
||||
html.I(className="bi bi-gear-wide"),
|
||||
id="settings-button-3dplot",
|
||||
className="mb-3",
|
||||
color="secondary",
|
||||
style={
|
||||
"marginBottom": "15px",
|
||||
"marginRight": "5px",
|
||||
},
|
||||
),
|
||||
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"},
|
||||
@ -128,31 +142,39 @@ mesh_card = dbc.Fade(
|
||||
config=config3DPlot,
|
||||
style={"marginBottom": "15px"},
|
||||
), # 'fig' is your 3D plotly figure
|
||||
dcc.Slider(
|
||||
id="iso-slider",
|
||||
min=0,
|
||||
max=volume.max() / 2,
|
||||
value=0,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
int(volume.max() / 2) + 1,
|
||||
int(volume.max() / 20),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="iso-slider",
|
||||
min=0,
|
||||
max=volume.max() / 2,
|
||||
value=0,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(
|
||||
0,
|
||||
int(volume.max() / 2) + 1,
|
||||
int(volume.max() / 20),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
),
|
||||
id="iso-slider-container",
|
||||
),
|
||||
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,
|
||||
html.Div(
|
||||
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,
|
||||
),
|
||||
id="y-slider-container",
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
@ -165,38 +187,47 @@ mesh_card = dbc.Fade(
|
||||
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())
|
||||
/ 20
|
||||
),
|
||||
)
|
||||
},
|
||||
step=1,
|
||||
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",
|
||||
),
|
||||
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,
|
||||
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",
|
||||
),
|
||||
]
|
||||
),
|
||||
@ -204,7 +235,57 @@ mesh_card = dbc.Fade(
|
||||
id="modal-3dplot",
|
||||
fullscreen=True,
|
||||
),
|
||||
]
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("3D plot settings")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
html.Span("Card display: "),
|
||||
dbc.Checklist(
|
||||
options=[
|
||||
{
|
||||
"label": "Show iso slider",
|
||||
"value": "iso_slider",
|
||||
},
|
||||
{
|
||||
"label": "Show Y slider",
|
||||
"value": "y_slider",
|
||||
},
|
||||
],
|
||||
id="checklist-3dplot-card-settings",
|
||||
),
|
||||
html.Span("Fullscreen display: "),
|
||||
dbc.Checklist(
|
||||
options=[
|
||||
{
|
||||
"label": "Show iso slider",
|
||||
"value": "iso_slider",
|
||||
},
|
||||
{
|
||||
"label": "Show Y slider",
|
||||
"value": "y_slider",
|
||||
},
|
||||
],
|
||||
id="checklist-3dplot-fullscreen-settings",
|
||||
),
|
||||
]
|
||||
),
|
||||
dbc.ModalFooter(
|
||||
[
|
||||
dbc.Button(
|
||||
"Save",
|
||||
id="save-settings-3dplot",
|
||||
className="ml-auto",
|
||||
color="primary",
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
id="modal-settings-3dplot",
|
||||
fullscreen=False,
|
||||
),
|
||||
],
|
||||
style={"height": "610px"},
|
||||
)
|
||||
]
|
||||
),
|
||||
@ -226,12 +307,26 @@ Ascan_card = dbc.Fade(
|
||||
className="card-title",
|
||||
style={"textAlign": "left"},
|
||||
),
|
||||
dbc.Button(
|
||||
html.I(className="bi bi-arrows-fullscreen"),
|
||||
id="fullscreen-button-ascan",
|
||||
className="mb-3",
|
||||
color="primary",
|
||||
style={"marginBottom": "15px"},
|
||||
html.Div(
|
||||
[
|
||||
dbc.Button(
|
||||
html.I(className="bi bi-gear-wide"),
|
||||
id="settings-button-ascan",
|
||||
className="mb-3",
|
||||
color="secondary",
|
||||
style={
|
||||
"marginBottom": "15px",
|
||||
"marginRight": "5px",
|
||||
},
|
||||
),
|
||||
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"},
|
||||
@ -241,6 +336,20 @@ Ascan_card = dbc.Fade(
|
||||
config=configAScan,
|
||||
style={"marginBottom": "15px"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
html.Div(
|
||||
dcc.RangeSlider(
|
||||
id="crop-slider",
|
||||
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-container",
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("A-Scan")),
|
||||
@ -251,18 +360,59 @@ Ascan_card = dbc.Fade(
|
||||
config=configAScan,
|
||||
style={"marginBottom": "15px"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
dcc.Slider(
|
||||
id="layer-slider-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))
|
||||
)
|
||||
},
|
||||
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",
|
||||
),
|
||||
]
|
||||
),
|
||||
@ -270,8 +420,57 @@ Ascan_card = dbc.Fade(
|
||||
id="modal-ascan",
|
||||
fullscreen=True,
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("A-Scan settings")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
html.Span("Card display: "),
|
||||
dbc.Checklist(
|
||||
options=[
|
||||
{
|
||||
"label": "Show crop slider",
|
||||
"value": "crop_slider",
|
||||
},
|
||||
],
|
||||
id="checklist-ascan-card-settings",
|
||||
),
|
||||
html.Span("Fullscreen display: "),
|
||||
dbc.Checklist(
|
||||
options=[
|
||||
{
|
||||
"label": "Show layer slider X",
|
||||
"value": "layer_slider_x",
|
||||
},
|
||||
{
|
||||
"label": "Show layer slider Z",
|
||||
"value": "layer_slider_z",
|
||||
},
|
||||
{
|
||||
"label": "Show crop slider",
|
||||
"value": "crop_slider",
|
||||
},
|
||||
],
|
||||
id="checklist-ascan-fullscreen-settings",
|
||||
),
|
||||
]
|
||||
),
|
||||
dbc.ModalFooter(
|
||||
[
|
||||
dbc.Button(
|
||||
"Save",
|
||||
id="save-settings-ascan",
|
||||
className="ml-auto",
|
||||
color="primary",
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
id="modal-settings-ascan",
|
||||
fullscreen=False,
|
||||
),
|
||||
],
|
||||
style={"height": "599px"},
|
||||
style={"height": "610px"},
|
||||
)
|
||||
],
|
||||
),
|
||||
@ -293,12 +492,26 @@ Bscan_card_xy = dbc.Fade(
|
||||
className="card-title",
|
||||
style={"textAlign": "left"},
|
||||
),
|
||||
dbc.Button(
|
||||
html.I(className="bi bi-arrows-fullscreen"),
|
||||
id="fullscreen-button-bscan-zx",
|
||||
className="mb-3",
|
||||
color="primary",
|
||||
style={"marginBottom": "15px"},
|
||||
html.Div(
|
||||
[
|
||||
dbc.Button(
|
||||
html.I(className="bi bi-gear-wide"),
|
||||
id="settings-button-bscan-zx",
|
||||
className="mb-3",
|
||||
color="secondary",
|
||||
style={
|
||||
"marginBottom": "15px",
|
||||
"marginRight": "5px",
|
||||
},
|
||||
),
|
||||
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"},
|
||||
@ -308,16 +521,19 @@ Bscan_card_xy = dbc.Fade(
|
||||
config=configBScanZX,
|
||||
style={"marginBottom": "15px"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-zx",
|
||||
min=0,
|
||||
max=dim_x - 1,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_x, max(1, int(dim_x / 20)))
|
||||
},
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-zx",
|
||||
min=0,
|
||||
max=dim_x - 1,
|
||||
value=0,
|
||||
step=1,
|
||||
marks={
|
||||
str(i): str(i)
|
||||
for i in range(0, dim_x, max(1, int(dim_x / 20)))
|
||||
},
|
||||
),
|
||||
id="layer-slider-bscan-zx-container",
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
@ -329,18 +545,23 @@ Bscan_card_xy = dbc.Fade(
|
||||
config=configBScanXY,
|
||||
style={"marginBottom": "15px", "height": "90%"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
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))
|
||||
)
|
||||
},
|
||||
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",
|
||||
),
|
||||
]
|
||||
),
|
||||
@ -348,6 +569,55 @@ Bscan_card_xy = dbc.Fade(
|
||||
id="modal-bscan-zx",
|
||||
fullscreen=True,
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("B-Scan ZX settings")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
html.Span("Card display: "),
|
||||
dbc.Checklist(
|
||||
options=[
|
||||
{
|
||||
"label": "Show X slider",
|
||||
"value": "x_slider",
|
||||
}
|
||||
],
|
||||
id="checklist-bscan-zx-card-settings",
|
||||
),
|
||||
html.Span("Fullscreen display: "),
|
||||
dbc.Checklist(
|
||||
options=[
|
||||
{
|
||||
"label": "Show X slider",
|
||||
"value": "x_slider",
|
||||
},
|
||||
{
|
||||
"label": "Show Y slider",
|
||||
"value": "y_slider",
|
||||
},
|
||||
{
|
||||
"label": "Show crop slider",
|
||||
"value": "crop_slider",
|
||||
},
|
||||
],
|
||||
id="checklist-bscan-zx-fullscreen-settings",
|
||||
),
|
||||
]
|
||||
),
|
||||
dbc.ModalFooter(
|
||||
[
|
||||
dbc.Button(
|
||||
"Save",
|
||||
id="save-settings-bscan-zx",
|
||||
className="ml-auto",
|
||||
color="primary",
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
id="modal-settings-bscan-zx",
|
||||
fullscreen=False,
|
||||
),
|
||||
]
|
||||
)
|
||||
]
|
||||
@ -370,12 +640,30 @@ Bscan_card_zx = dbc.Fade(
|
||||
className="card-title",
|
||||
style={"textAlign": "left"},
|
||||
),
|
||||
dbc.Button(
|
||||
html.I(className="bi bi-arrows-fullscreen"),
|
||||
id="fullscreen-button-bscan-xy",
|
||||
className="mb-3",
|
||||
color="primary",
|
||||
style={"marginBottom": "15px"},
|
||||
html.Div(
|
||||
[
|
||||
dbc.Button(
|
||||
html.I(className="bi bi-gear-wide"),
|
||||
id="settings-button-bscan-xy",
|
||||
className="mb-3",
|
||||
color="secondary",
|
||||
style={
|
||||
"marginBottom": "15px",
|
||||
"marginRight": "5px",
|
||||
},
|
||||
),
|
||||
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",
|
||||
},
|
||||
),
|
||||
],
|
||||
style={"display": "flex", "justifyContent": "space-between"},
|
||||
@ -385,16 +673,19 @@ Bscan_card_zx = dbc.Fade(
|
||||
config=configBScanXY,
|
||||
style={"marginBottom": "15px"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-xy",
|
||||
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)))
|
||||
},
|
||||
html.Div(
|
||||
dcc.Slider(
|
||||
id="layer-slider-bscan-xy",
|
||||
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="layer-slider-bscan-xy-container",
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
@ -406,18 +697,23 @@ Bscan_card_zx = dbc.Fade(
|
||||
config=configBScanXY,
|
||||
style={"marginBottom": "15px", "height": "90%"},
|
||||
), # 'fig' is your 2D plotly figure
|
||||
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))
|
||||
)
|
||||
},
|
||||
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",
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -425,6 +721,55 @@ Bscan_card_zx = dbc.Fade(
|
||||
id="modal-bscan-xy",
|
||||
fullscreen=True,
|
||||
),
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader(dbc.ModalTitle("B-Scan XY settings")),
|
||||
dbc.ModalBody(
|
||||
[
|
||||
html.Span("Card display: "),
|
||||
dbc.Checklist(
|
||||
options=[
|
||||
{
|
||||
"label": "Show X slider",
|
||||
"value": "x_slider",
|
||||
}
|
||||
],
|
||||
id="checklist-bscan-xy-card-settings",
|
||||
),
|
||||
html.Span("Fullscreen display: "),
|
||||
dbc.Checklist(
|
||||
options=[
|
||||
{
|
||||
"label": "Show X slider",
|
||||
"value": "x_slider",
|
||||
},
|
||||
{
|
||||
"label": "Show Y slider",
|
||||
"value": "y_slider",
|
||||
},
|
||||
{
|
||||
"label": "Show crop slider",
|
||||
"value": "crop_slider",
|
||||
},
|
||||
],
|
||||
id="checklist-bscan-xy-fullscreen-settings",
|
||||
),
|
||||
]
|
||||
),
|
||||
dbc.ModalFooter(
|
||||
[
|
||||
dbc.Button(
|
||||
"Save",
|
||||
id="save-settings-bscan-xy",
|
||||
className="ml-auto",
|
||||
color="primary",
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
id="modal-settings-bscan-xy",
|
||||
fullscreen=False,
|
||||
),
|
||||
]
|
||||
)
|
||||
]
|
||||
@ -449,4 +794,4 @@ layout = html.Div(
|
||||
]
|
||||
)
|
||||
|
||||
get_callbacks()
|
||||
get_callbacks()
|
||||
|
@ -2,11 +2,10 @@ dash==2.17.0
|
||||
dash_bootstrap_components==1.6.0
|
||||
diskcache==5.6.3
|
||||
matplotlib==3.8.4
|
||||
numpy==1.26.4
|
||||
numpy==2.0.0
|
||||
pandas==2.2.2
|
||||
plotly==5.22.0
|
||||
progress==1.6
|
||||
python_igraph==0.11.5
|
||||
scikit_learn==1.5.0
|
||||
scipy==1.13.1
|
||||
tqdm==4.66.4
|
||||
|
Reference in New Issue
Block a user