Skip to content

Commit cbbd59b

Browse files
committed
Merge branch 'master' into enh/DipyMultiTensorSimulate
2 parents ef0a9c6 + 1bef289 commit cbbd59b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+5001
-155
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
.pydevproject
1515
.idea/
1616
/documentation.zip
17+
.DS_Store

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ install:
2626
- source activate testenv
2727
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then pip install ordereddict; fi
2828
- conda install --yes numpy scipy nose traits networkx dateutil
29-
- pip install nibabel --use-mirrors
30-
- pip install python-coveralls --use-mirrors
31-
- pip install nose-cov --use-mirrors
29+
- pip install nibabel
30+
- pip install python-coveralls
31+
- pip install nose-cov
3232
- pip install https://github.com/RDFLib/rdflib/archive/master.zip
3333
- pip install https://github.com/trungdong/prov/archive/rdf.zip
3434
- python setup.py install

bin/nipype2boutiques

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env python
2+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
import sys
5+
from nipype.utils.nipype2boutiques import main
6+
7+
if __name__ == '__main__':
8+
main(sys.argv)

doc/quickstart.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,13 @@ Developer guides
5050
devel/gitwash/index
5151

5252
.. include:: links_names.txt
53+
54+
Useful links for beginners
55+
===========================
56+
57+
Getting started with Python - Tutorials. `Available here`__
58+
59+
Python for Beginners `Available here`__
60+
61+
__ http://www.codecademy.com/en/tracks/python
62+
__ https://www.python.org/about/gettingstarted/

doc/users/tutorial_101.rst

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,15 @@ This results in a workflow containing two isolated nodes:
9999

100100
**5. Connecting nodes to each other**
101101

102-
We want to connect the output produced by realignment to the input of
103-
smoothing. This is done as follows.
102+
We want to connect the output produced by the node realignment to the input of
103+
the node smoothing. This is done as follows.
104104

105105
.. testcode::
106106

107107
workflow.connect(realigner, 'realigned_files', smoother, 'in_files')
108108

109-
or alternatively, a more flexible notation can be used. Although not shown here,
110-
the following notation can be used to connect multiple outputs from one node to
109+
110+
Although not shown here, the following notation can be used to connect multiple outputs from one node to
111111
multiple inputs (see step 7 below).
112112

113113
.. testcode::
@@ -189,3 +189,22 @@ inside which are three folders: realign, smooth and artdetect (the names
189189
of the nodes). The outputs of these routines are in these folders.
190190

191191
.. include:: ../links_names.txt
192+
193+
.. glossary::
194+
195+
pipeline
196+
Connected series of processes (processes can be run parallel and or sequential)
197+
198+
workflow
199+
(kind of synonymous to pipeline) = hosting the nodes
200+
201+
node
202+
= switching-point within a pipeline, you can give it a name (in the above example e.g. realigner),
203+
a node usually requires an or several inputs and will produce an or several outputs
204+
205+
interface
206+
= specific software (e.g. FSL, SPM ...) are wrapped in interfaces, within a node instances of an
207+
interface can be run
208+
209+
modules
210+
for each interface the according modules have to be imported in the usual pythonic manner

nipype/interfaces/dipy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from .tracks import TrackDensityMap
2-
from .tensors import TensorMode
2+
from .tensors import TensorMode, DTI
33
from .preprocess import Resample, Denoise
44
from .simulate import SimulateMultiTensor

nipype/interfaces/dipy/tensors.py

Lines changed: 104 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,116 @@
2525
have_dipy = False
2626
else:
2727
import dipy.reconst.dti as dti
28-
from dipy.core.gradients import GradientTable
28+
from dipy.core.gradients import gradient_table
29+
from dipy.io.utils import nifti1_symmat
2930

3031

