Skip to content

Commit 18125f3

Browse files
committed
MAINT: simplify get_volume_labels by removing per-slice attributes
1 parent 4378d35 commit 18125f3

File tree

2 files changed

+11
-61
lines changed

2 files changed

+11
-61
lines changed

nibabel/parrec.py

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -249,18 +249,6 @@ class PARRECError(Exception):
249249
GEN_RE = re.compile(r".\s+(.*?)\s*:\s*(.*)")
250250

251251

252-
def _unique_rows(a):
253-
"""
254-
find unique rows of a 2D array. based on discussion at:
255-
http://stackoverflow.com/questions/16970982/find-unique-rows-in-numpy-array
256-
"""
257-
if a.ndim != 2:
258-
raise ValueError("expected 2D input")
259-
b = np.ascontiguousarray(a).view(
260-
np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
261-
return np.unique(b).view(a.dtype).reshape(-1, a.shape[1])
262-
263-
264252
def _split_header(fobj):
265253
""" Split header into `version`, `gen_dict`, `image_lines` """
266254
version = None
@@ -1126,48 +1114,34 @@ def get_sorted_slice_indices(self):
11261114
n_used = np.prod(self.get_data_shape()[2:])
11271115
return sort_order[:n_used]
11281116

1129-
def get_volume_labels(self, collapse_slices=True):
1117+
def get_volume_labels(self):
11301118
""" Dynamic labels corresponding to the final data dimension(s).
11311119
11321120
This is useful for custom data sorting. A subset of the info in
11331121
``self.image_defs`` is returned in an order that matches the final
11341122
data dimension(s). Only labels that have more than one unique value
11351123
across the dataset will be returned.
11361124
1137-
Parameters
1138-
----------
1139-
collapse_slices : bool, optional
1140-
If True, only return volume indices (corresponding to the first
1141-
slice). If False, return indices corresponding to individual
1142-
slices as well (with shape matching self.shape[2:]).
1143-
11441125
Returns
11451126
-------
11461127
sort_info : dict
1147-
Each key corresponds to a dynamically varying sequence dimension.
1148-
The ordering of each value corresponds to that returned by
1149-
``self.get_sorted_slice_indices``.
1128+
Each key corresponds to volume labels for a dynamically varying
1129+
sequence dimension. The ordering of the labels matches the volume
1130+
ordering determined via ``self.get_sorted_slice_indices``.
11501131
"""
11511132
sorted_indices = self.get_sorted_slice_indices()
11521133
image_defs = self.image_defs
11531134

1154-
# define which keys to store sorting info for
1155-
dynamic_keys = ['slice number',
1156-
'cardiac phase number',
1135+
# define which keys which might vary across image volumes
1136+
dynamic_keys = ['cardiac phase number',
11571137
'echo number',
11581138
'label type',
11591139
'image_type_mr',
11601140
'dynamic scan number',
1161-
'slice orientation',
1162-
'image_display_orientation', # ????
1163-
'image angulation',
11641141
'scanning sequence',
11651142
'gradient orientation number',
11661143
'diffusion b value number']
11671144

1168-
if collapse_slices:
1169-
dynamic_keys.remove('slice number')
1170-
11711145
# remove dynamic keys that may not be present in older .PAR versions
11721146
dynamic_keys = [d for d in dynamic_keys if d in
11731147
image_defs.dtype.fields]
@@ -1177,31 +1151,18 @@ def get_volume_labels(self, collapse_slices=True):
11771151
ndim = image_defs[key].ndim
11781152
if ndim == 1:
11791153
num_unique = len(np.unique(image_defs[key]))
1180-
elif ndim == 2:
1181-
# for 2D cases, e.g. 'image angulation'
1182-
num_unique = len(_unique_rows(image_defs[key]))
11831154
else:
1184-
raise ValueError("unexpected image_defs shape > 2D")
1155+
raise ValueError("unexpected image_defs shape > 1D")
11851156
if num_unique > 1:
11861157
non_unique_keys.append(key)
11871158

1188-
if collapse_slices:
1189-
for key in ('slice_orientation', 'image_angulation',
1190-
'image_display_orientation'):
1191-
if key in non_unique_keys:
1192-
raise ValueError(
1193-
'for values of {0} that differ overslices, use '
1194-
'"collapse_slice=False"'.format(key))
1195-
sl1_indices = image_defs['slice number'][sorted_indices] == 1
1159+
# each key in dynamic keys will be identical across slices, so use
1160+
# the value at slice 1.
1161+
sl1_indices = image_defs['slice number'][sorted_indices] == 1
11961162

11971163
sort_info = {}
11981164
for key in non_unique_keys:
1199-
if collapse_slices:
1200-
sort_info[key] = image_defs[key][sorted_indices][sl1_indices]
1201-
else:
1202-
value = image_defs[key][sorted_indices]
1203-
sort_info[key] = value.reshape(self.get_data_shape()[2:],
1204-
order='F')
1165+
sort_info[key] = image_defs[key][sorted_indices][sl1_indices]
12051166
return sort_info
12061167

12071168

nibabel/tests/test_parrec.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -197,14 +197,6 @@ def test_header_dimension_labels():
197197
assert_array_equal(vol_labels['dynamic scan number'], [1, 2, 3])
198198
# check that output is ndarray rather than list
199199
assert_true(isinstance(vol_labels['dynamic scan number'], np.ndarray))
200-
# check case with individual slice labels
201-
slice_vol_labels = hdr.get_volume_labels(collapse_slices=False)
202-
# verify that both expected keys are present
203-
assert_true('slice number' in slice_vol_labels)
204-
assert_true('dynamic scan number' in slice_vol_labels)
205-
# verify shape of labels matches final dimensions of data
206-
assert_equal(slice_vol_labels['slice number'].shape,
207-
hdr.get_data_shape()[2:])
208200

209201

210202
def test_orientation():
@@ -721,9 +713,6 @@ def get_rec_shape(self):
721713
n_slices = np.prod(self._shape[2:])
722714
return self._shape[:2] + (n_slices,)
723715

724-
def sorted_labels(self, sorted_indices, collapse_slices):
725-
return np.arange(self._shape[-1])
726-
727716

728717
def test_parrec_proxy():
729718
# Test PAR / REC proxy class, including mmap flags

0 commit comments

Comments
 (0)