Skip to content

Commit 3ea8bfe

Browse files
committed
ENH: Add vtkjs_to_zarr, zarr_to_vtkjs
1 parent 1e6331c commit 3ea8bfe

File tree

2 files changed

+138
-3
lines changed

2 files changed

+138
-3
lines changed

itkwidgets/_transform_types.py

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__all__ = ['to_itk_image', 'to_point_set', 'to_geometry']
1+
__all__ = ['to_itk_image', 'to_point_set', 'to_geometry', 'vtkjs_to_zarr', 'zarr_to_vtkjs']
22

33
import itk
44
import numpy as np
@@ -41,6 +41,77 @@ def is_arraylike(arr):
4141
have_skan = True
4242
except ImportError:
4343
pass
44+
have_zarr = False
45+
try:
46+
import zarr
47+
have_zarr = True
48+
except ImportError:
49+
pass
50+
51+
def vtkjs_to_zarr(vtkjs, group, chunks=True):
52+
"""Convert a vtk.js-like Python object to a Zarr Group.
53+
54+
Parameters
55+
----------
56+
57+
vtkjs: dictionary, required
58+
The vtk.js-like data structure to convert.
59+
60+
group: zarr.Group, required
61+
The Zarr group to store the result.
62+
63+
chunks: bool or int or tuple of ints, optional
64+
The chunk size passed to zarr.creation.create.
65+
"""
66+
for key, value in vtkjs.items():
67+
if key == 'vtkClass':
68+
group.attrs[key] = value
69+
elif key == 'arrays':
70+
for index, arr in enumerate(value):
71+
vtkjs_to_zarr(arr,
72+
group.create_group('arrays/' + str(index), True),
73+
chunks=chunks)
74+
elif isinstance(value, dict):
75+
vtkjs_to_zarr(value,
76+
group.create_group(key, True),
77+
chunks=chunks)
78+
elif isinstance(value, np.ndarray):
79+
group.array(key, value, chunks=chunks)
80+
else:
81+
group.attrs[key] = value
82+
return group
83+
84+
def zarr_to_vtkjs(group):
85+
"""Convert Zarr Group that contains vtk.js data structure to a Python-like object.
86+
87+
Parameters
88+
----------
89+
90+
group: zarr.Group, required
91+
The Zarr group to convert.
92+
"""
93+
94+
def process_group(group, result):
95+
for key, value in group.attrs.items():
96+
result[key] = value
97+
for name, value in group.arrays():
98+
result[name] = np.asarray(value)
99+
for name, value in group.groups():
100+
if name == 'arrays':
101+
nested = []
102+
for index, subgroup in value.groups():
103+
subresult = dict()
104+
process_group(subgroup, subresult)
105+
nested.append(subresult)
106+
result[name] = nested
107+
else:
108+
nested = dict()
109+
process_group(value, nested)
110+
result[name] = nested
111+
result = dict()
112+
process_group(group, result)
113+
return result
114+
44115

45116
_itk_pixel_to_vtkjs_type_components = {
46117
itk.SC: ('Int8Array', 1),
@@ -53,7 +124,6 @@ def is_arraylike(arr):
53124
itk.D: ('Float64Array', 1),
54125
}
55126

56-
57127
def _vtk_to_vtkjs(data_array):
58128
from vtk.util.numpy_support import vtk_to_numpy
59129
# From vtkType.h

tests/test_transform_types.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import numpy as np
33
import pytest
44

5-
from itkwidgets._transform_types import to_point_set, to_geometry, to_itk_image
5+
from itkwidgets._transform_types import to_point_set, to_geometry, to_itk_image, vtkjs_to_zarr, zarr_to_vtkjs
66

77

88
def test_mesh_to_geometry():
@@ -78,6 +78,71 @@ def test_mesh_to_geometry():
7878
# assert(np.alltrue(geometry['points']['values'] ==
7979
# geometry_array.astype(np.float32)))
8080

81+
def test_vtkjs_to_zarr():
82+
zarr = pytest.importorskip("zarr")
83+
84+
# 3D
85+
Dimension = 3
86+
PixelType = itk.ctype('double')
87+
MeshType = itk.Mesh[PixelType, Dimension]
88+
mesh = MeshType.New()
89+
PointType = itk.Point[itk.F, Dimension]
90+
point0 = PointType()
91+
point0[0] = -1
92+
point0[1] = -1
93+
point0[2] = 0
94+
mesh.SetPoint(0, point0)
95+
mesh.SetPointData(0, 8.0)
96+
point1 = PointType()
97+
point1[0] = 1
98+
point1[1] = -1
99+
point1[2] = 0
100+
mesh.SetPointData(1, 9.0)
101+
mesh.SetPoint(1, point1)
102+
point2 = PointType()
103+
point2[0] = 1
104+
point2[1] = 1
105+
point2[2] = 0
106+
mesh.SetPoint(2, point2)
107+
mesh.SetPointData(2, 19.0)
108+
point3 = PointType()
109+
point3[0] = 1
110+
point3[1] = 1
111+
point3[2] = 0
112+
mesh.SetPoint(3, point3)
113+
mesh.SetPointData(3, 24.0)
114+
115+
vtkjs = to_geometry(mesh)
116+
117+
store = zarr.group()
118+
119+
vtkjs_to_zarr(vtkjs, store)
120+
geometry = zarr_to_vtkjs(store)
121+
122+
points = mesh.GetPoints()
123+
point_template = itk.template(points)
124+
element_type = point_template[1][1]
125+
point_values = itk.PyVectorContainer[element_type].array_from_vector_container(
126+
points)
127+
128+
assert(geometry['vtkClass'] == 'vtkPolyData')
129+
assert(geometry['points']['vtkClass'] == 'vtkPoints')
130+
assert(geometry['points']['numberOfComponents'] == 3)
131+
assert(geometry['points']['dataType'] == 'Float32Array')
132+
assert(geometry['points']['size'] == 4 * 3)
133+
assert(np.array_equal(geometry['points']['values'],
134+
point_values.astype(np.float32)))
135+
assert(geometry['pointData']['vtkClass'] == 'vtkDataSetAttributes')
136+
assert(geometry['pointData']['arrays'][0]
137+
['data']['vtkClass'] == 'vtkDataArray')
138+
assert(geometry['pointData']['arrays'][0]['data']['name'] == 'Point Data')
139+
assert(geometry['pointData']['arrays'][0]
140+
['data']['numberOfComponents'] == 1)
141+
assert(geometry['pointData']['arrays'][0]['data']['size'] == 4)
142+
assert(geometry['pointData']['arrays'][0]
143+
['data']['dataType'] == 'Float64Array')
144+
assert(np.array_equal(geometry['pointData']['arrays'][0]['data']['values'],
145+
np.array([8.0, 9.0, 19.0, 24.0], dtype=np.float64)))
81146

82147
def test_vtkpolydata_to_geometry():
83148
vtk = pytest.importorskip("vtk")

0 commit comments

Comments
 (0)