Skip to content

Commit e0d829e

Browse files
authored
Merge pull request #2426 from mvdoc/enh/3dtproject
ENH+FIX: Add 3dTproject AFNI interface, Fix OneDToolPy, Add -noFDR flag to 3dDeconvolve
2 parents 765b0fc + 3adfd64 commit e0d829e

File tree

6 files changed

+248
-6
lines changed

6 files changed

+248
-6
lines changed

nipype/interfaces/afni/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
BlurInMask, BlurToFWHM, ClipLevel, DegreeCentrality, Despike, Detrend, ECM,
1414
Fim, Fourier, Hist, LFCD, Maskave, Means, OutlierCount, QualityIndex,
1515
ROIStats, Retroicor, Seg, SkullStrip, TCorr1D, TCorrMap, TCorrelate, TNorm,
16-
TShift, Volreg, Warp, QwarpPlusMinus, Qwarp)
16+
TProject, TShift, Volreg, Warp, QwarpPlusMinus, Qwarp)
1717
from .svm import (SVMTest, SVMTrain)
1818
from .utils import (
1919
ABoverlap, AFNItoNIFTI, Autobox, Axialize, BrickStat, Bucket, Calc, Cat,

nipype/interfaces/afni/model.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,10 @@ class DeconvolveInputSpec(AFNICommandInputSpec):
153153
'instead of the bucket dataset, if possible.',
154154
argstr='-cbucket %s')
155155
out_file = File(desc='output statistics file', argstr='-bucket %s')
156-
jobs = traits.Int(
156+
num_threads = traits.Int(
157157
desc='run the program with provided number of sub-processes',
158-
argstr='-jobs %d')
158+
argstr='-jobs %d',
159+
nohash=True)
159160
fout = traits.Bool(
160161
desc='output F-statistic for each stimulus', argstr='-fout')
161162
rout = traits.Bool(
@@ -165,6 +166,10 @@ class DeconvolveInputSpec(AFNICommandInputSpec):
165166
vout = traits.Bool(
166167
desc='output the sample variance (MSE) for each stimulus',
167168
argstr='-vout')
169+
nofdr = traits.Bool(
170+
desc="Don't compute the statistic-vs-FDR curves for the bucket "
171+
"dataset.",
172+
argstr='-noFDR')
168173
global_times = traits.Bool(
169174
desc='use global timing for stimulus timing files',
170175
argstr='-global_times',

nipype/interfaces/afni/preprocess.py

+165
Original file line numberDiff line numberDiff line change
@@ -2406,6 +2406,171 @@ class TNorm(AFNICommand):
24062406
output_spec = AFNICommandOutputSpec
24072407

24082408

2409+
class TProjectInputSpec(AFNICommandInputSpec):
2410+
in_file = File(
2411+
desc='input file to 3dTproject',
2412+
argstr='-input %s',
2413+
position=1,
2414+
mandatory=True,
2415+
exists=True,
2416+
copyfile=False)
2417+
out_file = File(
2418+
name_template='%s_tproject',
2419+
desc='output image file name',
2420+
position=-1,
2421+
argstr='-prefix %s',
2422+
name_source='in_file')
2423+
censor = File(
2424+
desc="""filename of censor .1D time series
2425+
* This is a file of 1s and 0s, indicating which
2426+
time points are to be included (1) and which are
2427+
to be excluded (0).""",
2428+
argstr="-censor %s",
2429+
exists=True)
2430+
censortr = traits.List(
2431+
traits.Str(),
2432+
desc="""list of strings that specify time indexes
2433+
to be removed from the analysis. Each string is
2434+
of one of the following forms:
2435+
37 => remove global time index #37
2436+
2:37 => remove time index #37 in run #2
2437+
37..47 => remove global time indexes #37-47
2438+
37-47 => same as above
2439+
2:37..47 => remove time indexes #37-47 in run #2
2440+
*:0-2 => remove time indexes #0-2 in all runs
2441+
+Time indexes within each run start at 0.
2442+
+Run indexes start at 1 (just be to confusing).
2443+
+N.B.: 2:37,47 means index #37 in run #2 and
2444+
global time index 47; it does NOT mean
2445+
index #37 in run #2 AND index #47 in run #2.""",
2446+
argstr="-CENSORTR %s")
2447+
cenmode = traits.Enum(
2448+
'KILL', 'ZERO', 'NTRP',
2449+
desc="""specifies how censored time points are treated in
2450+
the output dataset:
2451+
+ mode = ZERO ==> put zero values in their place
2452+
==> output datset is same length as input
2453+
+ mode = KILL ==> remove those time points
2454+
==> output dataset is shorter than input
2455+
+ mode = NTRP ==> censored values are replaced by interpolated
2456+
neighboring (in time) non-censored values,
2457+
BEFORE any projections, and then the
2458+
analysis proceeds without actual removal
2459+
of any time points -- this feature is to
2460+
keep the Spanish Inquisition happy.
2461+
* The default mode is KILL !!!""",
2462+
argstr='-cenmode %s')
2463+
concat = File(
2464+
desc="""The catenation file, as in 3dDeconvolve, containing the
2465+
TR indexes of the start points for each contiguous run
2466+
within the input dataset (the first entry should be 0).
2467+
++ Also as in 3dDeconvolve, if the input dataset is
2468+
automatically catenated from a collection of datasets,
2469+
then the run start indexes are determined directly,
2470+
and '-concat' is not needed (and will be ignored).
2471+
++ Each run must have at least 9 time points AFTER
2472+
censoring, or the program will not work!
2473+
++ The only use made of this input is in setting up
2474+
the bandpass/stopband regressors.
2475+
++ '-ort' and '-dsort' regressors run through all time
2476+
points, as read in. If you want separate projections
2477+
in each run, then you must either break these ort files
2478+
into appropriate components, OR you must run 3dTproject
2479+
for each run separately, using the appropriate pieces
2480+
from the ort files via the '{...}' selector for the
2481+
1D files and the '[...]' selector for the datasets.""",
2482+
exists=True,
2483+
argstr='-concat %s')
2484+
noblock = traits.Bool(
2485+
desc="""Also as in 3dDeconvolve, if you want the program to treat
2486+
an auto-catenated dataset as one long run, use this option.
2487+
++ However, '-noblock' will not affect catenation if you use
2488+
the '-concat' option.""",
2489+
argstr='-noblock')
2490+
ort = File(
2491+
desc="""Remove each column in file
2492+
++ Each column will have its mean removed.""",
2493+
exists=True,
2494+
argstr="-ort %s")
2495+
polort = traits.Int(
2496+
desc="""Remove polynomials up to and including degree pp.
2497+
++ Default value is 2.
2498+
++ It makes no sense to use a value of pp greater than
2499+
2, if you are bandpassing out the lower frequencies!
2500+
++ For catenated datasets, each run gets a separate set
2501+
set of pp+1 Legendre polynomial regressors.
2502+
++ Use of -polort -1 is not advised (if data mean != 0),
2503+
even if -ort contains constant terms, as all means are
2504+
removed.""",
2505+
argstr="-polort %d")
2506+
bandpass = traits.Tuple(
2507+
traits.Float, traits.Float,
2508+
desc="""Remove all frequencies EXCEPT those in the range""",
2509+
argstr='-bandpass %g %g')
2510+
stopband = traits.Tuple(
2511+
traits.Float, traits.Float,
2512+
desc="""Remove all frequencies in the range""",
2513+
argstr='-stopband %g %g')
2514+
TR = traits.Float(
2515+
desc="""Use time step dd for the frequency calculations,
2516+
rather than the value stored in the dataset header.""",
2517+
argstr='-TR %g')
2518+
mask = File(
2519+
exist=True,
2520+
desc="""Only operate on voxels nonzero in the mset dataset.
2521+
++ Voxels outside the mask will be filled with zeros.
2522+
++ If no masking option is given, then all voxels
2523+
will be processed.""",
2524+
argstr='-mask %s')
2525+
automask = traits.Bool(
2526+
desc="""Generate a mask automatically""",
2527+
xor=['mask'],
2528+
argstr='-automask')
2529+
blur = traits.Float(
2530+
desc="""Blur (inside the mask only) with a filter that has
2531+
width (FWHM) of fff millimeters.
2532+
++ Spatial blurring (if done) is after the time
2533+
series filtering.""",
2534+
argstr='-blur %g')
2535+
norm = traits.Bool(
2536+
desc="""Normalize each output time series to have sum of
2537+
squares = 1. This is the LAST operation.""",
2538+
argstr='-norm')
2539+
2540+
2541+
class TProject(AFNICommand):
2542+
"""
2543+
This program projects (detrends) out various 'nuisance' time series from
2544+
each voxel in the input dataset. Note that all the projections are done
2545+
via linear regression, including the frequency-based options such
2546+
as '-passband'. In this way, you can bandpass time-censored data, and at
2547+
the same time, remove other time series of no interest
2548+
(e.g., physiological estimates, motion parameters).
2549+
Shifts voxel time series from input so that seperate slices are aligned to
2550+
the same temporal origin.
2551+
2552+
For complete details, see the `3dTproject Documentation.
2553+
<https://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTproject.html>`_
2554+
2555+
Examples
2556+
========
2557+
2558+
>>> from nipype.interfaces import afni
2559+
>>> tproject = afni.TProject()
2560+
>>> tproject.inputs.in_file = 'functional.nii'
2561+
>>> tproject.inputs.bandpass = (0.00667, 99999)
2562+
>>> tproject.inputs.polort = 3
2563+
>>> tproject.inputs.automask = True
2564+
>>> tproject.inputs.out_file = 'projected.nii.gz'
2565+
>>> tproject.cmdline
2566+
'3dTproject -input functional.nii -automask -bandpass 0.00667 99999 -polort 3 -prefix projected.nii.gz'
2567+
>>> res = tproject.run() # doctest: +SKIP
2568+
2569+
"""
2570+
_cmd = '3dTproject'
2571+
input_spec = TProjectInputSpec
2572+
output_spec = AFNICommandOutputSpec
2573+
24092574
class TShiftInputSpec(AFNICommandInputSpec):
24102575
in_file = File(
24112576
desc='input file to 3dTShift',

nipype/interfaces/afni/tests/test_auto_Deconvolve.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ def test_Deconvolve_inputs():
4949
sep=' ',
5050
),
5151
input1D=dict(argstr='-input1D %s', ),
52-
jobs=dict(argstr='-jobs %d', ),
5352
legendre=dict(argstr='-legendre', ),
5453
local_times=dict(
5554
argstr='-local_times',
@@ -59,6 +58,7 @@ def test_Deconvolve_inputs():
5958
noblock=dict(argstr='-noblock', ),
6059
nocond=dict(argstr='-nocond', ),
6160
nodmbase=dict(argstr='-nodmbase', ),
61+
nofdr=dict(argstr='-noFDR', ),
6262
nolegendre=dict(argstr='-nolegendre', ),
6363
nosvd=dict(argstr='-nosvd', ),
6464
num_glt=dict(
@@ -70,8 +70,8 @@ def test_Deconvolve_inputs():
7070
position=-6,
7171
),
7272
num_threads=dict(
73+
argstr='-jobs %d',
7374
nohash=True,
74-
usedefault=True,
7575
),
7676
ortvec=dict(argstr='-ortvec %s %s', ),
7777
out_file=dict(argstr='-bucket %s', ),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from __future__ import unicode_literals
3+
from ..preprocess import TProject
4+
5+
6+
def test_TProject_inputs():
7+
input_map = dict(
8+
TR=dict(argstr='-TR %g', ),
9+
args=dict(argstr='%s', ),
10+
automask=dict(
11+
argstr='-automask',
12+
xor=['mask'],
13+
),
14+
bandpass=dict(argstr='-bandpass %g %g', ),
15+
blur=dict(argstr='-blur %g', ),
16+
cenmode=dict(argstr='-cenmode %s', ),
17+
censor=dict(argstr='-censor %s', ),
18+
censortr=dict(argstr='-CENSORTR %s', ),
19+
concat=dict(argstr='-concat %s', ),
20+
environ=dict(
21+
nohash=True,
22+
usedefault=True,
23+
),
24+
ignore_exception=dict(
25+
deprecated='1.0.0',
26+
nohash=True,
27+
usedefault=True,
28+
),
29+
in_file=dict(
30+
argstr='-input %s',
31+
copyfile=False,
32+
mandatory=True,
33+
position=1,
34+
),
35+
mask=dict(
36+
argstr='-mask %s',
37+
exist=True,
38+
),
39+
noblock=dict(argstr='-noblock', ),
40+
norm=dict(argstr='-norm', ),
41+
num_threads=dict(
42+
nohash=True,
43+
usedefault=True,
44+
),
45+
ort=dict(argstr='-ort %s', ),
46+
out_file=dict(
47+
argstr='-prefix %s',
48+
name_source='in_file',
49+
name_template='%s_tproject',
50+
position=-1,
51+
),
52+
outputtype=dict(),
53+
polort=dict(argstr='-polort %d', ),
54+
stopband=dict(argstr='-stopband %g %g', ),
55+
terminal_output=dict(
56+
deprecated='1.0.0',
57+
nohash=True,
58+
),
59+
)
60+
inputs = TProject.input_spec()
61+
62+
for key, metadata in list(input_map.items()):
63+
for metakey, value in list(metadata.items()):
64+
assert getattr(inputs.traits()[key], metakey) == value
65+
def test_TProject_outputs():
66+
output_map = dict(out_file=dict(), )
67+
outputs = TProject.output_spec()
68+
69+
for key, metadata in list(output_map.items()):
70+
for metakey, value in list(metadata.items()):
71+
assert getattr(outputs.traits()[key], metakey) == value

nipype/interfaces/afni/utils.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1815,7 +1815,8 @@ def _list_outputs(self):
18151815
os.getcwd(), self.inputs.show_cormat_warnings)
18161816
if isdefined(self.inputs.censor_motion):
18171817
outputs['out_file'] = os.path.join(os.getcwd(),
1818-
self.inputs.censor_motion[1])
1818+
self.inputs.censor_motion[1] +
1819+
'_censor.1D')
18191820
return outputs
18201821

18211822

0 commit comments

Comments
 (0)