Skip to content

Commit 15b7d86

Browse files
committed
Merge branch 'master' into enh/NewDipyInterfaces
Conflicts: CHANGES
2 parents cd7bb76 + 328a8fd commit 15b7d86

File tree

8 files changed

+88
-25
lines changed

8 files changed

+88
-25
lines changed

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ Next release
33

44
* ENH: New interfaces in dipy: RESTORE, EstimateResponseSH, CSD and StreamlineTractography
55
(https://github.com/nipy/nipype/pull/1090)
6+
* FIX: Enable absolute path definitions in DCMStack (https://github.com/nipy/nipype/pull/1089,
7+
replaced by https://github.com/nipy/nipype/pull/1093)
68
* ENH: New mesh.MeshWarpMaths to operate on surface-defined warpings
79
(https://github.com/nipy/nipype/pull/1016)
810
* FIX: Refactor P2PDistance, change name to ComputeMeshWarp, add regression tests,
@@ -53,6 +55,7 @@ Next release
5355
* ENH: Added csvReader() utility (https://github.com/nipy/nipype/pull/1044)
5456
* FIX: typo in nipype.interfaces.freesurfer.utils.py Tkregister2 (https://github.com/nipy/nipype/pull/1083)
5557
* FIX: SSHDataGrabber outputs now return full path to the grabbed/downloaded files. (https://github.com/nipy/nipype/pull/1086)
58+
* FIX: Add QA output for TSNR to resting workflow (https://github.com/nipy/nipype/pull/1088)
5659

5760
Release 0.10.0 (October 10, 2014)
5861
============

examples/rsfmri_vol_surface_preprocessing_nipy.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,8 @@ def create_reg_workflow(name='registration'):
387387
'transformed_mean',
388388
'segmentation_files',
389389
'anat2target',
390-
'aparc'
390+
'aparc',
391+
'min_cost_file'
391392
]),
392393
name='outputspec')
393394

@@ -505,7 +506,7 @@ def create_reg_workflow(name='registration'):
505506
reg.inputs.args = '--float'
506507
reg.inputs.output_warped_image = 'output_warped_image.nii.gz'
507508
reg.inputs.num_threads = 4
508-
reg.plugin_args = {'qsub_args': '-l nodes=1:ppn=4'}
509+
reg.plugin_args = {'sbatch_args': '-c%d' % 4}
509510
register.connect(stripper, 'out_file', reg, 'moving_image')
510511
register.connect(inputnode,'target_image', reg,'fixed_image')
511512

@@ -531,6 +532,7 @@ def create_reg_workflow(name='registration'):
531532
warpmean.inputs.terminal_output = 'file'
532533
warpmean.inputs.args = '--float'
533534
warpmean.inputs.num_threads = 4
535+
warpmean.plugin_args = {'sbatch_args': '-c%d' % 4}
534536

535537
register.connect(inputnode,'target_image', warpmean,'reference_image')
536538
register.connect(inputnode, 'mean_image', warpmean, 'input_image')
@@ -554,6 +556,8 @@ def create_reg_workflow(name='registration'):
554556
register.connect(reg, 'composite_transform',
555557
outputnode, 'anat2target_transform')
556558
register.connect(merge, 'out', outputnode, 'transforms')
559+
register.connect(bbregister, 'min_cost_file',
560+
outputnode, 'min_cost_file')
557561

558562
return register
559563

@@ -593,6 +597,7 @@ def create_workflow(files,
593597
realign.inputs.slice_times = slice_times
594598
realign.inputs.tr = TR
595599
realign.inputs.slice_info = 2
600+
realign.plugin_args = {'sbatch_args': '-c%d' % 4}
596601

597602

598603
# Comute TSNR on realigned data regressing polynomials upto order 2
@@ -615,6 +620,13 @@ def create_workflow(files,
615620
registration.inputs.inputspec.subjects_dir = subjects_dir
616621
registration.inputs.inputspec.target_image = target_file
617622

623+
"""Quantify TSNR in each freesurfer ROI
624+
"""
625+
get_roi_tsnr = MapNode(fs.SegStats(default_color_table=True),
626+
iterfield=['in_file'], name='get_aparc_tsnr')
627+
get_roi_tsnr.inputs.avgwf_txt_file = True
628+
wf.connect(tsnr, 'tsnr_file', get_roi_tsnr, 'in_file')
629+
wf.connect(registration, 'outputspec.aparc', get_roi_tsnr, 'segmentation_file')
618630

619631
"""Use :class:`nipype.algorithms.rapidart` to determine which of the
620632
images in the functional series are outliers based on deviations in
@@ -754,7 +766,8 @@ def merge_files(in1, in2):
754766
warpall.inputs.terminal_output = 'file'
755767
warpall.inputs.reference_image = target_file
756768
warpall.inputs.args = '--float'
757-
warpall.inputs.num_threads = 1
769+
warpall.inputs.num_threads = 2
770+
warpall.plugin_args = {'sbatch_args': '-c%d' % 2}
758771

759772
# transform to target
760773
wf.connect(collector, 'out', warpall, 'input_image')
@@ -874,13 +887,14 @@ def get_names(files, suffix):
874887
substitutions += [("_filtermotion%d" % i,"") for i in range(11)[::-1]]
875888
substitutions += [("_filter_noise_nosmooth%d" % i,"") for i in range(11)[::-1]]
876889
substitutions += [("_makecompcorfilter%d" % i,"") for i in range(11)[::-1]]
890+
substitutions += [("_get_aparc_tsnr%d/" % i, "run%d_" % (i + 1)) for i in range(11)[::-1]]
877891

878-
substitutions += [("T1_out_brain_pve_0_maths_warped","compcor_csf"),
879-
("T1_out_brain_pve_1_maths_warped","compcor_gm"),
892+
substitutions += [("T1_out_brain_pve_0_maths_warped", "compcor_csf"),
893+
("T1_out_brain_pve_1_maths_warped", "compcor_gm"),
880894
("T1_out_brain_pve_2_maths_warped", "compcor_wm"),
881-
("output_warped_image_maths","target_brain_mask"),
882-
("median_brain_mask","native_brain_mask"),
883-
("corr_","")]
895+
("output_warped_image_maths", "target_brain_mask"),
896+
("median_brain_mask", "native_brain_mask"),
897+
("corr_", "")]
884898

885899
regex_subs = [('_combiner.*/sar', '/smooth/'),
886900
('_combiner.*/ar', '/unsmooth/'),
@@ -910,6 +924,11 @@ def get_names(files, suffix):
910924
wf.connect(filter1, 'out_pf', datasink, 'resting.qa.compmaps.@mc_pF')
911925
wf.connect(filter2, 'out_f', datasink, 'resting.qa.compmaps')
912926
wf.connect(filter2, 'out_pf', datasink, 'resting.qa.compmaps.@p')
927+
wf.connect(registration, 'outputspec.min_cost_file', datasink, 'resting.qa.mincost')
928+
wf.connect(tsnr, 'tsnr_file', datasink, 'resting.qa.tsnr.@map')
929+
wf.connect([(get_roi_tsnr, datasink, [('avgwf_txt_file', 'resting.qa.tsnr'),
930+
('summary_file', 'resting.qa.tsnr.@summary')])])
931+
913932
wf.connect(bandpass, 'out_files', datasink, 'resting.timeseries.@bandpassed')
914933
wf.connect(smooth, 'out_file', datasink, 'resting.timeseries.@smoothed')
915934
wf.connect(createfilter1, 'out_files',

nipype/interfaces/dcmstack.py

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Provides interfaces to various commands provided by FreeSurfer
1+
"""Provides interfaces to various commands provided by dcmstack
22
33
Change directory to provide relative paths for doctests
44
>>> import os
@@ -9,8 +9,10 @@
99
"""
1010

1111
from __future__ import absolute_import
12-
import os, string
13-
from os import path
12+
import os
13+
import string
14+
import errno
15+
from os import path as op
1416
from glob import glob
1517
from nipype.interfaces.base import (TraitedSpec,
1618
DynamicTraitedSpec,
@@ -33,6 +35,7 @@
3335
except ImportError:
3436
have_dcmstack = False
3537

38+
3639
def sanitize_path_comp(path_comp):
3740
result = []
3841
for char in path_comp:
@@ -42,16 +45,18 @@ def sanitize_path_comp(path_comp):
4245
result.append(char)
4346
return ''.join(result)
4447

48+
4549
class NiftiGeneratorBaseInputSpec(TraitedSpec):
4650
out_format = traits.Str(desc="String which can be formatted with "
4751
"meta data to create the output filename(s)")
48-
out_ext = traits.Str('.nii.gz',
49-
usedefault=True,
52+
out_ext = traits.Str('.nii.gz', usedefault=True,
5053
desc="Determines output file type")
54+
out_path = Directory(desc='output path, current working directory if not set')
55+
5156

5257
class NiftiGeneratorBase(BaseInterface):
5358
'''Base class for interfaces that produce Nifti files, potentially with
54-
embeded meta data.'''
59+
embedded meta data.'''
5560
def _get_out_path(self, meta, idx=None):
5661
'''Return the output path for the gernerated Nifti.'''
5762
if self.inputs.out_format:
@@ -73,7 +78,22 @@ def _get_out_path(self, meta, idx=None):
7378
out_fmt = '-'.join(out_fmt)
7479
out_fn = (out_fmt % meta) + self.inputs.out_ext
7580
out_fn = sanitize_path_comp(out_fn)
76-
return path.join(os.getcwd(), out_fn)
81+
82+
out_path = os.getcwd()
83+
if isdefined(self.inputs.out_path):
84+
out_path = op.abspath(self.inputs.out_path)
85+
86+
# now, mkdir -p $out_path
87+
try:
88+
os.makedirs(out_path)
89+
except OSError as exc: # Python >2.5
90+
if exc.errno == errno.EEXIST and op.isdir(out_path):
91+
pass
92+
else:
93+
raise
94+
95+
return op.join(out_path, out_fn)
96+
7797

7898
class DcmStackInputSpec(NiftiGeneratorBaseInputSpec):
7999
dicom_files = traits.Either(InputMultiPath(File(exists=True)),
@@ -92,6 +112,7 @@ class DcmStackInputSpec(NiftiGeneratorBaseInputSpec):
92112
class DcmStackOutputSpec(TraitedSpec):
93113
out_file = File(exists=True)
94114

115+
95116
class DcmStack(NiftiGeneratorBase):
96117
'''Create one Nifti file from a set of DICOM files. Can optionally embed
97118
meta data.
@@ -111,8 +132,8 @@ class DcmStack(NiftiGeneratorBase):
111132

112133
def _get_filelist(self, trait_input):
113134
if isinstance(trait_input, six.string_types):
114-
if path.isdir(trait_input):
115-
return glob(path.join(trait_input, '*.dcm'))
135+
if op.isdir(trait_input):
136+
return glob(op.join(trait_input, '*.dcm'))
116137
else:
117138
return glob(trait_input)
118139

@@ -147,9 +168,11 @@ def _list_outputs(self):
147168
outputs["out_file"] = self.out_path
148169
return outputs
149170

171+
150172
class GroupAndStackOutputSpec(TraitedSpec):
151173
out_list = traits.List(desc="List of output nifti files")
152174

175+
153176
class GroupAndStack(DcmStack):
154177
'''Create (potentially) multiple Nifti files for a set of DICOM files.
155178
'''
@@ -177,6 +200,7 @@ def _list_outputs(self):
177200
outputs["out_list"] = self.out_list
178201
return outputs
179202

203+
180204
class LookupMetaInputSpec(TraitedSpec):
181205
in_file = File(mandatory=True,
182206
exists=True,
@@ -189,8 +213,9 @@ class LookupMetaInputSpec(TraitedSpec):
189213
"lookup and the values specify the output names")
190214
)
191215

216+
192217
class LookupMeta(BaseInterface):
193-
'''Lookup meta data values from a Nifti with embeded meta data.
218+
'''Lookup meta data values from a Nifti with embedded meta data.
194219
195220
Example
196221
-------
@@ -225,13 +250,13 @@ def _outputs(self):
225250
outputs.add_trait(out_name, traits.Any)
226251
undefined_traits[out_name] = Undefined
227252
outputs.trait_set(trait_change_notify=False, **undefined_traits)
228-
#Not sure why this is needed
253+
# Not sure why this is needed
229254
for out_name in self._meta_keys.values():
230255
_ = getattr(outputs, out_name)
231256
return outputs
232257

233258
def _run_interface(self, runtime):
234-
#If the 'meta_keys' input is a list, covert it to a dict
259+
# If the 'meta_keys' input is a list, covert it to a dict
235260
self._make_name_map()
236261
nw = NiftiWrapper.from_filename(self.inputs.in_file)
237262
self.result = {}
@@ -245,6 +270,7 @@ def _list_outputs(self):
245270
outputs.update(self.result)
246271
return outputs
247272

273+
248274
class CopyMetaInputSpec(TraitedSpec):
249275
src_file = File(mandatory=True, exists=True)
250276
dest_file = File(mandatory=True, exists=True)
@@ -254,9 +280,11 @@ class CopyMetaInputSpec(TraitedSpec):
254280
exclude_classes = traits.List(desc="List of meta data "
255281
"classifications to exclude")
256282

283+
257284
class CopyMetaOutputSpec(TraitedSpec):
258285
dest_file = File(exists=True)
259286

287+
260288
class CopyMeta(BaseInterface):
261289
'''Copy meta data from one Nifti file to another. Useful for preserving
262290
meta data after some processing steps.'''
@@ -288,8 +316,8 @@ def _run_interface(self, runtime):
288316
dest.meta_ext.slice_dim = src.meta_ext.slice_dim
289317
dest.meta_ext.shape = src.meta_ext.shape
290318

291-
self.out_path = path.join(os.getcwd(),
292-
path.basename(self.inputs.dest_file))
319+
self.out_path = op.join(os.getcwd(),
320+
op.basename(self.inputs.dest_file))
293321
dest.to_filename(self.out_path)
294322

295323
return runtime
@@ -299,6 +327,7 @@ def _list_outputs(self):
299327
outputs['dest_file'] = self.out_path
300328
return outputs
301329

330+
302331
class MergeNiftiInputSpec(NiftiGeneratorBaseInputSpec):
303332
in_files = traits.List(mandatory=True,
304333
desc="List of Nifti files to merge")
@@ -310,16 +339,19 @@ class MergeNiftiInputSpec(NiftiGeneratorBaseInputSpec):
310339
"specified, the last singular or "
311340
"non-existant dimension is used.")
312341

342+
313343
class MergeNiftiOutputSpec(TraitedSpec):
314344
out_file = File(exists=True, desc="Merged Nifti file")
315345

346+
316347
def make_key_func(meta_keys, index=None):
317348
def key_func(src_nii):
318349
result = [src_nii.get_meta(key, index) for key in meta_keys]
319350
return result
320351

321352
return key_func
322353

354+
323355
class MergeNifti(NiftiGeneratorBase):
324356
'''Merge multiple Nifti files into one. Merges together meta data
325357
extensions as well.'''
@@ -353,18 +385,23 @@ def _list_outputs(self):
353385
outputs['out_file'] = self.out_path
354386
return outputs
355387

388+
356389
class SplitNiftiInputSpec(NiftiGeneratorBaseInputSpec):
357390
in_file = File(exists=True, mandatory=True, desc="Nifti file to split")
358391
split_dim = traits.Int(desc="Dimension to split along. If not "
359392
"specified, the last dimension is used.")
360393

394+
361395
class SplitNiftiOutputSpec(TraitedSpec):
362396
out_list = traits.List(File(exists=True),
363397
desc="Split Nifti files")
364398

399+
365400
class SplitNifti(NiftiGeneratorBase):
366-
'''Split one Nifti file into many along the specified dimension. Each
367-
result has an updated meta data extension as well.'''
401+
'''
402+
Split one Nifti file into many along the specified dimension. Each
403+
result has an updated meta data extension as well.
404+
'''
368405
input_spec = SplitNiftiInputSpec
369406
output_spec = SplitNiftiOutputSpec
370407

nipype/interfaces/io.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1951,7 +1951,7 @@ def _list_outputs(self):
19511951
if not isdefined(self.inputs.out_file):
19521952
out_file = op.abspath('datasink.json')
19531953
else:
1954-
out_file = self.inputs.out_file
1954+
out_file = op.abspath(self.inputs.out_file)
19551955

19561956
out_dict = self.inputs.in_dict
19571957

nipype/interfaces/tests/test_auto_DcmStack.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def test_DcmStack_inputs():
1313
out_ext=dict(usedefault=True,
1414
),
1515
out_format=dict(),
16+
out_path=dict(),
1617
)
1718
inputs = DcmStack.input_spec()
1819

nipype/interfaces/tests/test_auto_GroupAndStack.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def test_GroupAndStack_inputs():
1313
out_ext=dict(usedefault=True,
1414
),
1515
out_format=dict(),
16+
out_path=dict(),
1617
)
1718
inputs = GroupAndStack.input_spec()
1819

nipype/interfaces/tests/test_auto_MergeNifti.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ def test_MergeNifti_inputs():
99
out_ext=dict(usedefault=True,
1010
),
1111
out_format=dict(),
12+
out_path=dict(),
1213
sort_order=dict(),
1314
)
1415
inputs = MergeNifti.input_spec()

nipype/interfaces/tests/test_auto_SplitNifti.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ def test_SplitNifti_inputs():
88
out_ext=dict(usedefault=True,
99
),
1010
out_format=dict(),
11+
out_path=dict(),
1112
split_dim=dict(),
1213
)
1314
inputs = SplitNifti.input_spec()

0 commit comments

Comments
 (0)