def test_slicer_init(): app = dash.Dash() vol = np.random.uniform(0, 255, (100, 100, 100)).astype(np.uint8) # Need a valid volume with raises(TypeError): VolumeSlicer(app, [3, 4, 5]) with raises(TypeError): VolumeSlicer(app, vol[0]) # Need a valid axis with raises(ValueError): VolumeSlicer(app, vol, axis=4) # Need a valide thumbnail with raises(ValueError): VolumeSlicer(app, vol, thumbnail=20.2) # This works s = VolumeSlicer(app, vol) # Check properties assert isinstance(s.graph, dcc.Graph) assert isinstance(s.slider, dcc.Slider) assert isinstance(s.stores, list) assert all( isinstance(store, (dcc.Store, dcc.Interval)) for store in s.stores)
def test_slicer_thumbnail(): app = dash.Dash() vol = np.random.uniform(0, 255, (100, 100, 100)).astype(np.uint8) _ = VolumeSlicer(app, vol) # Test for name pattern of server-side callback when thumbnails are used assert any(["server-data.data" in key for key in app.callback_map]) app = dash.Dash() _ = VolumeSlicer(app, vol, thumbnail=False) # No server-side callbacks when no thumbnails are used assert not any(["server-data.data" in key for key in app.callback_map])
def test_scene_id_and_context_id(): app = dash.Dash() vol = np.random.uniform(0, 255, (100, 100, 100)).astype(np.uint8) s1 = VolumeSlicer(app, vol, axis=0) s2 = VolumeSlicer(app, vol, axis=0) s3 = VolumeSlicer(app, vol, axis=1) # The scene id's are equal, so indicators will match up assert s1.scene_id == s2.scene_id and s1.scene_id == s3.scene_id # Context id's must be unique assert s1._context_id != s2._context_id and s1._context_id != s3._context_id
def test_clim(): app = dash.Dash() vol = np.random.uniform(0, 255, (10, 10, 10)).astype(np.uint8) mi, ma = vol.min(), vol.max() s = VolumeSlicer(app, vol) assert s._initial_clim == (mi, ma) s = VolumeSlicer(app, vol, clim=None) assert s._initial_clim == (mi, ma) s = VolumeSlicer(app, vol, clim=(10, 12)) assert s._initial_clim == (10, 12) # Fails with raises(TypeError): VolumeSlicer(app, vol, clim=10) with raises(TypeError): VolumeSlicer(app, vol, clim=(10, 12, 14))
def test_slice(): app = dash.Dash() vol = np.random.uniform(0, 255, (10, 20, 30)).astype(np.uint8) s = VolumeSlicer(app, vol, axis=0) im = s._slice(1, (0, 100)) assert im.dtype == np.uint8 assert im.shape == (20, 30) s = VolumeSlicer(app, vol, axis=1) im = s._slice(1, (0, 100)) assert im.dtype == np.uint8 assert im.shape == (10, 30) s = VolumeSlicer(app, vol, axis=2) im = s._slice(1, (0, 100)) assert im.dtype == np.uint8 assert im.shape == (10, 20)
def test_slicer_thumbnail(): vol = np.random.uniform(0, 255, (100, 100, 100)).astype(np.uint8) app = dash.Dash() _ = VolumeSlicer(app, vol) # Test for name pattern of server-side callback when thumbnails are used assert any(["server-data.data" in key for key in app.callback_map]) app = dash.Dash() _ = VolumeSlicer(app, vol, thumbnail=False) # No server-side callbacks when no thumbnails are used assert not any(["server-data.data" in key for key in app.callback_map]) # Default thumbnail size s = VolumeSlicer(app, vol) assert s._slice_info["thumbnail_size"] == (32, 32) # Custom size s = VolumeSlicer(app, vol, thumbnail=20) assert s._slice_info["thumbnail_size"] == (20, 20) s = VolumeSlicer(app, vol, thumbnail=50) assert s._slice_info["thumbnail_size"] == (50, 50) # Custom but too big s = VolumeSlicer(app, vol, thumbnail=102) assert s._slice_info["thumbnail_size"] == (100, 100) # Disable s = VolumeSlicer(app, vol, thumbnail=False) assert s._slice_info["thumbnail_size"] == (100, 100) s = VolumeSlicer(app, vol, thumbnail=0) assert s._slice_info["thumbnail_size"] == (100, 100) s = VolumeSlicer(app, vol, thumbnail=-1) assert s._slice_info["thumbnail_size"] == (100, 100) # None is simply not allowed - removes ambiguity about # whether None means no-thumbnails, or the default size with raises(TypeError): VolumeSlicer(app, vol, thumbnail=None)
def test_slicer_init(): app = dash.Dash() vol = np.random.uniform(0, 255, (100, 100, 100)).astype(np.uint8) # Need a dash app with raises(TypeError): VolumeSlicer("not a dash app", vol) # Need a valid volume with raises(TypeError): VolumeSlicer(app, [3, 4, 5]) with raises(TypeError): VolumeSlicer(app, vol[0]) # Need a valid axis with raises(ValueError): VolumeSlicer(app, vol, axis=4) # Need a valide thumbnail with raises(TypeError): VolumeSlicer(app, vol, thumbnail=20.2) # Need a valide scene id with raises(TypeError): VolumeSlicer(app, vol, scene_id=20) # This works s = VolumeSlicer(app, vol) # Check properties assert s.axis == 0 assert isinstance(s.graph, dcc.Graph) assert isinstance(s.slider, dcc.Slider) assert isinstance(s.stores, list) assert all( isinstance(store, (dcc.Store, dcc.Interval)) for store in s.stores) for store in [s.clim, s.state, s.extra_traces, s.overlay_data]: assert isinstance(store, dcc.Store)
def test_create_overlay_data(): app = dash.Dash() vol = np.random.uniform(0, 255, (100, 100, 100)).astype(np.uint8) s = VolumeSlicer(app, vol) # Bool overlay overlay = s.create_overlay_data(vol > 10) assert isinstance(overlay, list) and len(overlay) == s.nslices assert all(isinstance(x, str) for x in overlay) # Reset overlay = s.create_overlay_data(None) assert isinstance(overlay, list) and len(overlay) == s.nslices assert all(x is None for x in overlay) # Reset by zero mask overlay = s.create_overlay_data(vol > 300) assert isinstance(overlay, list) and len(overlay) == s.nslices assert all(x is None for x in overlay) # Wrong with raises(ValueError): s.create_overlay_data(vol[:-1]) # wrong shape
import dash import dash_html_components as html from dash_slicer import VolumeSlicer import imageio app = dash.Dash(__name__, update_title=None) vol1 = imageio.volread("imageio:stent.npz") vol2 = vol1[::3, ::2, :] spacing = 3, 2, 1 ori = 1000, 2000, 3000 slicer1 = VolumeSlicer(app, vol1, axis=1, origin=ori, scene_id="scene1", color="red") slicer2 = VolumeSlicer(app, vol1, axis=0, origin=ori, scene_id="scene1", color="green") slicer3 = VolumeSlicer(app, vol2, axis=0, origin=ori, spacing=spacing, scene_id="scene1", color="blue")
import plotly import dash import dash_html_components as html import dash_core_components as dcc from dash.dependencies import Input, Output from dash_slicer import VolumeSlicer import imageio from skimage import measure app = dash.Dash(__name__, update_title=None) server = app.server vol = imageio.volread("imageio:stent.npz") mi, ma = vol.min(), vol.max() slicer = VolumeSlicer(app, vol) app.layout = html.Div([ slicer.graph, slicer.slider, dcc.Slider( id="level-slider", min=mi, max=ma, step=1, value=mi + 0.2 * (ma - mi), ), *slicer.stores, ])
spacing = abs(mat[2, 2]), abs(mat[1, 1]), abs(mat[0, 0]) # Create smoothed image and histogram med_img = filters.median(img, selem=np.ones((1, 3, 3), dtype=np.bool)) hi = exposure.histogram(med_img) # Create mesh verts, faces, _, _ = measure.marching_cubes(med_img, 200, step_size=5) x, y, z = verts.T i, j, k = faces.T fig_mesh = go.Figure() fig_mesh.add_trace(go.Mesh3d(x=z, y=y, z=x, opacity=0.2, i=k, j=j, k=i)) # Create slicers slicer1 = VolumeSlicer(app, img, axis=0, spacing=spacing, thumbnail=False) slicer1.graph.figure.update_layout( dragmode="drawclosedpath", newshape_line_color="cyan" ) slicer1.graph.config.update( modeBarButtonsToAdd=["drawclosedpath", "eraseshape",] ) slicer2 = VolumeSlicer(app, img, axis=1, spacing=spacing, thumbnail=False) slicer2.graph.figure.update_layout(dragmode="drawrect", newshape_line_color="cyan") slicer2.graph.config.update( modeBarButtonsToAdd=["drawrect", "eraseshape",] ) def path_to_coords(path):
# Load the initial data (table, description, reference, conn_mat, parcellation) = get_atlas(atlas_keys[0]) region_labels = table["Region Name"] vol = template_img.get_fdata().squeeze() parcellation_colormap = px.colors.qualitative.Alphabet connectivity_colormap = [[ val, px.colors.label_rgb( plt.cm.plasma(val, alpha=1 if not val == 0 else 0, bytes=True)), ] for val in np.linspace(0, 1, 100)] sagittal_slicer = VolumeSlicer(app, vol, axis=0, scene_id="brain", color="white") coronal_slicer = VolumeSlicer(app, vol, axis=1, scene_id="brain", color="white") axial_slicer = VolumeSlicer(app, vol, axis=2, scene_id="brain", color="white") # Update all slicers in order slicer_list = [] for slicer_idx, slicer in enumerate( [sagittal_slicer, coronal_slicer, axial_slicer]): slicer.graph.figure.update_layout(dragmode=False, plot_bgcolor="rgb(0, 0, 0)")
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 from skimage.measure import marching_cubes import imageio app = dash.Dash(__name__, update_title=None) server = app.server # Read volumes and create slicer objects vol = imageio.volread("imageio:stent.npz") slicer0 = VolumeSlicer(app, vol, clim=(0, 800), axis=0) slicer1 = VolumeSlicer(app, vol, clim=(0, 800), axis=1) slicer2 = VolumeSlicer(app, vol, clim=(0, 800), axis=2) # Calculate isosurface and create a figure with a mesh object verts, faces, _, _ = marching_cubes(vol, 300, step_size=4) x, y, z = verts.T i, j, k = faces.T mesh = go.Mesh3d(x=z, y=y, z=x, opacity=0.2, i=k, j=j, k=i) fig = go.Figure(data=[mesh]) fig.update_layout(uirevision="anything") # prevent orientation reset on update # Put everything together in a 2x2 grid app.layout = html.Div( style={
def test_create_overlay_data(): app = dash.Dash() vol = np.random.uniform(0, 255, (100, 100, 100)).astype(np.uint8) s = VolumeSlicer(app, vol) # Bool overlay overlay = s.create_overlay_data(vol > 10) assert isinstance(overlay, list) and len(overlay) == s.nslices assert all(isinstance(x, str) for x in overlay) # Bool overlay - with color overlay = s.create_overlay_data(vol > 10, "#ff0000") assert isinstance(overlay, list) and len(overlay) == s.nslices assert all(isinstance(x, str) for x in overlay) # Uint8 overlay - with colormap overlay = s.create_overlay_data(vol.astype(np.uint8), ["#ff0000", "#00ff00"]) assert isinstance(overlay, list) and len(overlay) == s.nslices assert all(isinstance(x, str) for x in overlay) # Reset overlay = s.create_overlay_data(None) assert isinstance(overlay, list) and len(overlay) == s.nslices assert all(x is None for x in overlay) # Reset by zero mask overlay = s.create_overlay_data(vol > 300) assert isinstance(overlay, list) and len(overlay) == s.nslices assert all(x is None for x in overlay) # Wrong with raises(TypeError): s.create_overlay_data("not a valid mask") with raises(ValueError): s.create_overlay_data(vol.astype(np.float32)) # wrong dtype with raises(ValueError): s.create_overlay_data(vol[:-1]) # wrong shape
import imageio from skimage import measure 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="#00ff99")
""" This is an example that shows how the slicer position can be both read from and written to by listening to the "drag_value" of the default slider with an auxiliary slider """ import dash import dash_html_components as html from dash_slicer import VolumeSlicer import dash_core_components as dcc from dash.dependencies import Input, Output import imageio app = dash.Dash(__name__, update_title=None) vol = imageio.volread("imageio:stent.npz") slicer0 = VolumeSlicer(app, vol, axis=0, scene_id="brain") slicer1 = VolumeSlicer(app, vol, axis=1, scene_id="brain") slicer2 = VolumeSlicer(app, vol, axis=2, scene_id="brain") setpos_store = dcc.Store(id={ "context": "app", "scene": slicer0.scene_id, "name": "setpos" }) # Here we create an auxiliary slider for each slicer and encapsulate it inside a Div # to be added to the app layout slicer_list = [setpos_store] for sidx, slicer in enumerate([slicer0, slicer1, slicer2]): slider = dcc.Slider(id=f"slider-{sidx}", max=slicer.nslices) slicer_list.append(
import dash import dash_html_components as html import imageio from dash_slicer import VolumeSlicer from apps.imagens.dash_app.utilidades.import_imagem import seleciona_lista_arquivos, import_file app = dash.Dash(__name__, update_title=None) list_imagens = seleciona_lista_arquivos(38) im = import_file(list_imagens) slicer = VolumeSlicer(app, im) app.layout = html.Div([slicer.graph, slicer.slider, *slicer.stores]) if __name__ == "__main__": app.run_server(debug=True, dev_tools_props_check=False)
import dash import dash_html_components as html import imageio from dash_slicer import VolumeSlicer app = dash.Dash(__name__, update_title=None) vol = imageio.volread("imageio:stent.npz") slicer0 = VolumeSlicer(app, vol, axis=0) slicer1 = VolumeSlicer(app, vol, axis=1) slicer2 = VolumeSlicer(app, vol, axis=2) slicer0.graph.config["scrollZoom"] = False slicer1.graph.config["scrollZoom"] = False slicer2.graph.config["scrollZoom"] = False app.layout = html.Div( style={ "display": "grid", "gridTemplateColumns": "33% 33% 33%", }, children=[ html.Div([slicer0.graph, html.Br(), slicer0.slider, *slicer0.stores]), html.Div([slicer1.graph, html.Br(), slicer1.slider, *slicer1.stores]), html.Div([slicer2.graph, html.Br(), slicer2.slider, *slicer2.stores]), ], ) if __name__ == "__main__":
""" import dash import dash_html_components as html import dash_core_components as dcc from dash.dependencies import Input, Output from dash_slicer import VolumeSlicer import numpy as np import imageio app = dash.Dash(__name__, update_title=None) server = app.server vol = imageio.volread("imageio:stent.npz") mi, ma = vol.min(), vol.max() slicer = VolumeSlicer(app, vol, clim=(0, 800)) app.layout = html.Div([ slicer.graph, slicer.slider, dcc.RangeSlider( id="level-slider", min=vol.min(), max=vol.max(), step=1, value=[mi + 0.1 * (ma - mi), mi + 0.3 * (ma - mi)], ), *slicer.stores, ]) # Define colormap to make the lower threshold shown in yellow, and higher in red
import dash import dash_html_components as html import imageio from dash_slicer import VolumeSlicer app = dash.Dash(__name__, update_title=None) vol = imageio.volread("imageio:stent.npz") vol = vol[::3,:,:] spacing = 3, 1, 1 slicer0 = VolumeSlicer(app, vol, spacing=spacing, axis=0) slicer1 = VolumeSlicer(app, vol, spacing=spacing, axis=1) slicer0.graph.config["scrollZoom"] = False slicer1.graph.config["scrollZoom"] = False app.layout = html.Div( style={ "display": "grid", "gridTemplateColumns": "33% 33%", }, children=[ html.Div([slicer0.graph, html.Br(), slicer0.slider, *slicer0.stores]), html.Div([slicer1.graph, html.Br(), slicer1.slider, *slicer1.stores]), ], ) if __name__ == "__main__":