Skip to content

Commit e78852f

Browse files
committed
Updated Deconvolve InputSpec
Added options to Deconvolve InputSpec, updated __init__.py with Deconvolve, and fixed doctests.
1 parent e23d72d commit e78852f

File tree

2 files changed

+127
-109
lines changed

2 files changed

+127
-109
lines changed

nipype/interfaces/afni/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@
2121
Eval, FWHMx,
2222
MaskTool, Merge, Notes, Refit, Resample, TCat, TStat, To3D,
2323
Unifize, ZCutUp, GCOR,)
24+
from .model import(Deconvolve)

nipype/interfaces/afni/model.py

Lines changed: 126 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,9 @@
1313
>>> os.chdir(datadir)
1414
"""
1515
from __future__ import print_function, division, unicode_literals, absolute_import
16-
from builtins import str, bytes
1716

1817
import os
19-
import os.path as op
20-
import re
21-
import numpy as np
2218

23-
from ...utils.filemanip import (load_json, save_json, split_filename)
2419
from ..base import (
2520
CommandLineInputSpec, CommandLine, Directory, TraitedSpec,
2621
traits, isdefined, File, InputMultiPath, Undefined, Str)
@@ -33,133 +28,161 @@ class DeconvolveInputSpec(AFNICommandInputSpec):
3328
in_files = InputMultiPath(
3429
File(
3530
exists=True),
36-
desc='fname = filename of 3D+time input dataset '
37-
' [more than one filename can be given] '
38-
' here, and these datasets will be] '
39-
' [auto-catenated in time; if you do this,] '
40-
' [\'-concat\' is not needed and is ignored.] '
41-
'** You can input a 1D time series file here, '
42-
' but the time axis should run along the '
43-
' ROW direction, not the COLUMN direction as '
44-
' in the -input1D option. You can automatically '
45-
' transpose a 1D file on input using the \\\' '
46-
' operator at the end of the filename, as in '
47-
' -input fred.1D\\\' '
48-
' * This is the only way to use 3dDeconvolve '
49-
' with a multi-column 1D time series file.',
31+
desc='Filenames of 3D+time input datasets. More than one filename can '
32+
'be given and the datasets will be auto-catenated in time. '
33+
'You can input a 1D time series file here, but the time axis '
34+
'should run along the ROW direction, not the COLUMN direction as '
35+
'in the \'input1D\' option.',
5036
argstr='-input %s',
5137
mandatory=True,
52-
copyfile=False)
38+
copyfile=False,
39+
sep=" ")
40+
sat = traits.Bool(
41+
desc='Check the dataset time series for initial saturation transients,'
42+
' which should normally have been excised before data analysis.',
43+
argstr='-sat',
44+
xor=['trans'])
45+
trans = traits.Bool(
46+
desc='Check the dataset time series for initial saturation transients,'
47+
' which should normally have been excised before data analysis.',
48+
argstr='-trans',
49+
xor=['sat'])
50+
noblock = traits.Bool(
51+
desc='Normally, if you input multiple datasets with \'input\', then '
52+
'the separate datasets are taken to be separate image runs that '
53+
'get separate baseline models. Use this options if you want to '
54+
'have the program consider these to be all one big run.'
55+
'* If any of the input dataset has only 1 sub-brick, then this '
56+
'option is automatically invoked!'
57+
'* If the auto-catenation feature isn\'t used, then this option '
58+
'has no effect, no how, no way.',
59+
argstr='-noblock')
60+
force_TR = traits.Int(
61+
desc='Use this value of TR instead of the one in the \'input\' '
62+
'dataset. (It\'s better to fix the input using 3drefit.)',
63+
argstr='-force_TR %d')
64+
input1D = File(
65+
desc='Filename of single (fMRI) .1D time series where time runs down '
66+
'the column.',
67+
argstr='-input1D %s',
68+
exists=True)
69+
TR_1D = traits.Float(
70+
desc='TR to use with \'input1D\'. This option has no effect if you do '
71+
'not also use \'input1D\'.',
72+
argstr='-TR_1D %f')
73+
legendre = traits.Bool(
74+
desc='Use Legendre polynomials for null hypothesis (baseline model)',
75+
argstr='-legendre')
76+
nolegendre = traits.Bool(
77+
desc='Use power polynomials for null hypotheses. Don\'t do this '
78+
'unless you are crazy!',
79+
argstr='-nolegendre')
5380
mask = File(
54-
desc='filename of 3D mask dataset; '
55-
'Only data time series from within the mask '
56-
'will be analyzed; results for voxels outside '
57-
'the mask will be set to zero.',
81+
desc='Filename of 3D mask dataset; only data time series from within '
82+
'the mask will be analyzed; results for voxels outside the mask '
83+
'will be set to zero.',
5884
argstr='-mask %s',
5985
exists=True)
6086
automask = traits.Bool(
61-
usedefault=True,
62-
argstr='-automask',
63-
desc='Build a mask automatically from input data '
64-
'(will be slow for long time series datasets)')
87+
desc='Build a mask automatically from input data (will be slow for '
88+
'long time series datasets)',
89+
argstr='-automask')
6590
censor = File(
66-
desc=' cname = filename of censor .1D time series '
67-
'* This is a file of 1s and 0s, indicating which '
68-
' time points are to be included (1) and which are '
69-
' to be excluded (0). '
70-
'* Option \'-censor\' can only be used once!',
91+
desc='Filename of censor .1D time series. This is a file of 1s and 0s, '
92+
'indicating which time points are to be included (1) and which '
93+
'are to be excluded (0).',
7194
argstr='-censor %s',
7295
exists=True)
7396
polort = traits.Int(
74-
desc='pnum = degree of polynomial corresponding to the '
75-
' null hypothesis [default: pnum = 1]',
97+
desc='Degree of polynomial corresponding to the null hypothesis '
98+
'[default: 1]',
7699
argstr='-polort %d')
77100
ortvec = traits.Tuple(
78101
File(
79102
desc='filename',
80103
exists=True),
81104
Str(
82105
desc='label'),
83-
desc='This option lets you input a rectangular array '
84-
'of 1 or more baseline vectors from file \'fff\', '
85-
'which will get the label \'lll\'. Functionally, '
86-
'it is the same as using \'-stim_file\' on each '
87-
'column of \'fff\' separately (plus \'-stim_base\'). '
88-
'This method is just a faster and simpler way to '
106+
desc='This option lets you input a rectangular array of 1 or more '
107+
'baseline vectors from a file. This method is a fast way to '
89108
'include a lot of baseline regressors in one step. ',
90109
argstr='ortvec %s')
91-
x1d = File(
92-
desc='save out X matrix',
110+
x1D = File(
111+
desc='Save out X matrix',
93112
argstr='-x1D %s')
94-
x1d_stop = traits.Bool(
95-
desc='stop running after writing .xmat.1D file',
113+
x1D_stop = traits.Bool(
114+
desc='Stop running after writing .xmat.1D file',
96115
argstr='-x1D_stop')
97-
bucket = File(
98-
desc='output statistics file',
116+
out_file = File(
117+
'bucket.nii',
118+
desc='Output statistics file',
99119
argstr='-bucket %s')
100120
jobs = traits.Int(
101-
desc='run the program with given number of sub-processes',
121+
desc='Run the program with provided number of sub-processes',
102122
argstr='-jobs %d')
103-
stim_times_subtract = traits.Float(
104-
desc='This option means to subtract \'SS\' seconds from each time '
105-
'encountered in any \'-stim_times*\' option. The purpose of this '
106-
'option is to make it simple to adjust timing files for the '
107-
'removal of images from the start of each imaging run.',
108-
argstr='-stim_times_subtract %f')
109-
num_stimts = traits.Int(
110-
desc='number of stimulus timing files',
111-
argstr='-num_stimts %d')
112-
num_glt = traits.Int(
113-
desc='number of general linear tests (i.e., contrasts)',
114-
argstr='-num_glt %d')
115-
global_times = traits.Bool(
116-
desc='use global timing for stimulus timing files',
117-
argstr='-global_times',
118-
xor=['local_times'])
119-
local_times = traits.Bool(
120-
desc='use local timing for stimulus timing files',
121-
argstr='-local_times',
122-
xor=['global_times'])
123123
fout = traits.Bool(
124-
desc='output F-statistic for each stimulus',
124+
desc='Output F-statistic for each stimulus',
125125
argstr='-fout')
126126
rout = traits.Bool(
127-
desc='output the R^2 statistic for each stimulus',
127+
desc='Output the R^2 statistic for each stimulus',
128128
argstr='-rout')
129129
tout = traits.Bool(
130-
desc='output the T-statistic for each stimulus',
130+
desc='Output the T-statistic for each stimulus',
131131
argstr='-tout')
132132
vout = traits.Bool(
133-
desc='output the sample variance (MSE) for each stimulus',
133+
desc='Output the sample variance (MSE) for each stimulus',
134134
argstr='-vout')
135+
global_times = traits.Bool(
136+
desc='Use global timing for stimulus timing files',
137+
argstr='-global_times',
138+
xor=['local_times'])
139+
local_times = traits.Bool(
140+
desc='Use local timing for stimulus timing files',
141+
argstr='-local_times',
142+
xor=['global_times'])
143+
num_stimts = traits.Int(
144+
desc='Number of stimulus timing files',
145+
argstr='-num_stimts %d',
146+
position=0)
135147
stim_times = traits.List(
136148
traits.Tuple(traits.Int(desc='k-th response model'),
137149
File(desc='stimulus timing file',exists=True),
138150
Str(desc='model')),
139-
desc='Generate the k-th response model from a set of stimulus times'
140-
' given in file \'tname\'.',
141-
argstr='-stim_times %d %s %s')
151+
desc='Generate a response model from a set of stimulus times'
152+
' given in file.',
153+
argstr='-stim_times %d %s %s...')
142154
stim_label = traits.List(
143155
traits.Tuple(traits.Int(desc='k-th input stimulus'),
144156
Str(desc='stimulus label')),
145-
desc='label for kth input stimulus',
146-
argstr='-stim_label %d %s',
157+
desc='Label for kth input stimulus',
158+
argstr='-stim_label %d %s...',
147159
requires=['stim_times'])
160+
stim_times_subtract = traits.Float(
161+
desc='This option means to subtract specified seconds from each time '
162+
'encountered in any \'stim_times\' option. The purpose of this '
163+
'option is to make it simple to adjust timing files for the '
164+
'removal of images from the start of each imaging run.',
165+
argstr='-stim_times_subtract %f')
166+
num_glt = traits.Int(
167+
desc='Number of general linear tests (i.e., contrasts)',
168+
argstr='-num_glt %d',
169+
position=1)
148170
gltsym = traits.List(
149171
Str(desc='symbolic general linear test'),
150-
desc='general linear tests (i.e., contrasts) using symbolic '
151-
'conventions',
152-
argstr='-gltsym %s')
153-
glt_labels = traits.List(
172+
desc='General linear tests (i.e., contrasts) using symbolic '
173+
'conventions (e.g., \'+Label1 -Label2\')',
174+
argstr='-gltsym SYM: %s...')
175+
glt_label = traits.List(
154176
traits.Tuple(traits.Int(desc='k-th general linear test'),
155177
Str(desc='GLT label')),
156-
desc='general linear test (i.e., contrast) labels',
157-
argstr='-glt_label %d %s',
158-
requires=['glt_sym'])
178+
desc='General linear test (i.e., contrast) labels',
179+
argstr='-glt_label %d %s...',
180+
requires=['gltsym'])
159181

160182

161-
class DeconvolveOutputSpec(TraitedSpec):
162-
pass
183+
class DeconvolveOutputSpec(AFNICommandOutputSpec):
184+
out_file = File(desc='output statistics file',
185+
exists=True)
163186

164187

165188
class Deconvolve(AFNICommand):
@@ -173,20 +196,32 @@ class Deconvolve(AFNICommand):
173196
174197
>>> from nipype.interfaces import afni
175198
>>> deconvolve = afni.Deconvolve()
176-
>>> deconvolve.inputs.in_file = 'functional.nii'
177-
>>> deconvolve.inputs.bucket = 'output.nii'
199+
>>> deconvolve.inputs.in_files = ['functional.nii', 'functional2.nii']
200+
>>> deconvolve.inputs.out_file = 'output.nii'
178201
>>> deconvolve.inputs.x1D = 'output.1D'
179-
>>> stim_times = [(1, 'stims1.txt', 'SPMG1(4)'), (2, 'stims2.txt', 'SPMG2(4)')]
202+
>>> stim_times = [(1, 'timeseries.txt', 'SPMG1(4)'), (2, 'timeseries.txt', 'SPMG2(4)')]
180203
>>> deconvolve.inputs.stim_times = stim_times
204+
>>> deconvolve.inputs.stim_label = [(1, 'Houses'), (2, 'Apartments')]
205+
>>> deconvolve.inputs.gltsym = [('SYM: +Houses -Apartments')]
206+
>>> deconvolve.inputs.glt_label = [(1, 'Houses-Apartments')]
181207
>>> deconvolve.cmdline # doctest: +ALLOW_UNICODE
182-
'3dDeconvolve -input functional.nii -bucket output.nii -x1D output -stim_times 1 stims1.txt SPMG1(4) 2 stims2.txt SPMG2(4)'
208+
'3dDeconvolve -num_stimts 2 -num_glt 1 -glt_label 1 Houses_Apartments -gltsym SYM: +Houses -Apartments -input functional.nii functional2.nii -bucket output.nii -stim_label 1 Houses -stim_label 2 Apartments -stim_times 1 timeseries.txt SPMG1(4) -stim_times 2 timeseries.txt SPMG2(4) -x1D output.1D'
183209
>>> res = deconvolve.run() # doctest: +SKIP
184210
"""
185211

