Skip to content

Commit 864dbae

Browse files
committed
Merge branch 'master' of git://github.com/nipy/nipype into enh/selectdirs
2 parents 3afea0c + 32e724c commit 864dbae

34 files changed

+1810
-86
lines changed

.zenodo.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,11 @@
518518
"affiliation": "MIT, HMS",
519519
"name": "Ghosh, Satrajit",
520520
"orcid": "0000-0002-5312-6729"
521+
},
522+
{
523+
"affiliation": "University of Amsterdam",
524+
"name": "Lukas Snoek",
525+
"orcid": "0000-0001-8972-204X"
521526
}
522527
],
523528
"keywords": [

nipype/algorithms/confounds.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,9 @@ class CompCorInputSpec(BaseInterfaceInputSpec):
345345
'unspecified')
346346
save_pre_filter = traits.Either(
347347
traits.Bool, File, desc='Save pre-filter basis as text file')
348+
ignore_initial_volumes = traits.Range(
349+
low=0, usedefault=True,
350+
desc='Number of volumes at start of series to ignore')
348351

349352

350353
class CompCorOutputSpec(TraitedSpec):
@@ -357,6 +360,26 @@ class CompCor(BaseInterface):
357360
"""
358361
Interface with core CompCor computation, used in aCompCor and tCompCor
359362
363+
CompCor provides three pre-filter options, all of which include per-voxel
364+
mean removal:
365+
- polynomial: Legendre polynomial basis
366+
- cosine: Discrete cosine basis
367+
- False: mean-removal only
368+
369+
In the case of ``polynomial`` and ``cosine`` filters, a pre-filter file may
370+
be saved with a row for each volume/timepoint, and a column for each
371+
non-constant regressor.
372+
If no non-constant (mean-removal) columns are used, this file may be empty.
373+
374+
If ``ignore_initial_volumes`` is set, then the specified number of initial
375+
volumes are excluded both from pre-filtering and CompCor component
376+
extraction.
377+
Each column in the components and pre-filter files are prefixe with zeros
378+
for each excluded volume so that the number of rows continues to match the
379+
number of volumes in the input file.
380+
In addition, for each excluded volume, a column is added to the pre-filter
381+
file with a 1 in the corresponding row.
382+
360383
Example
361384
-------
362385
@@ -417,6 +440,12 @@ def _run_interface(self, runtime):
417440
header=imgseries.header)
418441
mask_images = [img]
419442

443+
skip_vols = self.inputs.ignore_initial_volumes
444+
if skip_vols:
445+
imgseries = imgseries.__class__(
446+
imgseries.get_data()[..., skip_vols:], imgseries.affine,
447+
imgseries.header)
448+
420449
mask_images = self._process_masks(mask_images, imgseries.get_data())
421450

422451
TR = 0
@@ -441,16 +470,33 @@ def _run_interface(self, runtime):
441470
imgseries.get_data(), mask_images, self.inputs.num_components,
442471
self.inputs.pre_filter, degree, self.inputs.high_pass_cutoff, TR)
443472

473+
if skip_vols:
474+
old_comp = components
475+
nrows = skip_vols + components.shape[0]
476+
components = np.zeros((nrows, components.shape[1]),
477+
dtype=components.dtype)
478+
components[skip_vols:] = old_comp
479+
444480
components_file = os.path.join(os.getcwd(), self.inputs.components_file)
445481
np.savetxt(components_file, components, fmt=b"%.10f", delimiter='\t',
446482
header=self._make_headers(components.shape[1]), comments='')
447483

448484
if self.inputs.pre_filter and self.inputs.save_pre_filter:
449485
pre_filter_file = self._list_outputs()['pre_filter_file']
450-
ftype = {'polynomial': 'poly',
451-
'cosine': 'cos'}[self.inputs.pre_filter]
486+
ftype = {'polynomial': 'Legendre',
487+
'cosine': 'Cosine'}[self.inputs.pre_filter]
452488
ncols = filter_basis.shape[1] if filter_basis.size > 0 else 0
453489
header = ['{}{:02d}'.format(ftype, i) for i in range(ncols)]
490+
if skip_vols:
491+
old_basis = filter_basis
492+
# nrows defined above
493+
filter_basis = np.zeros((nrows, ncols + skip_vols),
494+
dtype=filter_basis.dtype)
495+
if old_basis.size > 0:
496+
filter_basis[skip_vols:, :ncols] = old_basis
497+
filter_basis[:skip_vols, -skip_vols:] = np.eye(skip_vols)
498+
header.extend(['NonSteadyStateOutlier{:02d}'.format(i)
499+
for i in range(skip_vols)])
454500
np.savetxt(pre_filter_file, filter_basis, fmt=b'%.10f',
455501
delimiter='\t', header='\t'.join(header), comments='')
456502

nipype/algorithms/tests/test_auto_ACompCor.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def test_ACompCor_inputs():
1212
ignore_exception=dict(nohash=True,
1313
usedefault=True,
1414
),
15+
ignore_initial_volumes=dict(usedefault=True,
16+
),
1517
mask_files=dict(),
1618
mask_index=dict(requires=['mask_files'],
1719
xor=['merge_method'],

nipype/algorithms/tests/test_auto_TCompCor.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ def test_TCompCor_inputs():
1212
ignore_exception=dict(nohash=True,
1313
usedefault=True,
1414
),
15+
ignore_initial_volumes=dict(usedefault=True,
16+
),
1517
mask_files=dict(),
1618
mask_index=dict(requires=['mask_files'],
1719
xor=['merge_method'],

nipype/info.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def get_nipype_gitversion():
105105
PYTEST_MIN_VERSION = '3.0'
106106
FUTURE_MIN_VERSION = '0.16.0'
107107
SIMPLEJSON_MIN_VERSION = '3.8.0'
108-
PROV_MIN_VERSION = '1.5.0'
108+
PROV_VERSION = '1.5.0'
109109
CLICK_MIN_VERSION = '6.6.0'
110110

111111
NAME = 'nipype'
@@ -136,7 +136,7 @@ def get_nipype_gitversion():
136136
'traits>=%s' % TRAITS_MIN_VERSION,
137137
'future>=%s' % FUTURE_MIN_VERSION,
138138
'simplejson>=%s' % SIMPLEJSON_MIN_VERSION,
139-
'prov>=%s' % PROV_MIN_VERSION,
139+
'prov==%s' % PROV_VERSION,
140140
'click>=%s' % CLICK_MIN_VERSION,
141141
'funcsigs',
142142
'pytest>=%s' % PYTEST_MIN_VERSION,

nipype/interfaces/afni/__init__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,21 @@
88
"""
99

