Skip to content

Commit 0f72055

Browse files
committed
TEST: Build HDF5/Numpy-based surface classes
1 parent b51e7a0 commit 0f72055

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

nibabel/tests/test_surfaceimages.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
from nibabel.surfaceimages import SurfaceGeometry, SurfaceHeader, SurfaceImage
2+
from nibabel.optpkg import optional_package
3+
4+
from nibabel.tests.test_filebasedimages import FBNumpyImage
5+
6+
import numpy as np
7+
from pathlib import Path
8+
9+
h5, has_h5py, _ = optional_package('h5py')
10+
11+
12+
class H5ArrayProxy:
13+
def __init__(self, file_like, dataset_name):
14+
self.file_like = file_like
15+
self.dataset_name = dataset_name
16+
with h5.File(file_like, "r") as h5f:
17+
arr = h5f[dataset_name]
18+
self._shape = arr.shape
19+
self._dtype = arr.dtype
20+
21+
@property
22+
def is_proxy(self):
23+
return True
24+
25+
@property
26+
def shape(self):
27+
return self._shape
28+
29+
@property
30+
def ndim(self):
31+
return len(self.shape)
32+
33+
@property
34+
def dtype(self):
35+
return self._dtype
36+
37+
def __array__(self, dtype=None):
38+
with h5.File(self.file_like, "r") as h5f:
39+
return np.asanyarray(h5f[self.dataset_name], dtype)
40+
41+
def __slicer__(self, slicer):
42+
with h5.File(self.file_like, "r") as h5f:
43+
return h5f[self.dataset_name][slicer]
44+
45+
46+
class H5Geometry(SurfaceGeometry):
47+
"""Simple Geometry file structure that combines a single topology
48+
with one or more coordinate sets
49+
"""
50+
@classmethod
51+
def from_filename(klass, pathlike):
52+
meshes = {}
53+
with h5.File(pathlike, "r") as h5f:
54+
triangles = h5f['topology']
55+
for name, coords in h5f['coordinates'].items():
56+
meshes[name] = (coords, triangles)
57+
return klass(meshes)
58+
59+
60+
def to_filename(self, pathlike):
61+
topology = None
62+
coordinates = {}
63+
for name, mesh in self.meshes.items():
64+
coords, faces = mesh
65+
if topology is None:
66+
topology = faces
67+
elif not np.array_equal(faces, topology):
68+
raise ValueError("Inconsistent topology")
69+
coordinates[name] = coords
70+
71+
with h5.File(pathlike, "w") as h5f:
72+
h5f.create_dataset("/topology", topology)
73+
for name, coord in coordinates.items():
74+
h5f.create_dataset(f"/coordinates/{name}", coord)
75+
76+
77+
def get_coords(self, name=None):
78+
if name is None:
79+
name = next(iter(self._meshes))
80+
coords, _ = self._meshes[name]
81+
return coords
82+
83+
84+
def get_triangles(self, name=None):
85+
if name is None:
86+
name = next(iter(self._meshes))
87+
_, triangles = self._meshes[name]
88+
return triangles
89+
90+
91+
class NPSurfaceImage(SurfaceImage):
92+
valid_exts = ('.npy',)
93+
files_types = (('image', '.npy'),)
94+
95+
@classmethod
96+
def from_file_map(klass, file_map):
97+
with file_map['image'].get_prepare_fileobj('rb') as fobj:
98+
arr = np.load(fobj)
99+
return klass(arr)
100+
101+
def to_file_map(self, file_map=None):
102+
file_map = self.file_map if file_map is None else file_map
103+
with file_map['image'].get_prepare_fileobj('wb') as fobj:
104+
np.save(fobj, self.arr)
105+
106+
def get_data_dtype(self):
107+
return self.dataobj.dtype
108+
109+
def set_data_dtype(self, dtype):
110+
self.dataobj = self.dataobj.astype(dtype)

0 commit comments

Comments
 (0)