Using SPM12 with Nipype is simpler than any matlabbatch
and it's intuitive to read:
from nipype.interfaces.spm import Smooth
smooth = Smooth()
smooth.inputs.in_files = 'functional.nii'
smooth.inputs.fwhm = 6
smooth.run()
The GUI might look a bit old fashion but the command line interface gives me all the flexibility I need!
I don't care that it might be more difficult to learn than other neuroimaging softwares. At least it doesn't take me 20 clicks to do simple motion correction. And once you figure out the underlying commands, it's rather simple to script.
Nipype makes using FSL even easier:
from nipype.interfaces.fsl import MCFLIRT
mcflt = MCFLIRT()
mcflt.inputs.in_file = 'functional.nii'
mcflt.run()
And gives you transparency to what's happening under the hood with one additional line:
In [1]: mcflt.cmdline
Out[1]: 'mcflirt -in functional.nii -out functional_mcf.nii'
You and your problems with fMRI data. I'm perfectly happy with FreeSurfer's command line interface. It gives me all I need to do surface based analyses.
Of course, you can run your sequential FreeSurfer scripts as you want. But wouldn't it be nice to optimize computation time by using parallel computation?
Let's imagine you want to do smoothing on the surface, with two different FWHM values, on both hemispheres and this on six subjects, all in parallel? With Nipype this is as simple as that:
from nipype.interfaces.freesurfer import SurfaceSmooth
smoother = SurfaceSmooth()
smoother.inputs.in_file = "{hemi}.func.mgz"
smoother.iterables = [("hemi", ['lh', 'rh']),
("fwhm", [4, 8]),
("subject_id", ['sub01', 'sub02', 'sub03',
'sub04', 'sub05', 'sub06']),
]
smoother.run(mode='parallel')
Let's assume we want to do preprocessing that uses SPM for motion correction, FreeSurfer for coregistration, ANTS for normalization and FSL for smoothing. Normally this would be a hell of a mess. It would mean switching between multiple scripts in different programming languages with a lot of manual intervention. Nipype comes to the rescue!
The code to create an Nipype workflow like the example before would look something like this:
# Import modules
import nipype
from nipype.interfaces.freesurfer import BBRegister
from nipype.interfaces.ants import WarpTimeSeriesImageMultiTransform
from nipype.interfaces.fsl import SUSAN
from nipype.interfaces.spm import Realing
# Motion Correction (SPM)
realign = Realing(register_to_mean=True)
# Coregistration (FreeSurfer)
coreg = BBRegister()
# Normalization (ANTS)
normalize = WarpTimeSeriesImageMultiTransform()
# Smoothing (FSL)
smooth = SUSAN(fwhm=6.0)
# Where can the raw data be found?
grabber = nipype.DataGrabber()
grabber.inputs.base_directory = '~/experiment_folder/data'
grabber.inputs.subject_id = ['subject1', 'subject2', 'subject3']
# Where should the output data be stored at?
sink = nipype.DataSink()
sink.inputs.base_directory = '~/experiment_folder/output_folder'
# Create a workflow to connect all those nodes
preprocflow = nipype.Workflow()
# Connect the nodes to each other
preprocflow.connect([(grabber -> realign ),
(realign -> coreg ),
(coreg -> normalize),
(normalize -> smooth ),
(smooth -> sink )
])
# Run the workflow in parallel
preprocflow.run(mode='parallel')
Important: This code is a shortened and simplified version of the real Nipype code. But it gives you a good idea of how intuitive it is to use Nipype for your neuroimaging analysis.
Nipype consists of many parts, but the most important ones are Interfaces, the Workflow Engine and the Execution Plugins:
Interface: Wraps a program or function
Node/MapNode: Wraps an Interface
for use in a Workflow that provides caching and other goodies (e.g., pseudo-sandbox)
Workflow: A graph or forest of graphs whose nodes are of type Node
, MapNode
or Workflow
and whose edges represent data flow
Plugin: A component that describes how a Workflow
should be executed
In [ ]:
!jupyter-nbconvert --to slides introduction_nipype.ipynb --reveal-prefix=reveal.js