Skip to content

Commit 5abeaac

Browse files
committed
FIX: bugfix to replace np.unique() with _unique_rows() for 2D inputs needed for sorting vector properties. proper 2D ndarray to list of lists for JSON export in parrec2nii
1 parent 4dc2d50 commit 5abeaac

File tree

2 files changed

+52
-14
lines changed

2 files changed

+52
-14
lines changed

bin/parrec2nii

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import numpy.linalg as npl
99
import sys
1010
import os
1111
import json
12+
from copy import deepcopy
1213
import nibabel
1314
import nibabel.parrec as pr
1415
from nibabel.parrec import one_line
@@ -134,6 +135,24 @@ def error(msg, exit_code):
134135
sys.exit(exit_code)
135136

136137

138+
def sort_info_to_lists(sort_info):
139+
sort_info = deepcopy(sort_info)
140+
# convert from elements from numpy array to lists for easy JSON export
141+
for key in sort_info:
142+
ndim = sort_info[key].ndim
143+
if ndim == 1:
144+
sort_info[key] = list(sort_info[key])
145+
elif ndim == 2:
146+
k = sort_info[key]
147+
k_list = []
148+
for row in range(k.shape[0]):
149+
k_list.append(list(k[row]))
150+
sort_info[key] = k_list
151+
else:
152+
raise ValueError("only 1D and 2D arrays supported")
153+
return sort_info
154+
155+
137156
def proc_file(infile, opts):
138157
# figure out the output filename, and see if it exists
139158
basefilename = splitext_addext(os.path.basename(infile))[0]
@@ -265,15 +284,15 @@ def proc_file(infile, opts):
265284

266285
opts.dim_info = True # TODO: remove hard-coded value
267286
if opts.dim_info and pr_img.dataobj._dim_4_labels is not None:
268-
if len(list(pr_img.dataobj._dim_4_labels.keys())) > 0:
269-
with open(basefilename + '.ordering.json', 'w') as fid:
270-
json.dump(pr_img.dataobj._dim_4_labels, fid, sort_keys=True,
271-
indent=4)
287+
labels = pr_img.dataobj._dim_4_labels
272288
elif opts.dim_info and pr_img.dataobj._dim_3_4_labels is not None:
273-
if len(list(pr_img.dataobj._dim_3_4_labels.keys())) > 0:
274-
with open(basefilename + '.ordering.json', 'w') as fid:
275-
json.dump(pr_img.dataobj._dim_3_4_labels, fid, sort_keys=True,
276-
indent=4)
289+
labels = pr_img.dataobj._dim_3_4_labels
290+
else:
291+
labels = None
292+
if labels is not None and len(labels) > 0:
293+
sort_info = sort_info_to_lists(labels)
294+
with open(basefilename + '.ordering.json', 'w') as fid:
295+
json.dump(sort_info, fid, sort_keys=True, indent=4)
277296

278297
# write out dwell time if requested
279298
if opts.dwell_time:

nibabel/parrec.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,18 @@ 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+
252264
def _split_header(fobj):
253265
""" Split header into `version`, `gen_dict`, `image_lines` """
254266
version = None
@@ -1171,8 +1183,17 @@ def sorted_labels(self, sorted_indices=None, collapse_slices=True):
11711183
dynamic_keys.remove('slice number')
11721184

11731185
non_unique_keys = []
1186+
11741187
for key in dynamic_keys:
1175-
if len(np.unique(self.image_defs[key])) > 1:
1188+
ndim = self.image_defs[key].ndim
1189+
if ndim == 1:
1190+
num_unique = len(np.unique(self.image_defs[key]))
1191+
elif ndim == 2:
1192+
# for 2D cases, e.g. 'image angulation'
1193+
num_unique = len(_unique_rows(self.image_defs[key]))
1194+
else:
1195+
raise ValueError("unexpected image_defs shape > 2D")
1196+
if num_unique > 1:
11761197
non_unique_keys.append(key)
11771198

11781199
if collapse_slices:
@@ -1189,13 +1210,11 @@ def sorted_labels(self, sorted_indices=None, collapse_slices=True):
11891210

11901211
sort_info = {}
11911212
for key in non_unique_keys:
1213+
11921214
if collapse_slices:
1193-
sort_info[key] = list(
1194-
self.image_defs[key][sorted_indices][sl1_indices])
1215+
sort_info[key] = self.image_defs[key][sorted_indices][sl1_indices]
11951216
else:
1196-
sort_info[key] = list(
1197-
self.image_defs[key][sorted_indices])
1198-
1217+
sort_info[key] = self.image_defs[key][sorted_indices]
11991218
return sort_info
12001219

12011220

0 commit comments

Comments
 (0)