Skip to content

Commit 75e2f8b

Browse files
surchsalmarklein
andauthored
Interactive slicer example (#48)
* simple example for interactive position set - uses input fields to both display and change slider position - uses three viewers for volume * add comments, run doc also unhide the sliders * some verbose labels in the app * removed unused imports and short description * black * flake Co-authored-by: Almar Klein <[email protected]>
1 parent 495200d commit 75e2f8b

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"""
2+
This is an example that shows how the slicer position can be both read from and written to
3+
by listening to the "drag_value" of the default slider with an auxiliary slider
4+
"""
5+
6+
import dash
7+
import dash_html_components as html
8+
from dash_slicer import VolumeSlicer
9+
import dash_core_components as dcc
10+
from dash.dependencies import Input, Output
11+
import imageio
12+
13+
14+
app = dash.Dash(__name__, update_title=None)
15+
16+
vol = imageio.volread("imageio:stent.npz")
17+
slicer0 = VolumeSlicer(app, vol, axis=0, scene_id="brain")
18+
slicer1 = VolumeSlicer(app, vol, axis=1, scene_id="brain")
19+
slicer2 = VolumeSlicer(app, vol, axis=2, scene_id="brain")
20+
21+
setpos_store = dcc.Store(
22+
id={"context": "app", "scene": slicer0.scene_id, "name": "setpos"}
23+
)
24+
25+
# Here we create an auxiliary slider for each slicer and encapsulate it inside a Div
26+
# to be added to the app layout
27+
slicer_list = [setpos_store]
28+
for sidx, slicer in enumerate([slicer0, slicer1, slicer2]):
29+
slider = dcc.Slider(id=f"slider-{sidx}", max=slicer.nslices)
30+
slicer_list.append(
31+
html.Div(
32+
[
33+
html.Pre("slicer graph"),
34+
slicer.graph,
35+
html.Pre("builtin slider"),
36+
slicer.slider,
37+
html.Pre("auxiliary slider"),
38+
slider,
39+
*slicer.stores,
40+
]
41+
)
42+
)
43+
44+
# Create a small CSS grid with Input fields and text labels to both display
45+
# the slicer axis positions and allow the user to interactively change them
46+
nav_table = html.Div(
47+
[
48+
html.Div(""),
49+
html.Div("Voxel position"),
50+
html.Div("X axis"),
51+
dcc.Input(id="x-nav", type="number", placeholder="X value"),
52+
html.Div("Y axis"),
53+
dcc.Input(id="y-nav", type="number", placeholder="Y value"),
54+
html.Div("Z axis"),
55+
dcc.Input(id="z-nav", type="number", placeholder="Z value"),
56+
],
57+
style={"display": "grid", "gridTemplateColumns": "10% 10%"},
58+
)
59+
slicer_list.append(nav_table)
60+
61+
app.layout = html.Div(
62+
style={
63+
"display": "grid",
64+
"gridTemplateColumns": "33% 33% 33%",
65+
},
66+
children=slicer_list,
67+
)
68+
69+
70+
# Take the current value from the main slider and copy it to the
71+
# auxiliary slider
72+
@app.callback(
73+
[
74+
Output("slider-0", "value"),
75+
Output("slider-1", "value"),
76+
Output("slider-2", "value"),
77+
],
78+
[
79+
Input(slicer0.slider.id, "drag_value"),
80+
Input(slicer1.slider.id, "drag_value"),
81+
Input(slicer2.slider.id, "drag_value"),
82+
],
83+
)
84+
def write_to_auxiliary_slider(x_slider, y_slider, z_slider):
85+
return x_slider, y_slider, z_slider
86+
87+
88+
# Write the values of the axiliary slider to the input fields in the navigation table
89+
@app.callback(
90+
[Output("x-nav", "value"), Output("y-nav", "value"), Output("z-nav", "value")],
91+
[
92+
Input("slider-0", "value"),
93+
Input("slider-1", "value"),
94+
Input("slider-2", "value"),
95+
],
96+
)
97+
def write_to_position_table(x_val, y_val, z_val):
98+
return x_val, y_val, z_val
99+
100+
101+
# Listen for a user-triggered change to the value of the Input fields in the navigation table
102+
# and set the position of the slicer accordingly
103+
@app.callback(
104+
Output(setpos_store.id, "data"),
105+
[
106+
Input("x-nav", "value"),
107+
Input("y-nav", "value"),
108+
Input("z-nav", "value"),
109+
],
110+
)
111+
def write_table_values_to_slicer(x_pos, y_pos, z_pos):
112+
return z_pos, y_pos, x_pos
113+
114+
115+
if __name__ == "__main__":
116+
# Note: dev_tools_props_check negatively affects the performance of VolumeSlicer
117+
app.run_server(debug=True, dev_tools_props_check=False)

0 commit comments

Comments
 (0)