Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d0bbcc7

Browse files
committedJul 6, 2020
ENH: Add option to allow inferring of intent code based on output file suffixes
1 parent 3d266fc commit d0bbcc7

File tree

2 files changed

+56
-28
lines changed

2 files changed

+56
-28
lines changed
 

‎nibabel/cifti2/cifti2.py

+45-5
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,23 @@ class Cifti2HeaderError(Exception):
8888
'CIFTI_STRUCTURE_THALAMUS_LEFT',
8989
'CIFTI_STRUCTURE_THALAMUS_RIGHT')
9090

91+
# "Standard CIFTI Mapping Combinations" within CIFTI-2 spec
92+
# https://www.nitrc.org/forum/attachment.php?attachid=341&group_id=454&forum_id=1955
93+
CIFTI_EXTENSIONS_TO_INTENTS = {
94+
'.dconn': 'NIFTI_INTENT_CONNECTIVITY_DENSE',
95+
'.dtseries': 'NIFTI_INTENT_CONNECTIVITY_DENSE_SERIES',
96+
'.pconn': 'NIFTI_INTENT_CONNECTIVITY_PARCELLATED',
97+
'.ptseries': 'NIFTI_INTENT_CONNECTIVITY_PARCELLATED_SERIES',
98+
'.dscalar': 'NIFTI_INTENT_CONNECTIVITY_DENSE_SCALARS',
99+
'.dlabel': 'NIFTI_INTENT_CONNECTIVITY_DENSE_LABELS',
100+
'.pscalar': 'NIFTI_INTENT_CONNECTIVITY_PARCELLATED_SCALAR',
101+
'.pdconn': 'NIFTI_INTENT_CONNECTIVITY_PARCELLATED_DENSE',
102+
'.dpconn': 'NIFTI_INTENT_CONNECTIVITY_DENSE_PARCELLATED',
103+
'.pconnseries': 'NIFTI_INTENT_CONNECTIVITY_PARCELLATED_PARCELLATED_SERIES',
104+
'.pconnscalar': 'NIFTI_INTENT_CONNECTIVITY_PARCELLATED_PARCELLATED_SCALAR',
105+
'.dfan': 'NIFTI_INTENT_CONNECTIVITY_DENSE_SERIES',
106+
}
107+
91108

92109
def _value_if_klass(val, klass):
93110
if val is None or isinstance(val, klass):
@@ -1459,11 +1476,7 @@ def to_file_map(self, file_map=None):
14591476
raise ValueError(
14601477
f"Dataobj shape {self._dataobj.shape} does not match shape "
14611478
f"expected from CIFTI-2 header {self.header.matrix.get_data_shape()}")
1462-
# if intent code is not set, default to unknown CIFTI
1463-
if header.get_intent()[0] == 'none':
1464-
header.set_intent('NIFTI_INTENT_CONNECTIVITY_UNKNOWN')
1465-
data = reshape_dataobj(self.dataobj,
1466-
(1, 1, 1, 1) + self.dataobj.shape)
1479+
data = reshape_dataobj(self.dataobj, (1, 1, 1, 1) + self.dataobj.shape)
14671480
# If qform not set, reset pixdim values so Nifti2 does not complain
14681481
if header['qform_code'] == 0:
14691482
header['pixdim'][:4] = 1
@@ -1490,6 +1503,33 @@ def get_data_dtype(self):
14901503
def set_data_dtype(self, dtype):
14911504
self._nifti_header.set_data_dtype(dtype)
14921505

