Skip to content

Commit 8312af6

Browse files
Merge pull request #600 from matthew-brett/trk-codes-with-check
MRG: fix lower-case TRK codes, add error message * Kesshi's initial fix and test for lower-case codes in TRK header; * Error checking in axcodes2ornt to detect unknown or duplicate codes.
2 parents 96b2bda + 9ac73d0 commit 8312af6

File tree

4 files changed

+44
-9
lines changed

4 files changed

+44
-9
lines changed

nibabel/orientations.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,13 @@ def axcodes2ornt(axcodes, labels=None):
349349
[ 0., -1.],
350350
[ 2., 1.]])
351351
"""
352-
if labels is None:
353-
labels = list(zip('LPI', 'RAS'))
352+
labels = list(zip('LPI', 'RAS')) if labels is None else labels
353+
allowed_labels = sum([list(L) for L in labels], []) + [None]
354+
if len(allowed_labels) != len(set(allowed_labels)):
355+
raise ValueError('Duplicate labels in {}'.format(allowed_labels))
356+
if not set(axcodes).issubset(allowed_labels):
357+
raise ValueError('Not all axis codes {} in label set {}'
358+
.format(list(axcodes), allowed_labels))
354359
n_axes = len(axcodes)
355360
ornt = np.ones((n_axes, 2), dtype=np.int8) * np.nan
356361
for code_idx, code in enumerate(axcodes):

nibabel/streamlines/tests/test_trk.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from ..tractogram_file import HeaderError, HeaderWarning
1818

1919
from .. import trk as trk_module
20-
from ..trk import TrkFile, encode_value_in_name, decode_value_from_name
20+
from ..trk import TrkFile, encode_value_in_name, decode_value_from_name, get_affine_trackvis_to_rasmm
2121
from ..header import Field
2222

2323
DATA = {}
@@ -110,6 +110,17 @@ def trk_with_bytes(self, trk_key='simple_trk_fname', endian='<'):
110110
return trk_struct, trk_bytes
111111

112112
def test_load_file_with_wrong_information(self):
113+
# Simulate a TRK file where `voxel_order` is lowercase.
114+
trk_struct1, trk_bytes1 = self.trk_with_bytes()
115+
trk_struct1[Field.VOXEL_ORDER] = b'LAS'
116+
trk1 = TrkFile.load(BytesIO(trk_bytes1))
117+
trk_struct2, trk_bytes2 = self.trk_with_bytes()
118+
trk_struct2[Field.VOXEL_ORDER] = b'las'
119+
trk2 = TrkFile.load(BytesIO(trk_bytes2))
120+
trk1_aff2rasmm = get_affine_trackvis_to_rasmm(trk1.header)
121+
trk2_aff2rasmm = get_affine_trackvis_to_rasmm(trk2.header)
122+
assert_array_equal(trk1_aff2rasmm,trk2_aff2rasmm)
123+
113124
# Simulate a TRK file where `count` was not provided.
114125
trk_struct, trk_bytes = self.trk_with_bytes()
115126
trk_struct[Field.NB_STREAMLINES] = 0

nibabel/streamlines/trk.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def get_affine_trackvis_to_rasmm(header):
107107
if hasattr(vox_order, 'item'): # structured array
108108
vox_order = header[Field.VOXEL_ORDER].item()
109109
affine_ornt = "".join(aff2axcodes(header[Field.VOXEL_TO_RASMM]))
110-
header_ornt = axcodes2ornt(vox_order.decode('latin1'))
110+
header_ornt = axcodes2ornt(vox_order.decode('latin1').upper())
111111
affine_ornt = axcodes2ornt(affine_ornt)
112112
ornt = nib.orientations.ornt_transform(header_ornt, affine_ornt)
113113
M = nib.orientations.inv_ornt_aff(ornt, header[Field.DIMENSIONS])

nibabel/tests/test_orientations.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,8 @@ def test_axcodes2ornt():
300300
)
301301

302302
# default is RAS output directions
303-
assert_array_equal(axcodes2ornt(('R', 'A', 'S')),
304-
[[0, 1],
305-
[1, 1],
306-
[2, 1]]
307-
)
303+
default = np.c_[range(3), [1] * 3]
304+
assert_array_equal(axcodes2ornt(('R', 'A', 'S')), default)
308305

309306
# dropped axes produce None
310307
assert_array_equal(axcodes2ornt(('R', None, 'S')),
@@ -313,6 +310,28 @@ def test_axcodes2ornt():
313310
[2, 1]]
314311
)
315312

313+
# Missing axcodes raise an error
314+
assert_array_equal(axcodes2ornt('RAS'), default)
315+
assert_raises(ValueError, axcodes2ornt, 'rAS')
316+
# None is OK as axis code
317+
assert_array_equal(axcodes2ornt(('R', None, 'S')),
318+
[[0, 1],
319+
[np.nan, np.nan],
320+
[2, 1]])
321+
# Bad axis code with None also raises error.
322+
assert_raises(ValueError, axcodes2ornt, ('R', None, 's'))
323+
# Axis codes checked with custom labels
324+
labels = ('SD', 'BF', 'lh')
325+
assert_array_equal(axcodes2ornt('BlD', labels),
326+
[[1, -1],
327+
[2, -1],
328+
[0, 1]])
329+
assert_raises(ValueError, axcodes2ornt, 'blD', labels)
330+
331+
# Duplicate labels
332+
assert_raises(ValueError, axcodes2ornt, 'blD', ('SD', 'BF', 'lD'))
333+
assert_raises(ValueError, axcodes2ornt, 'blD', ('SD', 'SF', 'lD'))
334+
316335

317336
def test_aff2axcodes():
318337
assert_equal(aff2axcodes(np.eye(4)), tuple('RAS'))

0 commit comments

Comments
 (0)