Skip to content

Commit 651bc85

Browse files
committed
Smart defaults
1 parent 0915a9d commit 651bc85

File tree

1 file changed

+50
-52
lines changed

1 file changed

+50
-52
lines changed

nipype/interfaces/bids.py

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
>>> os.chdir(datadir)
1515
1616
"""
17+
from os.path import join, dirname
1718
from .. import logging
1819
from .base import (traits,
1920
DynamicTraitedSpec,
@@ -24,7 +25,8 @@
2425
Undefined)
2526

2627
try:
27-
from bids.grabbids import BIDSLayout
28+
from bids import grabbids as gb
29+
import json
2830
except ImportError:
2931
have_pybids = False
3032
else:
@@ -57,40 +59,34 @@ class BIDSDataGrabber(BaseInterface):
5759
>>> from os.path import basename
5860
>>> import pprint
5961
60-
Select all files from a BIDS project
62+
By default, the BIDSDataGrabber fetches anatomical and functional images
63+
from a project, and makes BIDS entities (e.g. subject) available for
64+
filtering outputs.
6165
6266
>>> bg = BIDSDataGrabber()
6367
>>> bg.inputs.base_dir = 'ds005/'
64-
>>> results = bg.run()
65-
>>> len(results.outputs.outfield) # doctest: +ALLOW_UNICODE
66-
135
67-
68-
Using dynamically created, user-defined input fields,
69-
filter files based on BIDS entities.
70-
71-
>>> bg = BIDSDataGrabber(infields = ['subject', 'run'])
72-
>>> bg.inputs.base_dir = 'ds005/'
7368
>>> bg.inputs.subject = '01'
74-
>>> bg.inputs.run = '01'
7569
>>> results = bg.run()
76-
>>> basename(results.outputs.outfield[0]) # doctest: +ALLOW_UNICODE
70+
>>> basename(results.outputs.anat[0]) # doctest: +ALLOW_UNICODE
71+
'sub-01_T1w.nii.gz'
72+
73+
>>> basename(results.outputs.func[0]) # doctest: +ALLOW_UNICODE
7774
'sub-01_task-mixedgamblestask_run-01_bold.nii.gz'
7875
79-
Using user-defined output fields, return different types of outputs,
80-
filtered on common entities
81-
filter files based on BIDS entities.
8276
83-
>>> bg = BIDSDataGrabber(infields = ['subject'], outfields = ['func', 'anat'])
77+
Dynamically created, user-defined output fields can also be defined to
78+
return different types of outputs from the same project. All outputs
79+
are filtered on common entities, which can be explicitly defined as
80+
infields.
81+
82+
>>> bg = BIDSDataGrabber(infields = ['subject'], outfields = ['dwi'])
8483
>>> bg.inputs.base_dir = 'ds005/'
8584
>>> bg.inputs.subject = '01'
86-
>>> bg.inputs.output_query['func'] = dict(modality='func')
87-
>>> bg.inputs.output_query['anat'] = dict(modality='anat')
85+
>>> bg.inputs.output_query['dwi'] = dict(modality='dwi')
8886
>>> results = bg.run()
89-
>>> basename(results.outputs.func[0]) # doctest: +ALLOW_UNICODE
90-
'sub-01_task-mixedgamblestask_run-01_bold.nii.gz'
87+
>>> basename(results.outputs.dwi[0]) # doctest: +ALLOW_UNICODE
88+
'sub-01_dwi.nii.gz'
9189
92-
>>> basename(results.outputs.anat[0]) # doctest: +ALLOW_UNICODE
93-
'sub-01_T1w.nii.gz'
9490
"""
9591
input_spec = BIDSDataGrabberInputSpec
9692
output_spec = DynamicTraitedSpec
@@ -107,51 +103,53 @@ def __init__(self, infields=None, outfields=None, **kwargs):
107103
Indicates output fields to be dynamically created.
108104
If no matching items, returns Undefined.
109105
"""
110-
if not outfields:
111-
outfields = []
112-
if not infields:
113-
infields = []
114-
115106
super(BIDSDataGrabber, self).__init__(**kwargs)
116-
undefined_traits = {}
117-
# used for mandatory inputs check
107+
if not have_pybids:
108+
raise ImportError("The BIDSEventsGrabber interface requires pybids."
109+
" Please make sure it is installed.")
110+
111+
# If outfields is None use anat and func as default
112+
if outfields is None:
113+
outfields = ['func', 'anat']
114+
self.inputs.output_query = {
115+
"func": {"modality": "func"},
116+
"anat": {"modality": "anat"}}
117+
else:
118+
self.inputs.output_query = {}
119+
120+
# If infields is None, use all BIDS entities
121+
if infields is None:
122+
bids_config = join(dirname(gb.__file__), 'config', 'bids.json')
123+
bids_config = json.load(open(bids_config, 'r'))
124+
infields = [i['name'] for i in bids_config['entities']]
125+
118126
self._infields = infields
119127
self._outfields = outfields
128+
129+
# used for mandatory inputs check
130+
undefined_traits = {}
120131
for key in infields:
121132
self.inputs.add_trait(key, traits.Any)
122133
undefined_traits[key] = Undefined
123134

124-
if not isdefined(self.inputs.output_query):
125-
self.inputs.output_query = {}
126-
127135
self.inputs.trait_set(trait_change_notify=False, **undefined_traits)
128136

129137
def _run_interface(self, runtime):
130-
if not have_pybids:
131-
raise ImportError("The BIDSEventsGrabber interface requires pybids."
132-
" Please make sure it is installed.")
133138
return runtime
134139

135140
def _list_outputs(self):
136-
if not self._outfields:
137-
self._outfields = ['outfield']
138-
self.inputs.output_query = {'outfield' : {}}
139-
else:
140-
for key in self._outfields:
141-
if key not in self.inputs.output_query:
142-
raise ValueError("Define query for all outputs")
141+
layout = gb.BIDSLayout(self.inputs.base_dir)
142+
143+
for key in self._outfields:
144+
if key not in self.inputs.output_query:
145+
raise ValueError("Define query for all outputs")
143146

147+
# If infield is not given nm input value, silently ignore
148+
filters = {}
144149
for key in self._infields:
145150
value = getattr(self.inputs, key)
146-
if not isdefined(value):
147-
msg = "%s requires a value for input '%s' because" \
148-
" it was listed in 'infields'" % \
149-
(self.__class__.__name__, key)
150-
raise ValueError(msg)
151-
152-
layout = BIDSLayout(self.inputs.base_dir)
153-
154-
filters = {i: getattr(self.inputs, i) for i in self._infields}
151+
if isdefined(value):
152+
filters[key] = value
155153

156154
outputs = {}
157155
for key, query in self.inputs.output_query.items():

0 commit comments

Comments
 (0)