1506+
def to_filename(self, filename, infer_intent=False):
1507+
"""
1508+
Ensures NIfTI header intent code is set prior to saving.
1509+
1510+
Parameters
1511+
----------
1512+
infer_intent : boolean, optional
1513+
If ``True``, attempt to infer and set intent code based on filename suffix.
1514+
"""
1515+
header = self._nifti_header
1516+
if infer_intent:
1517+
# try to infer intent code based on filename suffix
1518+
intent = _infer_intent_from_filename(filename)
1519+
if intent is not None:
1520+
header.set_intent(intent)
1521+
# if intent code is not set, default to unknown
1522+
if header.get_intent()[0] == 'none':
1523+
header.set_intent('NIFTI_INTENT_CONNECTIVITY_UNKNOWN')
1524+
super().to_filename(filename)
1525+
1526+
1527+
def _infer_intent_from_filename(filename):
1528+
"""Parses output filename for common suffixes and fetches corresponding intent code"""
1529+
from pathlib import Path
1530+
ext = Path(filename).suffixes[0]
1531+
return CIFTI_EXTENSIONS_TO_INTENTS.get(ext)
1532+
14931533

14941534
load = Cifti2Image.from_filename
14951535
save = Cifti2Image.instance_to_filename

‎nibabel/cifti2/tests/test_new_cifti2.py

+11-23
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,9 @@ def test_dtseries():
237237
hdr = ci.Cifti2Header(matrix)
238238
data = np.random.randn(13, 10)
239239
img = ci.Cifti2Image(data, hdr)
240-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_DENSE_SERIES')
241240

242241
with InTemporaryDirectory():
243-
ci.save(img, 'test.dtseries.nii')
242+
ci.save(img, 'test.dtseries.nii', infer_intent=True)
244243
img2 = nib.load('test.dtseries.nii')
245244
assert img2.nifti_header.get_intent()[0] == 'ConnDenseSeries'
246245
assert isinstance(img2, ci.Cifti2Image)
@@ -281,10 +280,9 @@ def test_dlabel():
281280
hdr = ci.Cifti2Header(matrix)
282281
data = np.random.randn(2, 10)
283282
img = ci.Cifti2Image(data, hdr)
284-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_DENSE_LABELS')
285283

286284
with InTemporaryDirectory():
287-
ci.save(img, 'test.dlabel.nii')
285+
ci.save(img, 'test.dlabel.nii', infer_intent=True)
288286
img2 = nib.load('test.dlabel.nii')
289287
assert img2.nifti_header.get_intent()[0] == 'ConnDenseLabel'
290288
assert isinstance(img2, ci.Cifti2Image)
@@ -301,10 +299,9 @@ def test_dconn():
301299
hdr = ci.Cifti2Header(matrix)
302300
data = np.random.randn(10, 10)
303301
img = ci.Cifti2Image(data, hdr)
304-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_DENSE')
305302

306303
with InTemporaryDirectory():
307-
ci.save(img, 'test.dconn.nii')
304+
ci.save(img, 'test.dconn.nii', infer_intent=True)
308305
img2 = nib.load('test.dconn.nii')
309306
assert img2.nifti_header.get_intent()[0] == 'ConnDense'
310307
assert isinstance(img2, ci.Cifti2Image)
@@ -323,10 +320,9 @@ def test_ptseries():
323320
hdr = ci.Cifti2Header(matrix)
324321
data = np.random.randn(13, 4)
325322
img = ci.Cifti2Image(data, hdr)
326-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_PARCELLATED_SERIES')
327323

328324
with InTemporaryDirectory():
329-
ci.save(img, 'test.ptseries.nii')
325+
ci.save(img, 'test.ptseries.nii', infer_intent=True)
330326
img2 = nib.load('test.ptseries.nii')
331327
assert img2.nifti_header.get_intent()[0] == 'ConnParcelSries'
332328
assert isinstance(img2, ci.Cifti2Image)
@@ -345,10 +341,9 @@ def test_pscalar():
345341
hdr = ci.Cifti2Header(matrix)
346342
data = np.random.randn(2, 4)
347343
img = ci.Cifti2Image(data, hdr)
348-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_PARCELLATED_SCALAR')
349344