1010
from .base import Info
11-
from .preprocess import (Allineate, Automask, AutoTcorrelate,
11+
from .preprocess import (AlignEpiAnatPy, Allineate, Automask,
12+
AutoTcorrelate, AutoTLRC,
1213
Bandpass, BlurInMask, BlurToFWHM,
1314
ClipLevel, DegreeCentrality, Despike,
1415
Detrend, ECM, Fim, Fourier, Hist, LFCD,
1516
Maskave, Means, OutlierCount,
1617
QualityIndex, ROIStats, Retroicor,
1718
Seg, SkullStrip, TCorr1D, TCorrMap, TCorrelate,
19+
TNorm,
1820
TShift, Volreg, Warp, QwarpPlusMinus, Qwarp)
1921
from .svm import (SVMTest, SVMTrain)
20-
from .utils import (AFNItoNIFTI, Autobox, Axialize, BrickStat, Calc, Cat, Copy,
22+
from .utils import (ABoverlap, AFNItoNIFTI, Autobox, Axialize, BrickStat,
23+
Bucket, Calc, Cat, CatMatvec, Copy, Dot,
2124
Edge3, Eval, FWHMx, MaskTool, Merge, Notes, NwarpApply,
22-
Refit, Resample, TCat, TStat, To3D, Unifize, ZCutUp, GCOR,
25+
OneDToolPy,
26+
Refit, Resample, TCat, TCatSubBrick, TStat, To3D, Unifize, ZCutUp, GCOR,
2327
Zcat, Zeropad)
2428
from .model import (Deconvolve, Remlfit)

nipype/interfaces/afni/base.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import os
1010
from sys import platform
11+
from distutils import spawn
1112

1213
from ... import logging
1314
from ...utils.filemanip import split_filename, fname_presuffix
@@ -144,7 +145,6 @@ class AFNICommandOutputSpec(TraitedSpec):
144145
out_file = File(desc='output file',
145146
exists=True)
146147

147-
148148
class AFNICommand(AFNICommandBase):
149149
"""Shared options for several AFNI commands """
150150
input_spec = AFNICommandInputSpec
@@ -283,3 +283,23 @@ def no_afni():
283283
if Info.version() is None:
284284
return True
285285
return False
286+
287+
288+
class AFNIPythonCommandInputSpec(CommandLineInputSpec):
289+
outputtype = traits.Enum('AFNI', list(Info.ftypes.keys()),
290+
desc='AFNI output filetype')
291+
py27_path = traits.Either('python2', File(exists=True),
292+
usedefault=True,
293+
default='python2')
294+
295+
class AFNIPythonCommand(AFNICommand):
296+
@property
297+
def cmd(self):
298+
if spawn.find_executable(super(AFNIPythonCommand, self).cmd) is not None:
299+
return spawn.find_executable(super(AFNIPythonCommand, self).cmd)
300+
else:
301+
return super(AFNIPythonCommand, self).cmd
302+
303+
@property
304+
def cmdline(self):
305+
return "{} {}".format(self.inputs.py27_path, super(AFNIPythonCommand, self).cmdline)

0 commit comments

Comments
 (0)