Skip to content

Commit f61da9c

Browse files
committed
ENH: Add clicked_slice_point trait
Provides the index, position, value and label associated with the point clicked on the image slice.
1 parent d657c79 commit f61da9c

File tree

5 files changed

+827
-548
lines changed

5 files changed

+827
-548
lines changed

itkwidgets/trait_types.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
pass
1818

1919
from ._transform_types import to_itk_image, to_point_set, to_geometry
20+
from ipydatawidgets import array_serialization
2021

2122
# from IPython.core.debugger import set_trace
2223

@@ -252,12 +253,61 @@ def itkimage_from_json(js, manager=None):
252253
row, col, directionJs[col + row * Dimension])
253254
return image
254255

255-
256256
itkimage_serialization = {
257257
'from_json': itkimage_from_json,
258258
'to_json': itkimage_to_json
259259
}
260260

261+
class ImagePoint(object):
262+
"""Data from a picked point on an image slice."""
263+
264+
def __init__(self, index=None, position=None, value=None, label=None):
265+
self.index = index
266+
self.position = position
267+
self.value = value
268+
self.label = label
269+
270+
def __str__(self):
271+
return 'index: {0}, position: {1}, value: {2}, label: {3}'.format(
272+
self.index,
273+
self.position,
274+
self.value,
275+
self.label)
276+
277+
class ImagePointTrait(traitlets.Instance):
278+
"""A trait type holding an data from a picked point on an image slice."""
279+
280+
info_text = 'Data from a picked point on an image'
281+
282+
klass = ImagePoint
283+
284+
def image_point_from_json(js, manager=None):
285+
if js is None:
286+
return None
287+
else:
288+
return ImagePoint(
289+
index = array_serialization['from_json'](js['index'], manager),
290+
position = array_serialization['from_json'](js['position'], manager),
291+
value = array_serialization['from_json'](js['value'], manager),
292+
label = int(js['label']),
293+
)
294+
295+
def image_point_to_json(image_point, manager=None):
296+
if image_point is None:
297+
return None
298+
else:
299+
return {
300+
'index': array_serialization['to_json'](image_point.index, manager),
301+
'position': array_serialization['to_json'](image_point.position,
302+
manager),
303+
'value': array_serialization['to_json'](image_point.value, manager),
304+
'label': int(image_point.label, manager),
305+
}
306+
307+
image_point_serialization = {
308+
'from_json': image_point_from_json,
309+
'to_json': image_point_to_json
310+
}
261311

262312
class PolyDataList(traitlets.TraitType):
263313
"""A trait type holding a list of Python data structures compatible with vtk.js.

itkwidgets/widget_viewer.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import itk
1616
import numpy as np
1717
import ipywidgets as widgets
18-
from traitlets import CBool, CFloat, Unicode, CaselessStrEnum, List, validate
18+
from traitlets import CBool, CFloat, CInt, Unicode, CaselessStrEnum, List, validate
1919
from ipydatawidgets import NDArray, array_serialization, shape_constraints
20-
from .trait_types import ITKImage, PointSetList, PolyDataList, itkimage_serialization, polydata_list_serialization, Colormap
20+
from .trait_types import ITKImage, ImagePointTrait, ImagePoint, PointSetList, PolyDataList, itkimage_serialization, image_point_serialization, polydata_list_serialization, Colormap
2121

2222
try:
2323
import ipywebrtc
@@ -170,6 +170,12 @@ class Viewer(ViewerParent):
170170
default_value=None,
171171
allow_none=True,
172172
help="World-space position of the Z slicing plane.").tag(sync=True)
173+
clicked_slice_point = ImagePointTrait(
174+
default_value=None,
175+
allow_none=True,
176+
help="Data for the point clicked on an image slice.").tag(
177+
sync=True,
178+
**image_point_serialization)
173179
gradient_opacity = CFloat(
174180
default_value=0.2,
175181
help="Volume rendering gradient opacity, from (0.0, 1.0]").tag(sync=True)
@@ -306,6 +312,9 @@ def __init__(self, **kwargs): # noqa: C901
306312
opacities_array = self._validate_geometry_opacities(proposal)
307313
kwargs['geometry_opacities'] = opacities_array
308314
self.observe(self._on_geometries_changed, ['geometries'])
315+
if 'label_map' in kwargs:
316+
# Interpolation is not currently supported with label maps
317+
kwargs['interpolation'] = False
309318

310319
super(Viewer, self).__init__(**kwargs)
311320

@@ -733,6 +742,7 @@ def view(image=None, # noqa: C901
733742
734743
interpolation: bool, optional, default: True
735744
Linear as opposed to nearest neighbor interpolation for image slices.
745+
Note: Interpolation is not currently supported with label maps.
736746
737747
gradient_opacity: float, optional, default: 0.22
738748
Gradient opacity for composite volume rendering, in the range (0.0, 1.0].

0 commit comments

Comments
 (0)