Example #1
0
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)
Example #2
0
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])
Example #3
0
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
Example #4
0
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))
Example #5
0
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)
Example #6
0
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)
Example #7
0
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)
Example #8
0
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
Example #9
0
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")
Example #10
0
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,
])

Example #11
0
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):
Example #12
0
# 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)")
Example #13
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={
Example #14
0
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
Example #15
0
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")
Example #16
0
"""
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)
Example #18
0
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__":
Example #19
0
"""

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
Example #20
0
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__":