Skip to content

Commit

Permalink
bidscoiner_plugin() API change: return a personals dict instead of …
Browse files Browse the repository at this point in the history
…writing it to the `participants.tsv` file
  • Loading branch information
marcelzwiers committed Nov 1, 2023
1 parent 07281cb commit e1c8045
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 28 deletions.
2 changes: 1 addition & 1 deletion bidscoin/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -2008,7 +2008,7 @@ def poolmetadata(sourcemeta: Path, targetmeta: Path, usermeta: dict, extensions:

def addparticipant(participants_tsv: Path, subid: str='', sesid: str='', data: dict=None) -> pd.DataFrame:
"""
Read/create and/or add a participant to the participants.tsv file
Read/create and/or add (if it's not there yet) a participant to the participants.tsv file
:param participants_tsv: The participants.tsv file
:param subid: The subject label. Leave empty to just read the participants table (add nothing)
Expand Down
17 changes: 8 additions & 9 deletions bidscoin/bidscoiner.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,11 @@ def bidscoiner(rawfolder: str, bidsfolder: str, subjects: list=(), force: bool=F
# Run the bidscoiner plugins
for module in plugins:
LOGGER.verbose(f"Executing plugin: {Path(module.__file__).name}")
module.bidscoiner_plugin(sesfolder, bidsmap, bidssession)
personals = module.bidscoiner_plugin(sesfolder, bidsmap, bidssession)

# Add a subject row to the participants table (if there is any data)
if next(bidssession.rglob('*.json'), None):
participants_table = bids.addparticipant(bidsfolder/'participants.tsv', subid, sesid, personals)

# Add the special fieldmap metadata (IntendedFor, B0FieldIdentifier, TE, etc)
addmetadata(bidssession, subid, sesid)
Expand All @@ -179,15 +183,10 @@ def bidscoiner(rawfolder: str, bidsfolder: str, subjects: list=(), force: bool=F
if unpacked:
shutil.rmtree(sesfolder)

# Add a subject row to the participants table if the plugin(s) haven't done so (if there is data)
if next(bidssession.rglob('*.json'), None):
bids.addparticipant(bidsfolder/'participants.tsv', subid, sesid)

# Create/write to the json participants table sidecar file
participants_table = bids.addparticipant(bidsfolder/'participants.tsv')
participants_json = bidsfolder/'participants.json'
participants_dict = {}
newkey = False
participants_json = bidsfolder/'participants.json'
participants_dict = {}
newkey = False
if participants_json.is_file():
with participants_json.open('r') as json_fid:
participants_dict = json.load(json_fid)
Expand Down
4 changes: 2 additions & 2 deletions bidscoin/plugins/README
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def bidsmapper_plugin(session: Path, bidsmap_new: dict, bidsmap_old: dict, templ
LOGGER.verbose(f'This is a bidsmapper demo-plugin working on: {session}')


def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> Union[None, dict]:
"""
The plugin to convert the runs in the source folder and save them in the bids folder. Each saved datafile should be
accompanied by a json sidecar file. The bidsmap options for this plugin can be found in:
Expand All @@ -166,7 +166,7 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
:param session: The full-path name of the subject/session raw data source folder
:param bidsmap: The full mapping heuristics from the bidsmap YAML-file
:param bidsses: The full-path name of the BIDS output `sub-/ses-` folder
:return: Nothing
:return: A dictionary with personal data for the participants.tsv file (such as sex or age)
"""

LOGGER.verbose(f'This is a bidscoiner demo-plugin working on: {session} -> {bidsses}')
9 changes: 5 additions & 4 deletions bidscoin/plugins/dcm2niix2bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,15 @@ def bidsmapper_plugin(session: Path, bidsmap_new: dict, bidsmap_old: dict, templ
bids.append_run(bidsmap_new, run)


def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> Union[None, dict]:
"""
The bidscoiner plugin to convert the session DICOM and PAR/REC source-files into BIDS-valid NIfTI-files in the
corresponding bids session-folder and extract personals (e.g. Age, Sex) from the source header
:param session: The full-path name of the subject/session source folder
:param bidsmap: The full mapping heuristics from the bidsmap YAML-file
:param bidsses: The full-path name of the BIDS output `sub-/ses-` folder
:return: Nothing
:return: A dictionary with personal data for the participants.tsv file (such as sex or age)
"""

# Get the subject identifiers and the BIDS root folder from the bidsses folder
Expand Down Expand Up @@ -486,7 +486,7 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
scans_table.sort_values(by=['acq_time','filename'], inplace=True)
scans_table.replace('','n/a').to_csv(scans_tsv, sep='\t', encoding='utf-8', na_rep='n/a')

# Collect personal data from a source header and store it in the participants.tsv file
# Collect personal data for the participants.tsv file
if dataformat == 'DICOM': # PAR does not contain personal info
personals = {}
age = datasource.attributes('PatientAge') # A string of characters with one of the following formats: nnnD, nnnW, nnnM, nnnY
Expand All @@ -500,4 +500,5 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
personals['sex'] = datasource.attributes('PatientSex')
personals['size'] = datasource.attributes('PatientSize')
personals['weight'] = datasource.attributes('PatientWeight')
bids.addparticipant(bidsfolder/'participants.tsv', subid, sesid, personals)

return personals
9 changes: 5 additions & 4 deletions bidscoin/plugins/pet2bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,15 +173,15 @@ def bidsmapper_plugin(session: Path, bidsmap_new: dict, bidsmap_old: dict, templ
bids.append_run(bidsmap_new, run)


def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> Union[None, dict]:
"""
The bidscoiner plugin to run dcm2niix4pet, this will run dcm2niix4pet on session folders
containing PET dicoms and include metadata from meta-dataspreadsheets if present
:param session: The full-path name of the subject/session source folder
:param bidsmap: The full mapping heuristics from the bidsmap YAML-file
:param bidsses: The full-path name of the BIDS output `ses-` folder
:return: Nothing
:return: A dictionary with personal data for the participants.tsv file (such as sex or age)
"""

# Get the subject identifiers and the BIDS root folder from the bidsses folder
Expand Down Expand Up @@ -292,7 +292,7 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
with sidecar.open('w') as json_fid:
json.dump(metadata, json_fid, indent=4)

# Collect personal data from a source header and store it in the participants.tsv file
# Collect personal data for the participants.tsv file
if dataformat == 'DICOM':
personals = {}
age = datasource.attributes('PatientAge') # A string of characters with one of the following formats: nnnD, nnnW, nnnM, nnnY
Expand All @@ -306,4 +306,5 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
personals['sex'] = datasource.attributes('PatientSex')
personals['size'] = datasource.attributes('PatientSize')
personals['weight'] = datasource.attributes('PatientWeight')
bids.addparticipant(bidsfolder/'participants.tsv', subid, sesid, personals)

return personals
11 changes: 5 additions & 6 deletions bidscoin/plugins/spec2nii2bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import json
import pandas as pd
import dateutil.parser
from typing import Union
from bids_validator import BIDSValidator
from pathlib import Path
from bidscoin import bcoin, bids
Expand Down Expand Up @@ -156,7 +157,7 @@ def bidsmapper_plugin(session: Path, bidsmap_new: dict, bidsmap_old: dict, templ
bids.append_run(bidsmap_new, run)


def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> Union[None, dict]:
"""
This wrapper function around spec2nii converts the MRS data in the session folder and saves it in the bidsfolder.
Each saved datafile should be accompanied by a json sidecar file. The bidsmap options for this plugin can be found in:
Expand All @@ -166,7 +167,7 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
:param session: The full-path name of the subject/session raw data source folder
:param bidsmap: The full mapping heuristics from the bidsmap YAML-file
:param bidsses: The full-path name of the BIDS output `sub-/ses-` folder
:return: Nothing
:return: A dictionary with personal data for the participants.tsv file (such as sex or age)
"""

# Get the subject identifiers and the BIDS root folder from the bidsses folder
Expand Down Expand Up @@ -288,7 +289,7 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
scans_table.sort_values(by=['acq_time','filename'], inplace=True)
scans_table.replace('','n/a').to_csv(scans_tsv, sep='\t', encoding='utf-8', na_rep='n/a')

# Collect personal data from a source header
# Collect personal data for the participants.tsv file
personals = {}
age = ''
if dataformat == 'Twix':
Expand All @@ -315,6 +316,4 @@ def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
age = int(float(age))
personals['age'] = str(age)

# Store the collected personals in the participants_table
if personals:
bids.addparticipant(bidsfolder/'participants.tsv', subid, sesid, personals)
return personals
4 changes: 2 additions & 2 deletions docs/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ As can be seen in the API code snippet below (but also see the default plugins f
LOGGER.verbose(f'This is a bidsmapper demo-plugin working on: {session}')
def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> None:
def bidscoiner_plugin(session: Path, bidsmap: dict, bidsses: Path) -> Union[None, dict]:
"""
The plugin to convert the runs in the source folder and save them in the bids folder. Each saved datafile should be
accompanied by a json sidecar file. The bidsmap options for this plugin can be found in:
Expand All @@ -219,7 +219,7 @@ As can be seen in the API code snippet below (but also see the default plugins f
:param session: The full-path name of the subject/session source folder
:param bidsmap: The full mapping heuristics from the bidsmap YAML-file
:param bidsses: The full-path name of the BIDS output 'ses-' folder
:return: Nothing
:return: A dictionary with personal data for the participants.tsv file (such as sex or age)
"""
LOGGER.debug(f'This is a bidscoiner demo-plugin working on: {session} -> {bidsfolder}')
Expand Down

0 comments on commit e1c8045

Please sign in to comment.