Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ up the slicer (and which must be present in the layout) are:

**method `VolumeSlicer.create_overlay_data(mask, color=None)`**

Given a 3D mask array and an index, create an object that
can be used as output for `slicer.overlay_data`. The color
can be a hex color or an rgb/rgba tuple. Alternatively, color
can be a list of such colors, defining a colormap.
Given a 3D mask array, create an object that can be used as
output for `slicer.overlay_data`. Set mask to `None` to clear the mask.
The color can be a hex color or an rgb/rgba tuple. Alternatively,
color can be a list of such colors, defining a colormap.

**property `VolumeSlicer.axis`** (`int`): The axis to slice.

Expand Down
18 changes: 12 additions & 6 deletions dash_slicer/slicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,19 @@ def overlay_data(self):
return self._overlay_data

def create_overlay_data(self, mask, color=None):
"""Given a 3D mask array and an index, create an object that
can be used as output for `slicer.overlay_data`. The color
can be a hex color or an rgb/rgba tuple. Alternatively, color
can be a list of such colors, defining a colormap.
"""Given a 3D mask array, create an object that can be used as
output for `slicer.overlay_data`. Set mask to `None` to clear the mask.
The color can be a hex color or an rgb/rgba tuple. Alternatively,
color can be a list of such colors, defining a colormap.
"""
# Check the mask
if mask.dtype not in (np.bool, np.uint8):
if mask is None:
return [None for index in range(self.nslices)] # A reset
elif not isinstance(mask, np.ndarray):
raise TypeError("Mask must be an ndarray or None.")
elif mask.dtype not in (np.bool, np.uint8):
raise ValueError(f"Mask must have bool or uint8 dtype, not {mask.dtype}.")
if mask.shape != self._volume.shape:
elif mask.shape != self._volume.shape:
raise ValueError(
f"Overlay must has shape {mask.shape}, but expected {self._volume.shape}"
)
Expand All @@ -264,6 +268,8 @@ def create_overlay_data(self, mask, color=None):
# Create a colormap (list) from the given color(s)
if color is None:
colormap = discrete_colors[3:]
elif isinstance(color, str):
colormap = [color]
elif isinstance(color, (tuple, list)) and all(
isinstance(x, (int, float)) for x in color
):
Expand Down
40 changes: 40 additions & 0 deletions tests/test_slicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,43 @@ def test_scene_id_and_context_id():

# Context id's must be unique
assert s1._context_id != s2._context_id and s1._context_id != s3._context_id


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