From e4a94ca76fb679bf53c2b618ed49e1308784ce8e Mon Sep 17 00:00:00 2001 From: Salma BOUGACHA Date: Thu, 17 May 2018 18:34:12 +0200 Subject: [PATCH 1/3] add AFNI interface LocalBistat --- nipype/interfaces/afni/__init__.py | 6 +- .../afni/tests/test_auto_LocalBistat.py | 64 ++++++++++ nipype/interfaces/afni/utils.py | 118 ++++++++++++++++++ 3 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 nipype/interfaces/afni/tests/test_auto_LocalBistat.py diff --git a/nipype/interfaces/afni/__init__.py b/nipype/interfaces/afni/__init__.py index 925011a19a..7c3498f7c6 100644 --- a/nipype/interfaces/afni/__init__.py +++ b/nipype/interfaces/afni/__init__.py @@ -18,7 +18,7 @@ from .utils import ( ABoverlap, AFNItoNIFTI, Autobox, Axialize, BrickStat, Bucket, Calc, Cat, CatMatvec, CenterMass, ConvertDset, Copy, Dot, Edge3, Eval, FWHMx, - MaskTool, Merge, Notes, NwarpApply, NwarpAdjust, NwarpCat, OneDToolPy, - Refit, Resample, TCat, TCatSubBrick, TStat, To3D, Unifize, Undump, ZCutUp, - GCOR, Zcat, Zeropad) + LocalBistat, MaskTool, Merge, Notes, NwarpApply, NwarpAdjust, NwarpCat, + OneDToolPy, Refit, Resample, TCat, TCatSubBrick, TStat, To3D, Unifize, + Undump, ZCutUp, GCOR, Zcat, Zeropad) from .model import (Deconvolve, Remlfit, Synthesize) diff --git a/nipype/interfaces/afni/tests/test_auto_LocalBistat.py b/nipype/interfaces/afni/tests/test_auto_LocalBistat.py new file mode 100644 index 0000000000..9d82f29660 --- /dev/null +++ b/nipype/interfaces/afni/tests/test_auto_LocalBistat.py @@ -0,0 +1,64 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..utils import LocalBistat + + +def test_LocalBistat_inputs(): + input_map = dict( + args=dict(argstr='%s', ), + automask=dict(), + environ=dict( + nohash=True, + usedefault=True, + ), + ignore_exception=dict( + deprecated='1.0.0', + nohash=True, + usedefault=True, + ), + in_files=dict( + argstr='%s', + mandatory=True, + position=-1, + ), + mask_file=dict( + argstr='-weight %s', + xor=['automask'], + ), + neighborhood=dict( + argstr='-nbhd %s', + mandatory=True, + ), + num_threads=dict( + nohash=True, + usedefault=True, + ), + out_file=dict( + argstr='-prefix %s', + keep_extension=True, + name_source='in_files', + name_template='%s_bistat', + position=0, + ), + outputtype=dict(), + stat=dict( + argstr='-stat %s', + mandatory=True, + ), + terminal_output=dict( + deprecated='1.0.0', + nohash=True, + ), + ) + inputs = LocalBistat.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_LocalBistat_outputs(): + output_map = dict(out_file=dict(), ) + outputs = LocalBistat.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value diff --git a/nipype/interfaces/afni/utils.py b/nipype/interfaces/afni/utils.py index 1f33e4de3a..a0ca6808d6 100644 --- a/nipype/interfaces/afni/utils.py +++ b/nipype/interfaces/afni/utils.py @@ -1338,6 +1338,124 @@ def _list_outputs(self): return outputs +class LocalBistatInputSpec(AFNICommandInputSpec): + in_files = InputMultiPath( + File(exists=True), + minlen=2, + maxlen=2, + mandatory=True, + argstr='%s', + position=-1, + desc='Filenames of the 2 images to compute statistics between') + neighborhood = traits.Either( + traits.Tuple(traits.Enum('SPHERE', 'RHDD', 'TOHD'), traits.Float()), + traits.Tuple(traits.Enum('RECT'), traits.Tuple(traits.Float(), + traits.Float(), + traits.Float())), + mandatory=True, + desc='The region around each voxel that will be extracted for ' + 'the statistics calculation. Possible regions are: ' + '\'SPHERE\', \'RHDD\' (rhombic dodecahedron), \'TOHD\' ' + '(truncated octahedron) with a given radius in mm or ' + '\'RECT\' (rectangular block) with dimensions to specify in mm.', + argstr='-nbhd %s') + _stat_names = ['pearson', 'spearman', 'quadrant', 'mutinfo', 'normuti', + 'jointent', 'hellinger', 'crU', 'crM', 'crA', 'L2slope', + 'L1slope', 'num', 'ALL'] + stat = traits.Either( + traits.Enum(*_stat_names), traits.List(traits.Enum(_stat_names)), + mandatory=True, + desc='statistics to compute. Possible names are :' + ' * pearson = Pearson correlation coefficient' + ' * spearman = Spearman correlation coefficient' + ' * quadrant = Quadrant correlation coefficient' + ' * mutinfo = Mutual Information' + ' * normuti = Normalized Mutual Information' + ' * jointent = Joint entropy' + ' * hellinger= Hellinger metric' + ' * crU = Correlation ratio (Unsymmetric)' + ' * crM = Correlation ratio (symmetrized by Multiplication)' + ' * crA = Correlation ratio (symmetrized by Addition)' + ' * L2slope = slope of least-squares (L2) linear regression of ' + ' the data from dataset1 vs. the dataset2 ' + ' (i.e., d2 = a + b*d1 ==> this is \'b\')' + ' * L1slope = slope of least-absolute-sum (L1) linear ' + ' regression of the data from dataset1 vs. ' + ' the dataset2' + ' * num = number of the values in the region: ' + ' with the use of -mask or -automask, ' + ' the size of the region around any given ' + ' voxel will vary; this option lets you ' + ' map that size.' + ' * ALL = all of the above, in that order' + 'More than one option can be used.', + argstr='-stat %s') + mask_file = traits.File( + exists=True, + desc='mask image file name. Voxels NOT in the mask will not be used ' + 'in the neighborhood of any voxel. Also, a voxel NOT in the mask ' + 'will have its statistic(s) computed as zero (0).', + argstr='-mask %s') + automask = traits.Bool( + desc='Compute the mask as in program 3dAutomask.') + mask_file = traits.File( + exists=True, + desc='File name of an image to use as a weight. Only applies to ' + '\'pearson\' statistics.', + argstr='-weight %s', + xor=['automask']) + out_file = traits.File( + desc='Output dataset.', + argstr='-prefix %s', + name_source='in_files', + name_template='%s_bistat', + keep_extension=True, + position=0) + + +class LocalBistat(AFNICommand): + """3dLocalBistat - computes statistics between 2 datasets, at each voxel, + based on a local neighborhood of that voxel. + + For complete details, see the `3dLocalBistat Documentation. + `_ + + Examples + ======== + + >>> from nipype.interfaces import afni + >>> bistat = afni.LocalBistat() + >>> bistat.inputs.in_files = ['functional.nii', 'structural.nii'] + >>> bistat.inputs.neighborhood = ('SPHERE', 1.2) + >>> bistat.inputs.stat = 'pearson' + >>> bistat.inputs.outputtype = 'NIFTI' + >>> bistat.cmdline + "3dLocalBistat -prefix functional_bistat.nii -nbhd 'SPHERE(1.2)' -stat pearson functional.nii structural.nii" + >>> res = automask.run() # doctest: +SKIP + + """ + + _cmd = '3dLocalBistat' + input_spec = LocalBistatInputSpec + output_spec = AFNICommandOutputSpec + + def _format_arg(self, name, spec, value): + if name == 'neighborhood': + region_name, region_size = value + if region_name == 'RECT': + return spec.argstr % ( + "'{0}({1})'".format(region_name, ','.join(region_size))) + else: + return spec.argstr % ( + "'{0}({1})'".format(region_name, region_size)) + if name == 'stat': + if isinstance(value, (str, bytes)): + return spec.argstr % value + else: + return ' '.join([spec.argstr % v for v in value]) + return super(LocalBistat, self)._format_arg(name, spec, value) + + class MaskToolInputSpec(AFNICommandInputSpec): in_file = File( desc='input file or files to 3dmask_tool', From aec6941cee90599b79a7a4d80db1ed912c325fcd Mon Sep 17 00:00:00 2001 From: salma1601 Date: Thu, 24 May 2018 00:11:27 +0200 Subject: [PATCH 2/3] address comments --- .../afni/tests/test_auto_LocalBistat.py | 18 ++++++----- nipype/interfaces/afni/utils.py | 30 +++++++------------ 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/nipype/interfaces/afni/tests/test_auto_LocalBistat.py b/nipype/interfaces/afni/tests/test_auto_LocalBistat.py index 9d82f29660..a36a69cbbd 100644 --- a/nipype/interfaces/afni/tests/test_auto_LocalBistat.py +++ b/nipype/interfaces/afni/tests/test_auto_LocalBistat.py @@ -6,7 +6,10 @@ def test_LocalBistat_inputs(): input_map = dict( args=dict(argstr='%s', ), - automask=dict(), + automask=dict( + argstr='-automask', + xor=['weight_file'], + ), environ=dict( nohash=True, usedefault=True, @@ -21,12 +24,9 @@ def test_LocalBistat_inputs(): mandatory=True, position=-1, ), - mask_file=dict( - argstr='-weight %s', - xor=['automask'], - ), + mask_file=dict(argstr='-mask %s', ), neighborhood=dict( - argstr='-nbhd %s', + argstr="-nbhd '%s(%s)'", mandatory=True, ), num_threads=dict( @@ -42,13 +42,17 @@ def test_LocalBistat_inputs(): ), outputtype=dict(), stat=dict( - argstr='-stat %s', + argstr='-stat %s...', mandatory=True, ), terminal_output=dict( deprecated='1.0.0', nohash=True, ), + weight_file=dict( + argstr='-weight %s', + xor=['automask'], + ), ) inputs = LocalBistat.input_spec() diff --git a/nipype/interfaces/afni/utils.py b/nipype/interfaces/afni/utils.py index a0ca6808d6..ec30549b94 100644 --- a/nipype/interfaces/afni/utils.py +++ b/nipype/interfaces/afni/utils.py @@ -1358,12 +1358,12 @@ class LocalBistatInputSpec(AFNICommandInputSpec): '\'SPHERE\', \'RHDD\' (rhombic dodecahedron), \'TOHD\' ' '(truncated octahedron) with a given radius in mm or ' '\'RECT\' (rectangular block) with dimensions to specify in mm.', - argstr='-nbhd %s') + argstr="-nbhd '%s(%s)'") _stat_names = ['pearson', 'spearman', 'quadrant', 'mutinfo', 'normuti', 'jointent', 'hellinger', 'crU', 'crM', 'crA', 'L2slope', 'L1slope', 'num', 'ALL'] - stat = traits.Either( - traits.Enum(*_stat_names), traits.List(traits.Enum(_stat_names)), + stat = InputMultiPath( + traits.Enum(_stat_names), mandatory=True, desc='statistics to compute. Possible names are :' ' * pearson = Pearson correlation coefficient' @@ -1389,7 +1389,7 @@ class LocalBistatInputSpec(AFNICommandInputSpec): ' map that size.' ' * ALL = all of the above, in that order' 'More than one option can be used.', - argstr='-stat %s') + argstr='-stat %s...') mask_file = traits.File( exists=True, desc='mask image file name. Voxels NOT in the mask will not be used ' @@ -1397,8 +1397,10 @@ class LocalBistatInputSpec(AFNICommandInputSpec): 'will have its statistic(s) computed as zero (0).', argstr='-mask %s') automask = traits.Bool( - desc='Compute the mask as in program 3dAutomask.') - mask_file = traits.File( + desc='Compute the mask as in program 3dAutomask.', + argstr='-automask', + xor=['weight_file']) + weight_file = traits.File( exists=True, desc='File name of an image to use as a weight. Only applies to ' '\'pearson\' statistics.', @@ -1440,19 +1442,9 @@ class LocalBistat(AFNICommand): output_spec = AFNICommandOutputSpec def _format_arg(self, name, spec, value): - if name == 'neighborhood': - region_name, region_size = value - if region_name == 'RECT': - return spec.argstr % ( - "'{0}({1})'".format(region_name, ','.join(region_size))) - else: - return spec.argstr % ( - "'{0}({1})'".format(region_name, region_size)) - if name == 'stat': - if isinstance(value, (str, bytes)): - return spec.argstr % value - else: - return ' '.join([spec.argstr % v for v in value]) + if name == 'neighborhood' and value[0] == 'RECT': + value = ('RECT', '%s,%s,%s' % value[1]) + return super(LocalBistat, self)._format_arg(name, spec, value) From 71fd6d361bd3f8a0049dc012653e5fd3a1484eaf Mon Sep 17 00:00:00 2001 From: salma1601 Date: Thu, 24 May 2018 18:15:03 +0200 Subject: [PATCH 3/3] seperate file1 and file2 --- .../afni/tests/test_auto_LocalBistat.py | 9 +++++++-- nipype/interfaces/afni/utils.py | 19 ++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/nipype/interfaces/afni/tests/test_auto_LocalBistat.py b/nipype/interfaces/afni/tests/test_auto_LocalBistat.py index a36a69cbbd..64ca4c9ebe 100644 --- a/nipype/interfaces/afni/tests/test_auto_LocalBistat.py +++ b/nipype/interfaces/afni/tests/test_auto_LocalBistat.py @@ -19,7 +19,12 @@ def test_LocalBistat_inputs(): nohash=True, usedefault=True, ), - in_files=dict( + in_file1=dict( + argstr='%s', + mandatory=True, + position=-2, + ), + in_file2=dict( argstr='%s', mandatory=True, position=-1, @@ -36,7 +41,7 @@ def test_LocalBistat_inputs(): out_file=dict( argstr='-prefix %s', keep_extension=True, - name_source='in_files', + name_source='in_file1', name_template='%s_bistat', position=0, ), diff --git a/nipype/interfaces/afni/utils.py b/nipype/interfaces/afni/utils.py index ec30549b94..ce32d183ef 100644 --- a/nipype/interfaces/afni/utils.py +++ b/nipype/interfaces/afni/utils.py @@ -1339,14 +1339,18 @@ def _list_outputs(self): class LocalBistatInputSpec(AFNICommandInputSpec): - in_files = InputMultiPath( - File(exists=True), - minlen=2, - maxlen=2, + in_file1 = File( + exists=True, + mandatory=True, + argstr='%s', + position=-2, + desc='Filename of the first image') + in_file2 = File( + exists=True, mandatory=True, argstr='%s', position=-1, - desc='Filenames of the 2 images to compute statistics between') + desc='Filename of the second image') neighborhood = traits.Either( traits.Tuple(traits.Enum('SPHERE', 'RHDD', 'TOHD'), traits.Float()), traits.Tuple(traits.Enum('RECT'), traits.Tuple(traits.Float(), @@ -1409,7 +1413,7 @@ class LocalBistatInputSpec(AFNICommandInputSpec): out_file = traits.File( desc='Output dataset.', argstr='-prefix %s', - name_source='in_files', + name_source='in_file1', name_template='%s_bistat', keep_extension=True, position=0) @@ -1427,7 +1431,8 @@ class LocalBistat(AFNICommand): >>> from nipype.interfaces import afni >>> bistat = afni.LocalBistat() - >>> bistat.inputs.in_files = ['functional.nii', 'structural.nii'] + >>> bistat.inputs.in_file1 = 'functional.nii' + >>> bistat.inputs.in_file2 = 'structural.nii' >>> bistat.inputs.neighborhood = ('SPHERE', 1.2) >>> bistat.inputs.stat = 'pearson' >>> bistat.inputs.outputtype = 'NIFTI'