186212
_cmd = '3dDeconvolve'
187213
input_spec = DeconvolveInputSpec
188214
output_spec = AFNICommandOutputSpec
189215

216+
def _parse_inputs(self, skip=None):
217+
if skip is None:
218+
skip = []
219+
if len(self.inputs.stim_times) and not isdefined(self.inputs.num_stimts):
220+
self.inputs.num_stimts = len(self.inputs.stim_times)
221+
if len(self.inputs.gltsym) and not isdefined(self.inputs.num_glt):
222+
self.inputs.num_glt = len(self.inputs.gltsym)
223+
return super(Deconvolve, self)._parse_inputs(skip)
224+
190225
def _list_outputs(self):
191226
outputs = self.output_spec().get()
192227
if isdefined(self.inputs.x1D):
@@ -195,23 +230,5 @@ def _list_outputs(self):
195230
else:
196231
outputs['x1D'] = self.inputs.x1D
197232

198-
outputs['bucket'] = self.inputs.bucket
233+
outputs['out_file'] = self.inputs.out_file
199234
return outputs
200-
201-
def _format_arg(self, name, trait_spec, value):
202-
"""
203-
Argument num_glt is defined automatically from the number of contrasts
204-
desired (defined by the length of glt_sym). No effort has been made to
205-
make this compatible with glt.
206-
"""
207-
if name in ['stim_times', 'stim_labels']:
208-
arg = ''
209-
for st in value:
210-
arg += trait_spec.argstr % value
211-
arg = arg.rstrip()
212-
return arg
213-
214-
if name == 'stim_times':
215-
self.inputs.num_stimts = len(value)
216-
elif name == 'glt_sym':
217-
self.inputs.num_glt = len(value)

0 commit comments

Comments
 (0)