Skip to content

Commit

Permalink
Make the dcm2niix suffix fallback optional (pull request #214)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelzwiers committed Jan 15, 2024
1 parent dcca154 commit efcd7ac
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 10 deletions.
14 changes: 9 additions & 5 deletions bidscoin/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -1797,16 +1797,20 @@ def get_bidsname(subid: str, sesid: str, run: dict, validkeys: bool, runtime: bo

def get_bidsvalue(bidsfile: Union[str, Path], bidskey: str, newvalue: str='') -> Union[Path, str]:
"""
Sets the bidslabel, i.e. '*_bidskey-*_' is replaced with '*_bidskey-bidsvalue_'. If the key is not in the bidsname
then the newvalue is appended to the acquisition label. If newvalue is empty (= default), then the parsed existing
bidsvalue is returned and nothing is set
Sets the bidslabel, i.e. '*_bidskey-*_' is replaced with '*_bidskey-bidsvalue_'. If the key exists but is not in the
bidsname (e.g. 'fallback') then, as a fallback, the newvalue is appended to the acquisition label. If newvalue is empty
(= default), then the parsed existing bidsvalue is returned and nothing is set
:param bidsfile: The bidsname (e.g. as returned from get_bidsname or fullpath)
:param bidskey: The name of the bidskey, e.g. 'echo' or 'suffix'
:param newvalue: The new bidsvalue. NB: remove non-BIDS compliant characters beforehand (e.g. using sanitize)
:return: The bidsname with the new bidsvalue or, if newvalue is empty, the existing bidsvalue
"""

# Check input
if not bidskey and newvalue:
return bidsfile # No fallback

bidspath = Path(bidsfile).parent
bidsname = Path(bidsfile).with_suffix('').stem
bidsext = ''.join(Path(bidsfile).suffixes)
Expand All @@ -1827,8 +1831,8 @@ def get_bidsvalue(bidsfile: Union[str, Path], bidskey: str, newvalue: str='') ->

# Replace the existing bidsvalue with the new value or append the newvalue to the acquisition value
if newvalue:
if f'_{bidskey}-' not in bidsname + 'suffix':
if '_acq-' not in bidsname: # Insert the 'acq' key right after task, ses or sub key-value pair (i.e. order as in entities.yaml)
if f'_{bidskey}-' not in bidsname + 'suffix': # Fallback: Append the newvalue to the 'acq'-value
if '_acq-' not in bidsname: # Insert the 'acq' key right after task, ses or sub key-value pair (i.e. order as in entities.yaml)
keyvals = bidsname.split('_')
keyvals.insert(1 + ('_ses-' in bidsname) + ('_task-' in bidsname), 'acq-')
bidsname = '_'.join(keyvals)
Expand Down
1 change: 1 addition & 0 deletions bidscoin/heuristics/bidsmap_dccn.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Options:
args: -b y -z y -i n -l n # Argument string that is passed to dcm2niix. Tip: SPM users may want to use '-z n' (which produces unzipped NIfTI's, see dcm2niix -h for more information)
anon: y # Set this anonymization flag to 'y' to round off age and discard acquisition date from the meta data
meta: [.json, .tsv, .tsv.gz] # The file extensions of the equally named metadata sourcefiles that are copied over to the BIDS sidecar files
fallback: y # Appends unhandled dcm2niix suffixes to the `acq` label if 'y' (recommended, else the suffix data is discarded)


DICOM:
Expand Down
1 change: 1 addition & 0 deletions bidscoin/heuristics/bidsmap_sst.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Options:
args: -b y -z y -i n -l n # Argument string that is passed to dcm2niix. Tip: SPM users may want to use '-z n' (which produces unzipped NIfTI's, see dcm2niix -h for more information)
anon: y # Set this anonymization flag to 'y' to round off age and discard acquisition date from the meta data
meta: [.json, .tsv, .tsv.gz] # The file extensions of the equally named metadata sourcefiles that are copied over to the BIDS sidecar files
fallback: y # Appends unhandled dcm2niix suffixes to the `acq` label if 'y' (recommended, else the suffix data is discarded)


DICOM:
Expand Down
3 changes: 2 additions & 1 deletion bidscoin/heuristics/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"command": { "type": "string" },
"args": { "type": ["string", "null"] },
"anon": { "type": ["string", "null"] },
"meta": { "type": ["array"] }
"meta": { "type": ["array"] },
"fallback": { "type": ["string", "null"] }
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions bidscoin/plugins/dcm2niix2bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
OPTIONS = {'command': 'dcm2niix', # Command to run dcm2niix, e.g. "module add dcm2niix/1.0.20180622; dcm2niix" or "PATH=/opt/dcm2niix/bin:$PATH; dcm2niix" or /opt/dcm2niix/bin/dcm2niix or 'C:\"Program Files"\dcm2niix\dcm2niix.exe' (use quotes to deal with whitespaces in the path)
'args': '-b y -z y -i n', # Argument string that is passed to dcm2niix. Tip: SPM users may want to use '-z n' (which produces unzipped NIfTI's, see dcm2niix -h for more information)
'anon': 'y', # Set this anonymization flag to 'y' to round off age and discard acquisition date from the metadata
'meta': ['.json', '.tsv', '.tsv.gz']} # The file extensions of the equally named metadata sourcefiles that are copied over as BIDS sidecar files
'meta': ['.json', '.tsv', '.tsv.gz'], # The file extensions of the equally named metadata sourcefiles that are copied over as BIDS sidecar files
'fallback': 'y'} # Appends unhandled dcm2niix suffixes to the `acq` label if 'y' (recommended, else the suffix data is discarding)


def test(options: dict=OPTIONS) -> int:
Expand Down Expand Up @@ -199,6 +200,7 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> Union[None

# Get started and see what dataformat we have
options = bidsmap['Options']['plugins']['dcm2niix2bids']
fallback = 'fallback' if options.get('fallback','y').lower() in ('y', 'yes', 'true') else ''
datasource = bids.get_datasource(session, {'dcm2niix2bids': options})
dataformat = datasource.dataformat
if not dataformat:
Expand Down Expand Up @@ -357,10 +359,10 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> Union[None
elif echonr[0:-1].isdecimal():
LOGGER.verbose(f"Splitting off echo-number {echonr[0:-1]} from the '{postfix}' postfix")
newbidsname = bids.insert_bidskeyval(newbidsname, 'echo', echonr[0:-1].lstrip('0'), bidsignore) # Strip of the 'a', 'b', etc. from `e1a`, `e1b`, etc
newbidsname = bids.get_bidsvalue(newbidsname, 'dummy', echonr[-1]) # Append the 'a' to the acq-label
newbidsname = bids.get_bidsvalue(newbidsname, fallback, echonr[-1]) # Append the 'a' to the acq-label
else:
LOGGER.error(f"Unexpected postix '{postfix}' found in {dcm2niixfile}")
newbidsname = bids.get_bidsvalue(newbidsname, 'dummy', postfix) # Append the unknown postfix to the acq-label
newbidsname = bids.get_bidsvalue(newbidsname, fallback, postfix) # Append the unknown postfix to the acq-label

# Patch the phase entity in the newbidsname with the dcm2niix mag/phase info
elif 'part' in run['bids'] and postfix in ('ph','real','imaginary'): # e.g. part: ['', 'mag', 'phase', 'real', 'imag', 0]
Expand Down Expand Up @@ -406,7 +408,7 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> Union[None

# Append the dcm2niix info to acq-label, may need to be improved / elaborated for future BIDS standards, supporting multi-coil data
else:
newbidsname = bids.get_bidsvalue(newbidsname, 'dummy', postfix)
newbidsname = bids.get_bidsvalue(newbidsname, fallback, postfix)

# Remove the added postfix from the new bidsname
newbidsname = newbidsname.replace(f"_{postfix}_",'_') # If it is not last
Expand Down
1 change: 1 addition & 0 deletions docs/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ The `dcm2niix2bids plugin <./plugins.html#dcm2niix2bids>`__ is the default bidsc
- ``args``: Argument string that is passed as input to dcm2niix to customize its behavior, e.g. ``-z n -i y`` for ignoring derived data and having uncompressed output data.
- ``anon``: Set this anonymization flag to 'y' to round off age and to discard acquisition date from the meta data
- ``meta``: The file extensions of the associated / equally named (meta)data sourcefiles that are copied over as BIDS (sidecar) files, such as ``['.json', '.tsv', '.tsv.gz']``. You can use this to enrich json sidecar files or add data that is not supported by this plugin. For instance, with each PET DICOM image you can put a small json file with key-value pairs that are not contained in the DICOM header (such as ``{InjectedRadioactivity: 400, InjectedMass: 10}``). NB: Data entered in the meta table of the bidseditor GUI always has priority over data in source json files, which itself has priority over dcm2niix-generated json data.
- ``fallback``: Appends unhandled dcm2niix suffixes to the `acq` label if 'y' (recommended, else the suffix data is discarded)

.. tip::
- Use the [Set as default] button to put your custom dcm2niix command in your template bidsmap so that you don't have to adjust it anymore for every new study
Expand Down

0 comments on commit efcd7ac

Please sign in to comment.