From 71e214099455d597debd171ad17a625e4a2bedc9 Mon Sep 17 00:00:00 2001 From: mathiasg Date: Wed, 17 May 2017 18:04:45 -0400 Subject: [PATCH 1/2] fix+enh: now supply custom flags + write_residuals --- nipype/interfaces/spm/model.py | 36 +++++++++++-------- .../spm/tests/test_auto_EstimateModel.py | 3 ++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/nipype/interfaces/spm/model.py b/nipype/interfaces/spm/model.py index 4a55a4ea79..e5928508ea 100644 --- a/nipype/interfaces/spm/model.py +++ b/nipype/interfaces/spm/model.py @@ -179,25 +179,27 @@ def _list_outputs(self): class EstimateModelInputSpec(SPMCommandInputSpec): spm_mat_file = File(exists=True, field='spmmat', - desc='absolute path to SPM.mat', - copyfile=True, - mandatory=True) - estimation_method = traits.Dict(traits.Enum('Classical', 'Bayesian2', - 'Bayesian'), - field='method', - desc=('Classical, Bayesian2, ' - 'Bayesian (dict)'), - mandatory=True) - flags = traits.Str(desc='optional arguments (opt)') + copyfile=True, mandatory=True, + desc='Absolute path to SPM.mat') + estimation_method = traits.Dict( + traits.Enum('Classical', 'Bayesian2', 'Bayesian'), + field='method', mandatory=True, + desc=('Dictionary of either Classical: 1, Bayesian: 1, ' + 'or Bayesian2: 1 (dict)')) + write_residuals = traits.Bool(field='write_residuals', + desc="Write individual residual images") + flags = traits.Dict(desc='Additional arguments') class EstimateModelOutputSpec(TraitedSpec): mask_image = File(exists=True, - desc='binary mask to constrain estimation') + desc='binary mask to constrain estimation') beta_images = OutputMultiPath(File(exists=True), - desc='design parameter estimates') + desc='design parameter estimates') residual_image = File(exists=True, - desc='Mean-squared image of the residuals') + desc='Mean-squared image of the residuals') + residual_images = OutputMultiPath(File(exists=True), + desc="individual residual images (requires `write_residuals`") RPVimage = File(exists=True, desc='Resels per voxel image') spm_mat_file = File(exists=True, desc='Updated SPM mat file') @@ -225,7 +227,7 @@ def _format_arg(self, opt, spec, val): return np.array([str(val)], dtype=object) if opt == 'estimation_method': if isinstance(val, (str, bytes)): - return {'%s' % val: 1} + return {'{}'.format(val): 1} else: return val return super(EstimateModel, self)._format_arg(opt, spec, val) @@ -235,7 +237,8 @@ def _parse_inputs(self): """ einputs = super(EstimateModel, self)._parse_inputs(skip=('flags')) if isdefined(self.inputs.flags): - einputs[0].update(self.inputs.flags) + einputs[0].update({flag: val for (flag, val) in + self.inputs.flags.items()}) return einputs def _list_outputs(self): @@ -262,6 +265,9 @@ def _list_outputs(self): rpv = os.path.join(pth, 'RPV.nii') else: rpv = os.path.join(pth, 'RPV.img') + if self.inputs.write_residuals: + outres = [x for x in glob(os.path.join(pth, 'Res_*'))] + outputs['residual_images'] = outres outputs['RPVimage'] = rpv spm = os.path.join(pth, 'SPM.mat') outputs['spm_mat_file'] = spm diff --git a/nipype/interfaces/spm/tests/test_auto_EstimateModel.py b/nipype/interfaces/spm/tests/test_auto_EstimateModel.py index c99ff7dd0d..eea5cf2409 100644 --- a/nipype/interfaces/spm/tests/test_auto_EstimateModel.py +++ b/nipype/interfaces/spm/tests/test_auto_EstimateModel.py @@ -23,6 +23,8 @@ def test_EstimateModel_inputs(): use_v8struct=dict(min_ver='8', usedefault=True, ), + write_residuals=dict(field='write_residuals', + ), ) inputs = EstimateModel.input_spec() @@ -36,6 +38,7 @@ def test_EstimateModel_outputs(): beta_images=dict(), mask_image=dict(), residual_image=dict(), + residual_images=dict(), spm_mat_file=dict(), ) outputs = EstimateModel.output_spec() From f6c2195b79406400311a2f09fb2b2a4e8aba0500 Mon Sep 17 00:00:00 2001 From: mathiasg Date: Thu, 18 May 2017 17:15:17 -0400 Subject: [PATCH 2/2] enh: support for bayesian estimation outputs --- nipype/interfaces/spm/model.py | 79 +++++++++++-------- .../spm/tests/test_auto_EstimateModel.py | 7 +- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/nipype/interfaces/spm/model.py b/nipype/interfaces/spm/model.py index e5928508ea..ddf35ef449 100644 --- a/nipype/interfaces/spm/model.py +++ b/nipype/interfaces/spm/model.py @@ -29,7 +29,7 @@ from ..base import (Bunch, traits, TraitedSpec, File, Directory, OutputMultiPath, InputMultiPath, isdefined) from .base import (SPMCommand, SPMCommandInputSpec, - scans_for_fnames) + scans_for_fnames, ImageFileSPM) __docformat__ = 'restructuredtext' logger = logging.getLogger('interface') @@ -192,16 +192,25 @@ class EstimateModelInputSpec(SPMCommandInputSpec): class EstimateModelOutputSpec(TraitedSpec): - mask_image = File(exists=True, + mask_image = ImageFileSPM(exists=True, desc='binary mask to constrain estimation') - beta_images = OutputMultiPath(File(exists=True), + beta_images = OutputMultiPath(ImageFileSPM(exists=True), desc='design parameter estimates') - residual_image = File(exists=True, + residual_image = ImageFileSPM(exists=True, desc='Mean-squared image of the residuals') - residual_images = OutputMultiPath(File(exists=True), + residual_images = OutputMultiPath(ImageFileSPM(exists=True), desc="individual residual images (requires `write_residuals`") - RPVimage = File(exists=True, desc='Resels per voxel image') + RPVimage = ImageFileSPM(exists=True, desc='Resels per voxel image') spm_mat_file = File(exists=True, desc='Updated SPM mat file') + labels = ImageFileSPM(exists=True, desc="label file") + SDerror = OutputMultiPath(ImageFileSPM(exists=True), + desc="Images of the standard deviation of the error") + ARcoef = OutputMultiPath(ImageFileSPM(exists=True), + desc="Images of the AR coefficient") + Cbetas = OutputMultiPath(ImageFileSPM(exists=True), + desc="Images of the parameter posteriors") + SDbetas = OutputMultiPath(ImageFileSPM(exists=True), + desc="Images of the standard deviation of parameter posteriors") class EstimateModel(SPMCommand): @@ -213,6 +222,7 @@ class EstimateModel(SPMCommand): -------- >>> est = EstimateModel() >>> est.inputs.spm_mat_file = 'SPM.mat' + >>> est.inputs.estimation_method = {'Classical': 1} >>> est.run() # doctest: +SKIP """ input_spec = EstimateModelInputSpec @@ -243,34 +253,37 @@ def _parse_inputs(self): def _list_outputs(self): outputs = self._outputs().get() - pth, _ = os.path.split(self.inputs.spm_mat_file) - spm12 = '12' in self.version.split('.')[0] - if spm12: - mask = os.path.join(pth, 'mask.nii') - else: - mask = os.path.join(pth, 'mask.img') - outputs['mask_image'] = mask + pth = os.path.dirname(self.inputs.spm_mat_file) + outtype = 'nii' if '12' in self.version.split('.')[0] else 'img' spm = sio.loadmat(self.inputs.spm_mat_file, struct_as_record=False) - betas = [] - for vbeta in spm['SPM'][0, 0].Vbeta[0]: - betas.append(str(os.path.join(pth, vbeta.fname[0]))) - if betas: - outputs['beta_images'] = betas - if spm12: - resms = os.path.join(pth, 'ResMS.nii') - else: - resms = os.path.join(pth, 'ResMS.img') - outputs['residual_image'] = resms - if spm12: - rpv = os.path.join(pth, 'RPV.nii') - else: - rpv = os.path.join(pth, 'RPV.img') - if self.inputs.write_residuals: - outres = [x for x in glob(os.path.join(pth, 'Res_*'))] - outputs['residual_images'] = outres - outputs['RPVimage'] = rpv - spm = os.path.join(pth, 'SPM.mat') - outputs['spm_mat_file'] = spm + + betas = [vbeta.fname[0] for vbeta in spm['SPM'][0, 0].Vbeta[0]] + if ('Bayesian' in self.inputs.estimation_method.keys() or + 'Bayesian2' in self.inputs.estimation_method.keys()): + outputs['labels'] = os.path.join(pth, + 'labels.{}'.format(outtype)) + outputs['SDerror'] = glob(os.path.join(pth, 'Sess*_SDerror*')) + outputs['ARcoef'] = glob(os.path.join(pth, 'Sess*_AR_*')) + if betas: + outputs['Cbetas'] = [os.path.join(pth, 'C{}'.format(beta)) + for beta in betas] + outputs['SDbetas'] = [os.path.join(pth, 'SD{}'.format(beta)) + for beta in betas] + + if 'Classical' in self.inputs.estimation_method.keys(): + outputs['residual_image'] = os.path.join(pth, + 'ResMS.{}'.format(outtype)) + outputs['RPVimage'] = os.path.join(pth, + 'RPV.{}'.format(outtype)) + if self.inputs.write_residuals: + outputs['residual_images'] = glob(os.path.join(pth, 'Res_*')) + if betas: + outputs['beta_images'] = [os.path.join(pth, beta) + for beta in betas] + + outputs['mask_image'] = os.path.join(pth, + 'mask.{}'.format(outtype)) + outputs['spm_mat_file'] = os.path.join(pth, 'SPM.mat') return outputs diff --git a/nipype/interfaces/spm/tests/test_auto_EstimateModel.py b/nipype/interfaces/spm/tests/test_auto_EstimateModel.py index eea5cf2409..703c97c6fc 100644 --- a/nipype/interfaces/spm/tests/test_auto_EstimateModel.py +++ b/nipype/interfaces/spm/tests/test_auto_EstimateModel.py @@ -34,8 +34,13 @@ def test_EstimateModel_inputs(): def test_EstimateModel_outputs(): - output_map = dict(RPVimage=dict(), + output_map = dict(ARcoef=dict(), + Cbetas=dict(), + RPVimage=dict(), + SDbetas=dict(), + SDerror=dict(), beta_images=dict(), + labels=dict(), mask_image=dict(), residual_image=dict(), residual_images=dict(),