From 17f99898b42587fd69c0bfe58e83ba52aafad5de Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 11 Dec 2020 15:06:16 +0100 Subject: [PATCH 1/3] add option to reset overlay data, plus some fixes --- dash_slicer/slicer.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/dash_slicer/slicer.py b/dash_slicer/slicer.py index 6300bb8..c011684 100644 --- a/dash_slicer/slicer.py +++ b/dash_slicer/slicer.py @@ -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}" ) @@ -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 ): From 9246cded7bd608bd19b5979f90cc7e2cab952992 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 11 Dec 2020 15:06:29 +0100 Subject: [PATCH 2/3] add tests for create_overlay_data --- tests/test_slicer.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/test_slicer.py b/tests/test_slicer.py index 089a7d2..c857b74 100644 --- a/tests/test_slicer.py +++ b/tests/test_slicer.py @@ -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 From 613ecc3b423b71af40e43881dc86fc67fea18137 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 11 Dec 2020 15:06:42 +0100 Subject: [PATCH 3/3] Update reamde --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e61b1dc..e042e12 100644 --- a/README.md +++ b/README.md @@ -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.