Skip to content

Commit 4401035

Browse files
committed
ENH: Support label_map_names
1 parent b3a0702 commit 4401035

File tree

5 files changed

+72
-23
lines changed

5 files changed

+72
-23
lines changed

examples/LabelMap.ipynb

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
},
2424
{
2525
"cell_type": "code",
26-
"execution_count": 2,
26+
"execution_count": 1,
2727
"metadata": {},
2828
"outputs": [],
2929
"source": [
@@ -38,7 +38,7 @@
3838
},
3939
{
4040
"cell_type": "code",
41-
"execution_count": 3,
41+
"execution_count": 2,
4242
"metadata": {},
4343
"outputs": [],
4444
"source": [
@@ -55,7 +55,7 @@
5555
},
5656
{
5757
"cell_type": "code",
58-
"execution_count": 4,
58+
"execution_count": 3,
5959
"metadata": {},
6060
"outputs": [],
6161
"source": [
@@ -65,27 +65,53 @@
6565
},
6666
{
6767
"cell_type": "code",
68-
"execution_count": 6,
69-
"metadata": {},
68+
"execution_count": 21,
69+
"metadata": {
70+
"scrolled": true
71+
},
7072
"outputs": [
7173
{
7274
"data": {
7375
"application/vnd.jupyter.widget-view+json": {
74-
"model_id": "7416595a86114b29b9cdd40676af0e84",
76+
"model_id": "37dcf1f9c89b4f9c8e7ab039d3f38dde",
7577
"version_major": 2,
7678
"version_minor": 0
7779
},
7880
"text/plain": [
79-
"Viewer(cmap='Grayscale', geometries=[], gradient_opacity=0.8, interpolation=False, point_sets=[], rendered_ima"
81+
"Viewer(cmap='Grayscale', geometries=[], gradient_opacity=0.5, interpolation=False, label_map_names=[(0, 'Backg"
8082
]
8183
},
8284
"metadata": {},
8385
"output_type": "display_data"
8486
}
8587
],
8688
"source": [
87-
"view(image, label_map=label_map, rotate=True, gradient_opacity=0.8)"
89+
"names = [(0, 'Background'), (1, 'First cell'), (2, 'Second cell')]\n",
90+
"viewer = view(image,\n",
91+
" label_map=label_map,\n",
92+
" label_map_names=names,\n",
93+
" rotate=True,\n",
94+
" gradient_opacity=0.5,\n",
95+
" slicing_planes=True)\n",
96+
"viewer"
8897
]
98+
},
99+
{
100+
"cell_type": "code",
101+
"execution_count": 5,
102+
"metadata": {},
103+
"outputs": [],
104+
"source": [
105+
"names = [(0, 'Background'), (1, 'First cell'), (2, 'Second cell')]\n",
106+
"viewer.label_map_names = names"
107+
]
108+
},
109+
{
110+
"cell_type": "code",
111+
"execution_count": null,
112+
"metadata": {},
113+
"outputs": [],
114+
"source": []
89115
}
90116
],
91117
"metadata": {

itkwidgets/widget_viewer.py

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

@@ -143,6 +143,12 @@ class Viewer(ViewerParent):
143143
allow_none=True).tag(
144144
sync=True,
145145
**itkimage_serialization)
146+
label_map_names = List(
147+
trait=Tuple(),
148+
allow_none=True,
149+
default_value=None,
150+
help="Names for labels in the label map.").tag(
151+
sync=True)
146152
interpolation = CBool(
147153
default_value=True,
148154
help="Use linear interpolation in slicing planes.").tag(sync=True)
@@ -649,6 +655,7 @@ def roi_slice(self):
649655

650656
def view(image=None, # noqa: C901
651657
label_map=None, # noqa: C901
658+
label_map_names=None, # noqa: C901
652659
cmap=None,
653660
select_roi=False,
654661
interpolation=True,
@@ -720,6 +727,9 @@ def view(image=None, # noqa: C901
720727
The 2D or 3D label map to visualize. If an image is also provided, the
721728
label map must have the same size.
722729
730+
label_map_names : OrderedDict of (label_value, label_name)
731+
String names associated with the integer label values.
732+
723733
vmin: float, optional, default: None
724734
Value that maps to the minimum of image colormap. Defaults to minimum of
725735
the image pixel buffer.
@@ -886,6 +896,7 @@ def view(image=None, # noqa: C901
886896

887897
viewer = Viewer(image=image,
888898
label_map=label_map,
899+
label_map_names=label_map_names,
889900
cmap=cmap,
890901
select_roi=select_roi,
891902
interpolation=interpolation,

js/lib/viewer.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ import macro from 'vtk.js/Sources/macro'
1616
const widgets = require('@jupyter-widgets/base')
1717

1818
const ANNOTATION_DEFAULT =
19-
'<table style="margin-left: 0;"><tr><td style="margin-left: auto; margin-right: 0;">Index:</td><td>${iIndex},</td><td>${jIndex},</td><td>${kIndex}</td></tr><tr><td style="margin-left: auto; margin-right: 0;">Position:</td><td>${xPosition},</td><td>${yPosition},</td><td>${zPosition}</td></tr><tr><td style="margin-left: auto; margin-right: 0;"">Value:</td><td>${value}</td></tr></table>'
19+
'<table style="margin-left: 0;"><tr><td style="margin-left: auto; margin-right: 0;">Index:</td><td>${iIndex},</td><td>${jIndex},</td><td>${kIndex}</td></tr><tr><td style="margin-left: auto; margin-right: 0;">Position:</td><td>${xPosition},</td><td>${yPosition},</td><td>${zPosition}</td></tr><tr><td style="margin-left: auto; margin-right: 0;"">Value:</td><td style="text-align:center;" colspan="3">${value}</td></tr><tr ${annotationLabelStyle}><td style="margin-left: auto; margin-right: 0;">Label:</td><td style="text-align:center;" colspan="3">${annotation}</td></tr></table>'
2020
const ANNOTATION_CUSTOM_PREFIX =
2121
'<table style="margin-left: 0;"><tr><td style="margin-left: auto; margin-right: 0;">Scale/Index:</td>'
2222
const ANNOTATION_CUSTOM_POSTFIX =
23-
'</tr><tr><td style="margin-left: auto; margin-right: 0;">Position:</td><td>${xPosition},</td><td>${yPosition},</td><td>${zPosition}</td></tr><tr><td style="margin-left: auto; margin-right: 0;"">Value:</td><td>${value}</td></tr></table>'
23+
'</tr><tr><td style="margin-left: auto; margin-right: 0;">Position:</td><td>${xPosition},</td><td>${yPosition},</td><td>${zPosition}</td></tr><tr><td style="margin-left: auto; margin-right: 0;"">Value:</td><td style="text-align:center;" colspan="3">${value}</td></tr><tr ${annotationLabelStyle}><td style="margin-left: auto; margin-right: 0;">Label:</td><td style="text-align:center;" colspan="3">${annotation}</td></tr></table>'
2424

2525
const cores = navigator.hardwareConcurrency ? navigator.hardwareConcurrency : 4
2626
const numberOfWorkers = cores + Math.floor(Math.sqrt(cores))
@@ -116,6 +116,7 @@ const ViewerModel = widgets.DOMWidgetModel.extend(
116116
_view_module_version: '0.27.5',
117117
rendered_image: null,
118118
rendered_label_map: null,
119+
label_map_names: null,
119120
_rendering_image: false,
120121
interpolation: true,
121122
cmap: 'Viridis (matplotlib)',
@@ -719,6 +720,9 @@ const ViewerView = widgets.DOMWidgetView.extend({
719720
this.select_roi_changed()
720721
this.scale_factors_changed()
721722
}
723+
if (rendered_label_map) {
724+
this.label_map_names_changed()
725+
}
722726

723727
const onUserInterfaceCollapsedToggle = (collapsed) => {
724728
if (collapsed !== this.model.get('ui_collapsed')) {
@@ -1044,6 +1048,7 @@ const ViewerView = widgets.DOMWidgetView.extend({
10441048
this.model.on('change:mode', this.mode_changed, this)
10451049
this.model.on('change:units', this.units_changed, this)
10461050
this.model.on('change:camera', this.camera_changed, this)
1051+
this.model.on('change:label_map_names', this.label_map_names_changed, this)
10471052

10481053
let toDecompress = []
10491054
const rendered_image = this.model.get('rendered_image')
@@ -1161,6 +1166,14 @@ const ViewerView = widgets.DOMWidgetView.extend({
11611166
return Promise.resolve(null)
11621167
},
11631168

1169+
label_map_names_changed: function () {
1170+
const label_map_names = this.model.get('label_map_names')
1171+
if (label_map_names && this.model.hasOwnProperty('itkVtkViewer')) {
1172+
const labelMapNames = new Map(label_map_names)
1173+
this.model.itkVtkViewer.setLabelMapNames(labelMapNames)
1174+
}
1175+
},
1176+
11641177
point_sets_changed: function () {
11651178
const point_sets = this.model.get('point_sets')
11661179
if (point_sets && !!point_sets.length) {
@@ -1524,7 +1537,7 @@ const ViewerView = widgets.DOMWidgetView.extend({
15241537
scaleFactors[1] === 1 &&
15251538
scaleFactors[2] === 1
15261539
) {
1527-
viewProxy.setCornerAnnotation('se', `${ANNOTATION_DEFAULT}`)
1540+
viewProxy.setSeCornerAnnotation(`${ANNOTATION_DEFAULT}`)
15281541
} else {
15291542
let scaleIndex = ''
15301543
if (scaleFactors[0] === 1) {
@@ -1542,8 +1555,7 @@ const ViewerView = widgets.DOMWidgetView.extend({
15421555
} else {
15431556
scaleIndex = `${scaleIndex}<td>${scaleFactors[2]}X</td>`
15441557
}
1545-
viewProxy.setCornerAnnotation(
1546-
'se',
1558+
viewProxy.setSeCornerAnnotation(
15471559
`${ANNOTATION_CUSTOM_PREFIX}${scaleIndex}${ANNOTATION_CUSTOM_POSTFIX}`
15481560
)
15491561
}

js/package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@
6363
"copy-webpack-plugin": "^5.1.1",
6464
"css-element-queries": "^1.2.3",
6565
"itk": "^13.1.0",
66-
"itk-vtk-viewer": "^10.0.0",
66+
"itk-vtk-viewer": "^10.1.0",
6767
"jupyter-dataserializers": "^2.2.0",
6868
"mobx": "^5.15.4",
6969
"regenerator-runtime": "^0.13.5",
70-
"vtk.js": "^14.1.2"
70+
"vtk.js": "^14.3.2"
7171
},
7272
"jupyterlab": {
7373
"extension": "dist/labextension"

0 commit comments

Comments
 (0)