-
Notifications
You must be signed in to change notification settings - Fork 296
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ENH: Use BIDS URIs to track Sources in sidecars (#3255)
Closes #3252. This is just a first pass- it only modifies the RawSources for now. I can add the immediate Sources in another PR (this'll require a lot more effort). ## Changes proposed in this pull request - Add `DatasetLinks` field to the `dataset_description.json` - The input dataset is called `raw` - Any other datasets supplied through `--derivatives` are automatically named `deriv-<index>`. We might want to support named derivatives at some point. - Replace BIDS-relative paths in `RawSources` fields with BIDS-URIs. - Change `RawSources` to `Sources` in the sidecar files, since `RawSources` is deprecated. ## Documentation that should be reviewed I'll probably need to update the documentation, but haven't yet. --------- Co-authored-by: Mathias Goncalves <[email protected]>
- Loading branch information
Showing
8 changed files
with
303 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
"""BIDS-related interfaces.""" | ||
|
||
from pathlib import Path | ||
|
||
from bids.utils import listify | ||
from nipype.interfaces.base import ( | ||
DynamicTraitedSpec, | ||
SimpleInterface, | ||
TraitedSpec, | ||
isdefined, | ||
traits, | ||
) | ||
from nipype.interfaces.io import add_traits | ||
from nipype.interfaces.utility.base import _ravel | ||
|
||
from ..utils.bids import _find_nearest_path | ||
|
||
|
||
class _BIDSURIInputSpec(DynamicTraitedSpec): | ||
dataset_links = traits.Dict(mandatory=True, desc='Dataset links') | ||
out_dir = traits.Str(mandatory=True, desc='Output directory') | ||
|
||
|
||
class _BIDSURIOutputSpec(TraitedSpec): | ||
out = traits.List( | ||
traits.Str, | ||
desc='BIDS URI(s) for file', | ||
) | ||
|
||
|
||
class BIDSURI(SimpleInterface): | ||
"""Convert input filenames to BIDS URIs, based on links in the dataset. | ||
This interface can combine multiple lists of inputs. | ||
""" | ||
|
||
input_spec = _BIDSURIInputSpec | ||
output_spec = _BIDSURIOutputSpec | ||
|
||
def __init__(self, numinputs=0, **inputs): | ||
super().__init__(**inputs) | ||
self._numinputs = numinputs | ||
if numinputs >= 1: | ||
input_names = [f'in{i + 1}' for i in range(numinputs)] | ||
else: | ||
input_names = [] | ||
add_traits(self.inputs, input_names) | ||
|
||
def _run_interface(self, runtime): | ||
inputs = [getattr(self.inputs, f'in{i + 1}') for i in range(self._numinputs)] | ||
in_files = listify(inputs) | ||
in_files = _ravel(in_files) | ||
# Remove undefined inputs | ||
in_files = [f for f in in_files if isdefined(f)] | ||
# Convert the dataset links to BIDS URI prefixes | ||
updated_keys = {f'bids:{k}:': Path(v) for k, v in self.inputs.dataset_links.items()} | ||
updated_keys['bids::'] = Path(self.inputs.out_dir) | ||
# Convert the paths to BIDS URIs | ||
out = [_find_nearest_path(updated_keys, f) for f in in_files] | ||
self._results['out'] = out | ||
|
||
return runtime |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
"""Tests for fmriprep.interfaces.bids.""" | ||
|
||
|
||
def test_BIDSURI(): | ||
"""Test the BIDSURI interface.""" | ||
from fmriprep.interfaces.bids import BIDSURI | ||
|
||
dataset_links = { | ||
'raw': '/data', | ||
'deriv-0': '/data/derivatives/source-1', | ||
} | ||
out_dir = '/data/derivatives/fmriprep' | ||
|
||
# A single element as a string | ||
interface = BIDSURI( | ||
numinputs=1, | ||
dataset_links=dataset_links, | ||
out_dir=out_dir, | ||
) | ||
interface.inputs.in1 = '/data/sub-01/func/sub-01_task-rest_bold.nii.gz' | ||
results = interface.run() | ||
assert results.outputs.out == ['bids:raw:sub-01/func/sub-01_task-rest_bold.nii.gz'] | ||
|
||
# A single element as a list | ||
interface = BIDSURI( | ||
numinputs=1, | ||
dataset_links=dataset_links, | ||
out_dir=out_dir, | ||
) | ||
interface.inputs.in1 = ['/data/sub-01/func/sub-01_task-rest_bold.nii.gz'] | ||
results = interface.run() | ||
assert results.outputs.out == ['bids:raw:sub-01/func/sub-01_task-rest_bold.nii.gz'] | ||
|
||
# Two inputs: a string and a list | ||
interface = BIDSURI( | ||
numinputs=2, | ||
dataset_links=dataset_links, | ||
out_dir=out_dir, | ||
) | ||
interface.inputs.in1 = '/data/sub-01/func/sub-01_task-rest_bold.nii.gz' | ||
interface.inputs.in2 = [ | ||
'/data/derivatives/source-1/sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
'/out/sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
] | ||
results = interface.run() | ||
assert results.outputs.out == [ | ||
'bids:raw:sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
'bids:deriv-0:sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
'/out/sub-01/func/sub-01_task-rest_bold.nii.gz', # No change | ||
] | ||
|
||
# Two inputs as lists | ||
interface = BIDSURI( | ||
numinputs=2, | ||
dataset_links=dataset_links, | ||
out_dir=out_dir, | ||
) | ||
interface.inputs.in1 = [ | ||
'/data/sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
'bids:raw:sub-01/func/sub-01_task-rest_boldref.nii.gz', | ||
] | ||
interface.inputs.in2 = [ | ||
'/data/derivatives/source-1/sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
'/out/sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
] | ||
results = interface.run() | ||
assert results.outputs.out == [ | ||
'bids:raw:sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
'bids:raw:sub-01/func/sub-01_task-rest_boldref.nii.gz', # No change | ||
'bids:deriv-0:sub-01/func/sub-01_task-rest_bold.nii.gz', | ||
'/out/sub-01/func/sub-01_task-rest_bold.nii.gz', # No change | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.