32+
def tensor_fitting(data, bvals, bvecs, mask_file=None):
33+
"""
34+
Use dipy to fit DTI
35+
36+
Parameters
37+
----------
38+
in_file : str
39+
Full path to a DWI data file.
40+
bvals : str
41+
Full path to a file containing gradient magnitude information (b-values).
42+
bvecs : str
43+
Full path to a file containing gradient direction information (b-vectors).
44+
mask_file : str, optional
45+
Full path to a file containing a binary mask. Defaults to use the entire volume.
46+
47+
Returns
48+
-------
49+
TensorFit object, affine
50+
"""
51+
img = nb.load(in_file).get_data()
52+
data = img.get_data()
53+
affine = img.get_affine()
54+
if mask_file is not None:
55+
mask = nb.load(self.inputs.mask_file).get_data()
56+
else:
57+
mask=None
58+
59+
# Load information about the gradients:
60+
gtab = grad.gradient_table(self.inputs.bvals, self.inputs.bvecs)
61+
62+
# Fit it
63+
tenmodel = dti.TensorModel(gtab)
64+
return tenmodel.fit(data, mask), affine
65+
66+
67+
class DTIInputSpec(TraitedSpec):
68+
in_file = File(exists=True, mandatory=True,
69+
desc='The input 4D diffusion-weighted image file')
70+
bvecs = File(exists=True, mandatory=True,
71+
desc='The input b-vector text file')
72+
bvals = File(exists=True, mandatory=True,
73+
desc='The input b-value text file')
74+
mask_file = File(exists=True, mandatory=False,
75+
desc='An optional white matter mask')
76+
out_filename = File(
77+
genfile=True, desc='The output filename for the DTI parameters image')
78+
79+
80+
class DTIOutputSpec(TraitedSpec):
81+
out_file = File(exists=True)
82+
83+
84+
class DTI(BaseInterface):
85+
"""
86+
Calculates the diffusion tensor model parameters
87+
88+
Example
89+
-------
90+
91+
>>> import nipype.interfaces.dipy as dipy
92+
>>> dti = dipy.DTI()
93+
>>> dti.inputs.in_file = 'diffusion.nii'
94+
>>> dti.inputs.bvecs = 'bvecs'
95+
>>> dti.inputs.bvals = 'bvals'
96+
>>> dti.run() # doctest: +SKIP
97+
"""
98+
input_spec = DTIInputSpec
99+
output_spec = DTIOutputSpec
100+
101+
def _run_interface(self, runtime):
102+
ten_fit, affine = tensor_fitting(self.inputs.in_file,
103+
self.inputs.bvals,
104+
self.inputs.bvecs,
105+
self.inputs.mask_file)
106+
lower_triangular = tenfit.lower_triangular()
107+
img = nifti1_symmat(lower_triangular, affine)
108+
out_file = op.abspath(self._gen_outfilename())
109+
nb.save(img, out_file)
110+
iflogger.info('DTI parameters image saved as {i}'.format(i=out_file))
111+
return runtime
112+
113+
def _list_outputs(self):
114+
outputs = self._outputs().get()
115+
outputs['out_file'] = op.abspath(self._gen_outfilename())
116+
return outputs
117+
118+
def _gen_filename(self, name):
119+
if name is 'out_filename':
120+
return self._gen_outfilename()
121+
else:
122+
return None
123+
124+
def _gen_outfilename(self):
125+
_, name, _ = split_filename(self.inputs.in_file)
126+
return name + '_dti.nii'
127+
128+
31129
class TensorModeInputSpec(TraitedSpec):
32130
in_file = File(exists=True, mandatory=True,
33131
desc='The input 4D diffusion-weighted image file')
34132
bvecs = File(exists=True, mandatory=True,
35133
desc='The input b-vector text file')
36134
bvals = File(exists=True, mandatory=True,
37135
desc='The input b-value text file')
136+
mask_file = File(exists=True, mandatory=False,
137+
desc='An optional white matter mask')
38138
out_filename = File(
39139
genfile=True, desc='The output filename for the Tensor mode image')
40140

@@ -69,32 +169,11 @@ class TensorMode(BaseInterface):
69169
output_spec = TensorModeOutputSpec
70170

71171
def _run_interface(self, runtime):
72-
## Load the 4D image files
73-
img = nb.load(self.inputs.in_file)
74-
data = img.get_data()
75-
affine = img.get_affine()
76-
77-
## Load the gradient strengths and directions
78-
bvals = np.loadtxt(self.inputs.bvals)
79-
gradients = np.loadtxt(self.inputs.bvecs).T
80-
81-
## Place in Dipy's preferred format
82-
gtab = GradientTable(gradients)
83-
gtab.bvals = bvals
84-
85-
## Mask the data so that tensors are not fit for
86-
## unnecessary voxels
87-
mask = data[..., 0] > 50
88-
89-
## Fit the tensors to the data
90-
tenmodel = dti.TensorModel(gtab)
91-
tenfit = tenmodel.fit(data, mask)
92-
93-
## Calculate the mode of each voxel's tensor
94-
mode_data = tenfit.mode
172+
ten_fit = tensor_fitting(self.inputs.in_file, self.inputs.bvals, self.inputs.bvecs,
173+
self.inputs.mask_file)
95174

