From c81a0c98d2db8f0c744666e11e214266d8f43ac4 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 8 Dec 2020 17:01:33 +0100 Subject: [PATCH 1/4] tweak one example --- examples/slicer_with_3_views.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/slicer_with_3_views.py b/examples/slicer_with_3_views.py index 2462f20..c5ff1f1 100644 --- a/examples/slicer_with_3_views.py +++ b/examples/slicer_with_3_views.py @@ -17,9 +17,9 @@ # Read volumes and create slicer objects vol = imageio.volread("imageio:stent.npz") -slicer1 = VolumeSlicer(app, vol, axis=0) -slicer2 = VolumeSlicer(app, vol, axis=1) -slicer3 = VolumeSlicer(app, vol, axis=2) +slicer0 = VolumeSlicer(app, vol, axis=0) +slicer1 = VolumeSlicer(app, vol, axis=1) +slicer2 = VolumeSlicer(app, vol, axis=2) # Calculate isosurface and create a figure with a mesh object verts, faces, _, _ = marching_cubes(vol, 300, step_size=4) @@ -40,28 +40,28 @@ html.Div( [ html.Center(html.H1("Transversal")), - slicer1.graph, + slicer0.graph, html.Br(), - slicer1.slider, - *slicer1.stores, + slicer0.slider, + *slicer0.stores, ] ), html.Div( [ html.Center(html.H1("Coronal")), - slicer2.graph, + slicer1.graph, html.Br(), - slicer2.slider, - *slicer2.stores, + slicer1.slider, + *slicer1.stores, ] ), html.Div( [ html.Center(html.H1("Sagittal")), - slicer3.graph, + slicer2.graph, html.Br(), - slicer3.slider, - *slicer3.stores, + slicer2.slider, + *slicer2.stores, ] ), html.Div( @@ -102,7 +102,7 @@ } """, Output("3Dgraph", "figure"), - [Input({"scene": slicer1.scene_id, "context": ALL, "name": "state"}, "data")], + [Input({"scene": slicer0.scene_id, "context": ALL, "name": "state"}, "data")], [State("3Dgraph", "figure")], ) From fdfe5f4396d1960c51f8e42ad539d50b4d3ad0f2 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 8 Dec 2020 17:13:52 +0100 Subject: [PATCH 2/4] add example --- examples/all_features.py | 109 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 examples/all_features.py diff --git a/examples/all_features.py b/examples/all_features.py new file mode 100644 index 0000000..275aeed --- /dev/null +++ b/examples/all_features.py @@ -0,0 +1,109 @@ +""" +An example that is (tries to be) a demo of all features. +""" + +import plotly.graph_objects as go +import dash +import dash_html_components as html +import dash_core_components as dcc +from dash_slicer import VolumeSlicer +from dash.dependencies import Input, Output, State, ALL +import imageio + + +app = dash.Dash(__name__, update_title=None) +server = app.server + +# Read volume +vol = imageio.volread("imageio:stent.npz") +vol = vol[::3, :, :] +spacing = 3, 1, 1 +ori = 1000, 2000, 3000 + +# Create slicer objects +slicer0 = VolumeSlicer(app, vol, spacing=spacing, origin=ori, axis=0, thumbnail=False) +slicer1 = VolumeSlicer( + app, vol, spacing=spacing, origin=ori, axis=1, thumbnail=8, reverse_y=False +) +slicer2 = VolumeSlicer(app, vol, spacing=spacing, origin=ori, axis=2, color="#00ff77") + +# Put everything together in a 2x2 grid +app.layout = html.Div( + style={ + "display": "grid", + "gridTemplateColumns": "40% 40%", + }, + children=[ + html.Div( + [ + html.Center(html.H1("Transversal")), + slicer0.graph, + html.Br(), + slicer0.slider, + *slicer0.stores, + ] + ), + html.Div( + [ + html.Center(html.H1("Coronal")), + slicer1.graph, + html.Br(), + slicer1.slider, + *slicer1.stores, + ] + ), + html.Div( + [ + html.Center(html.H1("Sagittal")), + slicer2.graph, + html.Br(), + slicer2.slider, + *slicer2.stores, + ] + ), + html.Div( + [ + html.Center(html.H1("3D")), + dcc.Graph(id="3Dgraph", figure=go.Figure()), + ] + ), + ], +) + + +# Callback to display slicer view positions in the 3D view +app.clientside_callback( + """ +function update_3d_figure(states, ori_figure) { + let traces = []; + for (let state of states) { + if (!state) continue; + let xrange = state.xrange; + let yrange = state.yrange; + let xyz = [ + [xrange[0], xrange[1], xrange[1], xrange[0], xrange[0]], + [yrange[0], yrange[0], yrange[1], yrange[1], yrange[0]], + [state.zpos, state.zpos, state.zpos, state.zpos, state.zpos] + ]; + xyz.splice(2 - state.axis, 0, xyz.pop()); + let s = { + type: 'scatter3d', + x: xyz[0], y: xyz[1], z: xyz[2], + mode: 'lines', line: {color: state.color} + }; + traces.push(s); + } + let figure = {...ori_figure}; + figure.data = traces; + return figure; +} + """, + Output("3Dgraph", "figure"), + [Input({"scene": slicer0.scene_id, "context": ALL, "name": "state"}, "data")], + [State("3Dgraph", "figure")], +) + + +if __name__ == "__main__": + # Note: dev_tools_props_check negatively affects the performance of VolumeSlicer + app.run_server(debug=True, dev_tools_props_check=False) From b0888ecf49b68f06867782fe9f29f1ae221ccfba Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 8 Dec 2020 17:15:04 +0100 Subject: [PATCH 3/4] Use that example for deployment --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index ce1bd4f..b1eebc0 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: gunicorn examples.slicer_with_3_views:server +web: gunicorn examples.all_features:server From 4d75ff9443503603becd47e027386feea9ca8314 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Tue, 8 Dec 2020 23:20:24 +0100 Subject: [PATCH 4/4] add texts --- examples/all_features.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/examples/all_features.py b/examples/all_features.py index 275aeed..8c8997b 100644 --- a/examples/all_features.py +++ b/examples/all_features.py @@ -25,18 +25,18 @@ slicer1 = VolumeSlicer( app, vol, spacing=spacing, origin=ori, axis=1, thumbnail=8, reverse_y=False ) -slicer2 = VolumeSlicer(app, vol, spacing=spacing, origin=ori, axis=2, color="#00ff77") +slicer2 = VolumeSlicer(app, vol, spacing=spacing, origin=ori, axis=2, color="#00ff99") # Put everything together in a 2x2 grid app.layout = html.Div( style={ "display": "grid", - "gridTemplateColumns": "40% 40%", + "gridTemplateColumns": "33% 33% 33%", }, children=[ html.Div( [ - html.Center(html.H1("Transversal")), + html.Center(html.H1("Axis 0")), slicer0.graph, html.Br(), slicer0.slider, @@ -45,7 +45,7 @@ ), html.Div( [ - html.Center(html.H1("Coronal")), + html.Center(html.H1("Axis 1")), slicer1.graph, html.Br(), slicer1.slider, @@ -54,7 +54,7 @@ ), html.Div( [ - html.Center(html.H1("Sagittal")), + html.Center(html.H1("Axis 2")), slicer2.graph, html.Br(), slicer2.slider, @@ -67,6 +67,18 @@ dcc.Graph(id="3Dgraph", figure=go.Figure()), ] ), + dcc.Markdown( + """ + Take note of: + * Full-res thumbnails for axis 0. + * Very low-res thumbnails for axis 1. + * Default low-res thumbnails for axis 2. + * The `reverse_y` is false for axis 1. + * Elongated voxels for axis 1 and 2. + * An origin in the thousands, visible in the 3D view. + * A custom brighter green for axis 2. + """ + ), ], )