350345
with InTemporaryDirectory():
351-
ci.save(img, 'test.pscalar.nii')
346+
ci.save(img, 'test.pscalar.nii', infer_intent=True)
352347
img2 = nib.load('test.pscalar.nii')
353348
assert img2.nifti_header.get_intent()[0] == 'ConnParcelScalr'
354349
assert isinstance(img2, ci.Cifti2Image)
@@ -367,10 +362,9 @@ def test_pdconn():
367362
hdr = ci.Cifti2Header(matrix)
368363
data = np.random.randn(10, 4)
369364
img = ci.Cifti2Image(data, hdr)
370-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_PARCELLATED_DENSE')
371365

372366
with InTemporaryDirectory():
373-
ci.save(img, 'test.pdconn.nii')
367+
ci.save(img, 'test.pdconn.nii', infer_intent=True)
374368
img2 = ci.load('test.pdconn.nii')
375369
assert img2.nifti_header.get_intent()[0] == 'ConnParcelDense'
376370
assert isinstance(img2, ci.Cifti2Image)
@@ -389,10 +383,9 @@ def test_dpconn():
389383
hdr = ci.Cifti2Header(matrix)
390384
data = np.random.randn(4, 10)
391385
img = ci.Cifti2Image(data, hdr)
392-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_DENSE_PARCELLATED')
393386

394387
with InTemporaryDirectory():
395-
ci.save(img, 'test.dpconn.nii')
388+
ci.save(img, 'test.dpconn.nii', infer_intent=True)
396389
img2 = ci.load('test.dpconn.nii')
397390
assert img2.nifti_header.get_intent()[0] == 'ConnDenseParcel'
398391
assert isinstance(img2, ci.Cifti2Image)
@@ -430,10 +423,9 @@ def test_pconn():
430423
hdr = ci.Cifti2Header(matrix)
431424
data = np.random.randn(4, 4)
432425
img = ci.Cifti2Image(data, hdr)
433-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_PARCELLATED')
434426

435427
with InTemporaryDirectory():
436-
ci.save(img, 'test.pconn.nii')
428+
ci.save(img, 'test.pconn.nii', infer_intent=True)
437429
img2 = ci.load('test.pconn.nii')
438430
assert img.nifti_header.get_intent()[0] == 'ConnParcels'
439431
assert isinstance(img2, ci.Cifti2Image)
@@ -453,11 +445,9 @@ def test_pconnseries():
453445
hdr = ci.Cifti2Header(matrix)
454446
data = np.random.randn(4, 4, 13)
455447
img = ci.Cifti2Image(data, hdr)
456-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_PARCELLATED_'
457-
'PARCELLATED_SERIES')
458448

459449
with InTemporaryDirectory():
460-
ci.save(img, 'test.pconnseries.nii')
450+
ci.save(img, 'test.pconnseries.nii', infer_intent=True)
461451
img2 = ci.load('test.pconnseries.nii')
462452
assert img.nifti_header.get_intent()[0] == 'ConnPPSr'
463453
assert isinstance(img2, ci.Cifti2Image)
@@ -478,11 +468,9 @@ def test_pconnscalar():
478468
hdr = ci.Cifti2Header(matrix)
479469
data = np.random.randn(4, 4, 2)
480470
img = ci.Cifti2Image(data, hdr)
481-
img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_PARCELLATED_'
482-
'PARCELLATED_SCALAR')
483471

484472
with InTemporaryDirectory():
485-
ci.save(img, 'test.pconnscalar.nii')
473+
ci.save(img, 'test.pconnscalar.nii', infer_intent=True)
486474
img2 = ci.load('test.pconnscalar.nii')
487475
assert img.nifti_header.get_intent()[0] == 'ConnPPSc'
488476
assert isinstance(img2, ci.Cifti2Image)
@@ -517,7 +505,7 @@ def test_wrong_shape():
517505
ci.Cifti2Image(data, hdr)
518506
with suppress_warnings():
519507
img = ci.Cifti2Image(data, hdr)
520-
508+
521509
with pytest.raises(ValueError):
522510
img.to_file_map()
523511

0 commit comments

Comments
 (0)