96175
## Write as a 3D Nifti image with the original affine
97-
img = nb.Nifti1Image(mode_data, affine)
176+
img = nb.Nifti1Image(tenfit.mode, affine)
98177
out_file = op.abspath(self._gen_outfilename())
99178
nb.save(img, out_file)
100179
iflogger.info('Tensor mode image saved as {i}'.format(i=out_file))
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from nipype.testing import assert_equal
3+
from nipype.interfaces.dipy.tensors import DTI
4+
5+
def test_DTI_inputs():
6+
input_map = dict(bvals=dict(mandatory=True,
7+
),
8+
bvecs=dict(mandatory=True,
9+
),
10+
in_file=dict(mandatory=True,
11+
),
12+
mask_file=dict(mandatory=False,
13+
),
14+
out_filename=dict(genfile=True,
15+
),
16+
)
17+
inputs = DTI.input_spec()
18+
19+
for key, metadata in input_map.items():
20+
for metakey, value in metadata.items():
21+
yield assert_equal, getattr(inputs.traits()[key], metakey), value
22+
23+
def test_DTI_outputs():
24+
output_map = dict(out_file=dict(),
25+
)
26+
outputs = DTI.output_spec()
27+
28+
for key, metadata in output_map.items():
29+
for metakey, value in metadata.items():
30+
yield assert_equal, getattr(outputs.traits()[key], metakey), value
31+

nipype/interfaces/dipy/tests/test_auto_TensorMode.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ def test_TensorMode_inputs():
99
),
1010
in_file=dict(mandatory=True,
1111
),
12+
mask_file=dict(mandatory=False,
13+
),
1214
out_filename=dict(genfile=True,
1315
),
1416
)

nipype/interfaces/fsl/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
ImageStats, FilterRegressor, Overlay, Slicer,
1717
PlotTimeSeries, PlotMotionParams, ConvertXFM,
1818
SwapDimensions, PowerSpectrum, Reorient2Std,
19-
Complex, InvWarp, WarpUtils, ConvertWarp, WarpPoints, WarpPointsToStd)
19+
Complex, InvWarp, WarpUtils, ConvertWarp, WarpPoints,
20+
WarpPointsToStd, RobustFOV)
2021

2122
from .epi import (PrepareFieldmap, TOPUP, ApplyTOPUP, Eddy, EPIDeWarp,
2223
SigLoss, EddyCorrect, EpiReg)

nipype/interfaces/fsl/preprocess.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,26 +1388,6 @@ def _parse_inputs(self, skip=None):
13881388

13891389
return super(FUGUE, self)._parse_inputs(skip=skip)
13901390

1391-
def _list_outputs(self):
1392-
outputs = self._outputs().get()
1393-
if self.inputs.forward_warping:
1394-
out_field = 'warped_file'
1395-
else:
1396-
out_field = 'unwarped_file'
1397-
out_file = getattr(self.inputs, out_field)
1398-
if not isdefined(out_file):
1399-
if isdefined(self.inputs.in_file):
1400-
out_file = self._gen_fname(self.inputs.in_file,
1401-
suffix='_'+out_field[:-5])
1402-
if isdefined(out_file):
1403-
outputs[out_field] = os.path.abspath(out_file)
1404-
if isdefined(self.inputs.fmap_out_file):
1405-
outputs['fmap_out_file'] = os.path.abspath(
1406-
self.inputs.fmap_out_file)
1407-
if isdefined(self.inputs.shift_out_file):
1408-
outputs['shift_out_file'] = os.path.abspath(
1409-
self.inputs.shift_out_file)
1410-
return outputs
14111391

14121392
class PRELUDEInputSpec(FSLCommandInputSpec):
14131393
complex_phase_file = File(exists=True, argstr='--complex=%s',
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from nipype.testing import assert_equal
3+
from nipype.interfaces.fsl.utils import RobustFOV
4+
5+
def test_RobustFOV_inputs():
6+
input_map = dict(args=dict(argstr='%s',
7+
),
8+
environ=dict(nohash=True,
9+
usedefault=True,
10+
),
11+
ignore_exception=dict(nohash=True,
12+
usedefault=True,
13+
),
14+
in_file=dict(argstr='-i %s',
15+
mandatory=True,
16+
position=0,
17+
),
18+
out_roi=dict(argstr='-r %s',
19+
hash_files=False,
20+
name_source=['in_file'],
21+
name_template='%s_ROI',
22+
),
23+
output_type=dict(),
24+
terminal_output=dict(nohash=True,
25+
),
26+
)
27+
inputs = RobustFOV.input_spec()
28+
29+
for key, metadata in input_map.items():
30+
for metakey, value in metadata.items():
31+
yield assert_equal, getattr(inputs.traits()[key], metakey), value
32+
33+
def test_RobustFOV_outputs():
34+
output_map = dict(out_roi=dict(),
35+
)
36+
outputs = RobustFOV.output_spec()
37+
38+
for key, metadata in output_map.items():
39+
for metakey, value in metadata.items():
40+
yield assert_equal, getattr(outputs.traits()[key], metakey), value
41+

0 commit comments

Comments
 (0)