From 22f3daf320ca0386d1a647b7ebf4f10595a0e361 Mon Sep 17 00:00:00 2001 From: Anthony Galassi <28850131+bendhouseart@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:33:40 -0600 Subject: [PATCH 1/5] updated to be more bids-app like --- README.md | 41 ++++++++++---------- docs/usage.rst | 28 +++++++------- petdeface/petdeface.py | 86 ++++++++++++++++++++++-------------------- 3 files changed, 80 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 6986efc..5596ee3 100644 --- a/README.md +++ b/README.md @@ -35,46 +35,43 @@ This software can be installed via source or via pip from PyPi with `pip install **_NOTE:_** This project is currently in beta release, some features listed below may not be available for version numbers < 1.0.0 ```bash -usage: petdeface.py [-h] [--output_dir OUTPUT_DIR] [--anat_only] - [--subject SUBJECT] [--session SESSION] [--docker] - [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] - [--version] [--placement PLACEMENT] [--remove_existing] - [--excludesubject] input_dir +usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--session SESSION] [--docker] [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics] + [--excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...]] + bids_dir [output_dir] [analysis_level] PetDeface positional arguments: - input_dir The directory with the input dataset + bids_dir The directory with the input dataset + output_dir The directory where the output files should be stored, if not supplied will default to /derivatives/petdeface + analysis_level This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as a participant level analysis options: -h, --help show this help message and exit - --output_dir OUTPUT_DIR, -o OUTPUT_DIR - The directory where the output files should be stored --anat_only, -a Only deface anatomical images - --subject SUBJECT, -s SUBJECT - The label of the subject to be processed. + --participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...], -pl PARTICIPANT_LABEL [PARTICIPANT_LABEL ...] + The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces. --session SESSION, -ses SESSION The label of the session to be processed. --docker, -d Run in docker container --singularity, -si Run in singularity container --n_procs N_PROCS Number of processors to use when running the workflow --skip_bids_validator - --version, -v show programs version number and exit + --version, -v show program's version number and exit --placement PLACEMENT, -p PLACEMENT - Where to place the defaced images. Options are - 'adjacent': next to the input_dir (default) in a folder appended with _defaced - 'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images - w/ defaced at input_dir - 'derivatives': does all of the defacing within the derivatives folder in input_dir. - --remove_existing, -r Remove existing output files in output_dir. - --excludesubject EXCLUDESUBJECT [EXCLUDESUBJECT ...] - Exclude a subject(s) from the defacing workflow. e.g. --excludesubject sub-01 sub-02 + Where to place the defaced images. Options are 'adjacent': next to the bids_dir (default) in a folder appended with _defaced'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir'derivatives': does all of the + defacing within the derivatives folder in bids_dir. + --remove_existing, -r + Remove existing output files in output_dir. + --preview_pics Create preview pictures of defacing, defaults to false for docker + --excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...] + Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02 ``` Working example usage: ```bash -petdeface /inputfolder --output_dir /outputfolder --n_procs 16 --skip_bids_validator --placement adjacent +petdeface /inputfolder /outputfolder --n_procs 16 --skip_bids_validator --placement adjacent ``` ### Docker Usage @@ -107,7 +104,7 @@ docker run --user=$UID:$GID -a stderr -a stdout --rm \ -v /Data/defaced_pet_data/:/output \ -v /home/freesurfer/license.txt:/opt/freesurfer/license.txt \ --platform linux/amd64 \ -petdeface:latest /input --output_dir /output --n_procs 16 --skip_bids_validator --placement adjacent --user=$UID:$GID system_platform=Linux +petdeface:latest /input /output --n_procs 16 --skip_bids_validator --placement adjacent --user=$UID:$GID system_platform=Linux ``` ### Singularity Usage @@ -127,7 +124,7 @@ Otherwise, one can run and execute petdeface with the same syntax as calling it with `singularity exec -e` ```bash -singularity exec -e --bind license.txt:/opt/freesurfer/license.txt docker://openneuropet/petdeface:0.1.1 petdeface /input --output-dir /output --n_procs 10 +singularity exec -e --bind license.txt:/opt/freesurfer/license.txt docker://openneuropet/petdeface:0.1.1 petdeface /input /output --n_procs 10 ``` **_NOTE_**: Testing with singularity has been limited to version singularity-ce 4.2.0, please let us know in the issues section of this repo if you have diff --git a/docs/usage.rst b/docs/usage.rst index a3e1cfc..ef357f2 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -81,40 +81,42 @@ When viewed, a succesfully defaced PET image will have varying intensities in th The number of processors made available to PETdeface can be set by the `--n_procs` flag e.g.:: - petdeface /inputfolder --output_dir /outputfolder --n_procs 4 + petdeface /inputfolder /outputfolder --n_procs 4 Additional options can be found in the help menu:: petdeface -h - usage: petdeface [-h] [--output_dir OUTPUT_DIR] [--anat_only] [--subject SUBJECT] [--session SESSION] [--docker] [--n_procs N_PROCS] [--skip_bids_validator] [--version] - [--placement PLACEMENT] [--remove_existing] - input_dir + usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--session SESSION] [--docker] [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics] + [--excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...]] + bids_dir [output_dir] [analysis_level] PetDeface positional arguments: - input_dir The directory with the input dataset + bids_dir The directory with the input dataset + output_dir The directory where the output files should be stored, if not supplied will default to /derivatives/petdeface + analysis_level This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as a participant level analysis options: -h, --help show this help message and exit - --output_dir OUTPUT_DIR, -o OUTPUT_DIR - The directory where the output files should be stored --anat_only, -a Only deface anatomical images - --subject SUBJECT, -s SUBJECT - The label of the subject to be processed. + --participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...], -pl PARTICIPANT_LABEL [PARTICIPANT_LABEL ...] + The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces. --session SESSION, -ses SESSION The label of the session to be processed. --docker, -d Run in docker container + --singularity, -si Run in singularity container --n_procs N_PROCS Number of processors to use when running the workflow --skip_bids_validator --version, -v show program's version number and exit --placement PLACEMENT, -p PLACEMENT - Where to place the defaced images. Options are 'adjacent': next to the input_dir (default) in a folder appended with _defaced'inplace': defaces the dataset in place, - e.g. replaces faced PET and T1w images w/ defaced at input_dir'derivatives': does all of the defacing within the derivatives folder in input_dir. + Where to place the defaced images. Options are 'adjacent': next to the bids_dir (default) in a folder appended with _defaced'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir'derivatives': does all of the + defacing within the derivatives folder in bids_dir. --remove_existing, -r Remove existing output files in output_dir. - --excludesubject EXCLUDESUBJECT [EXCLUDESUBJECT ...] - Exclude a subject(s) from the defacing workflow. e.g. --excludesubject sub-01 sub-02 + --preview_pics Create preview pictures of defacing, defaults to false for docker + --excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...] + Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02 Docker Based ------------ diff --git a/petdeface/petdeface.py b/petdeface/petdeface.py index 587b55d..6b88197 100755 --- a/petdeface/petdeface.py +++ b/petdeface/petdeface.py @@ -223,8 +223,8 @@ def deface(args: Union[dict, argparse.Namespace]) -> None: if not check_valid_fs_license() and not locate_freesurfer_license().exists(): raise Exception("You need a valid FreeSurfer license to proceed!") - if args.subject: - subjects = args.subject + if args.participant_label: + subjects = args.participant_label # if subject contains the string sub-, remove it to avoid redundancy as pybids will add it uses the # right side of the sub- string as the subject label if any("sub-" in subject for subject in subjects): @@ -247,15 +247,15 @@ def deface(args: Union[dict, argparse.Namespace]) -> None: ) # check to see if any subjects are excluded from the defacing workflow - if args.excludesubject != []: + if args.excludeparticipant != []: print( - f"Removing the following subjects {args.excludesubject} from the defacing workflow" + f"Removing the following subjects {args.excludeparticipant} from the defacing workflow" ) - args.excludesubject = [ - subject.replace("sub-", "") for subject in args.excludesubject + args.excludeparticipant = [ + subject.replace("sub-", "") for subject in args.excludeparticipant ] subjects = [ - subject for subject in subjects if subject not in args.excludesubject + subject for subject in subjects if subject not in args.excludeparticipant ] print(f"Subjects remaining in the defacing workflow: {subjects}") @@ -540,7 +540,7 @@ def wrap_up_defacing( :param path_to_dataset: Path to original dataset :type path_to_dataset: path like object (str or pathlib.Path) :param output_dir: Specific directory to place output, arguably redundant given placemnent, defaults to - input_dir/derivatives/petdeface + bids_dir/derivatives/petdeface :type output_dir: path like object (str or pathlib.Path), optional :param placement: str, optional Can be one of three values @@ -726,7 +726,7 @@ def __init__( remove_existing=True, # TODO: currently not implemented placement="adjacent", # TODO: currently not implemented preview_pics=True, - excludesubject=[], + excludeparticipant=[], ): self.bids_dir = bids_dir self.remove_existing = remove_existing @@ -738,7 +738,7 @@ def __init__( self.n_procs = n_procs self.skip_bids_validator = skip_bids_validator self.preview_pics = preview_pics - self.excludesubject = excludesubject + self.excludeparticipant = excludeparticipant # check if freesurfer license is valid self.fs_license = check_valid_fs_license() @@ -767,7 +767,7 @@ def run(self): "placement": self.placement, "remove_existing": self.remove_existing, "preview_pics": self.preview_pics, - "excludesubject": self.excludesubject, + "excludeparticipant": self.excludeparticipant, } ) wrap_up_defacing( @@ -785,16 +785,22 @@ def cli(): parser = argparse.ArgumentParser(description="PetDeface") parser.add_argument( - "input_dir", help="The directory with the input dataset", type=pathlib.Path + "bids_dir", help="The directory with the input dataset", type=pathlib.Path ) parser.add_argument( - "--output_dir", - "-o", - help="The directory where the output files should be stored", + "output_dir", + nargs="?", + help="The directory where the output files should be stored, if not supplied will default to /derivatives/petdeface", type=pathlib.Path, - required=False, default=None, ) + parser.add_argument( + 'analysis_level', + nargs='?', + default='participant', + help="This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as " + "a participant level analysis", + ) parser.add_argument( "--anat_only", "-a", @@ -803,9 +809,9 @@ def cli(): help="Only deface anatomical images", ) parser.add_argument( - "--subject", - "-s", - help="The label of the subject to be processed.", + "--participant_label", + "-pl", + help="The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces.", type=str, nargs="+", required=False, @@ -849,9 +855,9 @@ def cli(): "--placement", "-p", help="Where to place the defaced images. Options are " - "'adjacent': next to the input_dir (default) in a folder appended with _defaced" - "'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at input_dir" - "'derivatives': does all of the defacing within the derivatives folder in input_dir.", + "'adjacent': next to the bids_dir (default) in a folder appended with _defaced" + "'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir" + "'derivatives': does all of the defacing within the derivatives folder in bids_dir.", type=str, required=False, default="adjacent", @@ -870,8 +876,8 @@ def cli(): default=False, ) parser.add_argument( - "--excludesubject", - help="Exclude a subject(s) from the defacing workflow. e.g. --excludesubject sub-01 sub-02", + "--excludeparticipant", + help="Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02", type=str, nargs="+", required=False, @@ -900,10 +906,10 @@ def main(): # noqa: max-complexity: 12 args = cli() - if isinstance(args.input_dir, pathlib.PosixPath) and "~" in str(args.input_dir): - args.input_dir = args.input_dir.expanduser().resolve() + if isinstance(args.bids_dir, pathlib.PosixPath) and "~" in str(args.bids_dir): + args.bids_dir = args.bids_dir.expanduser().resolve() else: - args.input_dir = args.input_dir.absolute() + args.bids_dir = args.bids_dir.absolute() if isinstance(args.output_dir, pathlib.PosixPath) and "~" in str(args.output_dir): args.output_dir = args.output_dir.expanduser().resolve() else: @@ -920,22 +926,22 @@ def main(): # noqa: max-complexity: 12 gid = os.getegid() system_platform = system() - input_mount_point = str(args.input_dir) + input_mount_point = str(args.bids_dir) output_mount_point = str(args.output_dir) if output_mount_point == "None" or output_mount_point is None: - output_mount_point = str(args.input_dir / "derivatives" / "petdeface") + output_mount_point = str(args.bids_dir / "derivatives" / "petdeface") # create output directory if it doesn't exist if not pathlib.Path(output_mount_point).exists(): pathlib.Path(output_mount_point).mkdir(parents=True, exist_ok=True) subprocess.run(f"chown -R {uid}:{gid} {str(output_mount_point)}", shell=True) - args.input_dir = pathlib.Path("/input") + args.bids_dir = pathlib.Path("/input") args.output_dir = pathlib.Path("/output") print( "Attempting to run in docker container, mounting {} to {} and {} to {}".format( - input_mount_point, args.input_dir, output_mount_point, args.output_dir + input_mount_point, args.bids_dir, output_mount_point, args.output_dir ) ) # convert args to dictionary @@ -957,9 +963,9 @@ def main(): # noqa: max-complexity: 12 ) args_string = args_string.replace("empty_str", "") - # remove --input_dir from args_string as input dir is positional, we + # remove --bids_dir from args_string as input dir is positional, we # we're simply removing an artifact of argparse - args_string = args_string.replace("--input_dir", "") + args_string = args_string.replace("--bids_dir", "") # invoke docker run command to run petdeface in container, while redirecting stdout and stderr to terminal docker_command = f"docker run " @@ -969,7 +975,7 @@ def main(): # noqa: max-complexity: 12 docker_command += ( f"-a stderr -a stdout --rm " - f"-v {input_mount_point}:{args.input_dir} " + f"-v {input_mount_point}:{args.bids_dir} " f"-v {output_mount_point}:{args.output_dir} " ) if code_dir: @@ -1005,7 +1011,7 @@ def main(): # noqa: max-complexity: 12 singularity_command = f"singularity exec -e" if args.output_dir == "None" or args.output_dir is None or args.output_dir == "": - args.output_dir = args.input_dir / "derivatives" / "petdeface" + args.output_dir = args.bids_dir / "derivatives" / "petdeface" # create output directory if it doesn't exist if not args.output_dir.exists(): @@ -1030,9 +1036,9 @@ def main(): # noqa: max-complexity: 12 ) args_string = args_string.replace("empty_str", "") - # remove --input_dir from args_string as input dir is positional, we + # remove --bids_dir from args_string as input dir is positional, we # we're simply removing an artifact of argparse - args_string = args_string.replace("--input_dir", "") + args_string = args_string.replace("--bids_dir", "") # collect location of freesurfer license if it's installed and working try: @@ -1057,17 +1063,17 @@ def main(): # noqa: max-complexity: 12 else: petdeface = PetDeface( - bids_dir=args.input_dir, + bids_dir=args.bids_dir, output_dir=args.output_dir, anat_only=args.anat_only, - subject=args.subject, + subject=args.participant_label, session=args.session, n_procs=args.n_procs, skip_bids_validator=args.skip_bids_validator, remove_existing=args.remove_existing, placement=args.placement, preview_pics=args.preview_pics, - excludesubject=args.excludesubject, + excludeparticipant=args.excludeparticipant, ) petdeface.run() From 75e29f108d9b547fcaf9895efed464202a8e4b78 Mon Sep 17 00:00:00 2001 From: Anthony Galassi <28850131+bendhouseart@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:36:10 -0600 Subject: [PATCH 2/5] enabled anat only, cleaned up comments --- petdeface/petdeface.py | 194 ++++++++++++++++++++++------------------- pyproject.toml | 2 +- 2 files changed, 105 insertions(+), 91 deletions(-) diff --git a/petdeface/petdeface.py b/petdeface/petdeface.py index 6b88197..29b94f4 100755 --- a/petdeface/petdeface.py +++ b/petdeface/petdeface.py @@ -52,7 +52,9 @@ for place in places_to_look: for root, folders, files in os.walk(place): for file in files: - if file.endswith("pyproject.toml") and "petdeface" in os.path.join(root, file): + if file.endswith("pyproject.toml") and "petdeface" in os.path.join( + root, file + ): toml_file = os.path.join(root, file) with open(toml_file, "r") as f: @@ -71,12 +73,12 @@ # we check the version with a regex expression to see if all of the parts are there if re.match(r"\d+\.\d+\.\d+", __version__): break - + if __version__ != "unable to locate version number in pyproject.toml": - # we try to load the version using import lib - __version__ = importlib.metadata.version("petdeface") - if re.match(r"\d+\.\d+\.\d+", __version__): - break + # we try to load the version using import lib + __version__ = importlib.metadata.version("petdeface") + if re.match(r"\d+\.\d+\.\d+", __version__): + break def locate_freesurfer_license(): @@ -101,7 +103,7 @@ def locate_freesurfer_license(): else: return fs_license_env_var else: - # collect freesurfer home environment variable and look there instead + # collect freesurfer home environment variable and look there instead fs_home = pathlib.Path(os.environ.get("FREESURFER_HOME", "")) if not fs_home: raise ValueError( @@ -271,7 +273,10 @@ def deface(args: Union[dict, argparse.Namespace]) -> None: for subject_id in subjects: try: single_subject_wf = init_single_subject_wf( - subject_id, args.bids_dir, preview_pics=args.preview_pics + subject_id, + args.bids_dir, + preview_pics=args.preview_pics, + anat_only=args.anat_only, ) except FileNotFoundError: single_subject_wf = None @@ -294,9 +299,10 @@ def deface(args: Union[dict, argparse.Namespace]) -> None: def init_single_subject_wf( subject_id: str, - bids_data: [pathlib.Path, BIDSLayout], + bids_data: Union[pathlib.Path, BIDSLayout], output_dir: pathlib.Path = None, preview_pics=False, + anat_only=False, ) -> Workflow: """ Organize the preprocessing pipeline for a single subject. @@ -307,6 +313,10 @@ def init_single_subject_wf( :type bids_data: pathlib.Path, BIDSLayout] :param output_dir: _description_, defaults to None :type output_dir: pathlib.Path, optional + :param preview_pics: _description_, defaults to False + :type preview_pics: bool, optional + :param anat_only: _description_, defaults to False + :type anat_only: bool, optional :raises FileNotFoundError: _description_ :return: _description_ :rtype: Workflow @@ -404,71 +414,80 @@ def init_single_subject_wf( t1w_workflows[t1w_file] = {"workflow": t1w_wf, "anat_string": anat_string} workflow = Workflow(name=name) - for pet_file, t1w_file in subject_data.items(): - try: - ses_id = re.search("ses-[^_|\/]*", str(pet_file)).group(0) - pet_string = f"sub-{subject_id}_{ses_id}" - except AttributeError: - ses_id = "" - pet_string = f"sub-{subject_id}" + if anat_only: + for each in t1w_workflows.values(): + workflow.add_nodes([each["workflow"]]) + else: + for pet_file, t1w_file in subject_data.items(): + try: + ses_id = re.search("ses-[^_|\/]*", str(pet_file)).group(0) + pet_string = f"sub-{subject_id}_{ses_id}" + except AttributeError: + ses_id = "" + pet_string = f"sub-{subject_id}" - # collect run info from pet file - try: - run_id = "_" + re.search("run-[^_|\/]*", str(pet_file)).group(0) - except AttributeError: - run_id = "" - pet_wf_name = f"pet_{pet_string}{run_id}_wf" - pet_wf = Workflow(name=pet_wf_name) - - weighted_average = Node( - WeightedAverage(pet_file=pet_file), name="weighted_average" - ) + # collect run info from pet file + try: + run_id = "_" + re.search("run-[^_|\/]*", str(pet_file)).group(0) + except AttributeError: + run_id = "" + pet_wf_name = f"pet_{pet_string}{run_id}_wf" + pet_wf = Workflow(name=pet_wf_name) + + weighted_average = Node( + WeightedAverage(pet_file=pet_file), name="weighted_average" + ) - # rename registration file to something more descriptive than registration.lta - # we do this here to account for mulitple runs during the same session - mricoreg = MRICoreg(reference_file=t1w_file) - mricoreg.inputs.out_lta_file = f"{pet_string}{run_id}_desc-pet2anat_pet.lta" + # rename registration file to something more descriptive than registration.lta + # we do this here to account for mulitple runs during the same session + mricoreg = MRICoreg(reference_file=t1w_file) + mricoreg.inputs.out_lta_file = f"{pet_string}{run_id}_desc-pet2anat_pet.lta" - coreg_pet_to_t1w = Node(mricoreg, "coreg_pet_to_t1w") + coreg_pet_to_t1w = Node(mricoreg, "coreg_pet_to_t1w") - deface_pet = Node(ApplyMideface(in_file=pet_file), name="deface_pet") + deface_pet = Node(ApplyMideface(in_file=pet_file), name="deface_pet") - pet_wf.connect( - [ - (weighted_average, coreg_pet_to_t1w, [("out_file", "source_file")]), - (coreg_pet_to_t1w, deface_pet, [("out_lta_file", "lta_file")]), - ( - coreg_pet_to_t1w, - datasink, - [("out_lta_file", f"{pet_string.replace('_', '.')}.pet.@{run_id}")], - ), - ( - deface_pet, - datasink, - [ - ( - "out_file", - f"{pet_string.replace('_', '.')}.pet.@defaced{run_id}", - ) - ], - ), - ] - ) + pet_wf.connect( + [ + (weighted_average, coreg_pet_to_t1w, [("out_file", "source_file")]), + (coreg_pet_to_t1w, deface_pet, [("out_lta_file", "lta_file")]), + ( + coreg_pet_to_t1w, + datasink, + [ + ( + "out_lta_file", + f"{pet_string.replace('_', '.')}.pet.@{run_id}", + ) + ], + ), + ( + deface_pet, + datasink, + [ + ( + "out_file", + f"{pet_string.replace('_', '.')}.pet.@defaced{run_id}", + ) + ], + ), + ] + ) - workflow.connect( - [ - ( - t1w_workflows[t1w_file]["workflow"], - pet_wf, - [ - ( - f"deface_t1w_{t1w_workflows[t1w_file]['anat_string']}.out_facemask", - "deface_pet.facemask", - ) - ], - ) - ] - ) + workflow.connect( + [ + ( + t1w_workflows[t1w_file]["workflow"], + pet_wf, + [ + ( + f"deface_t1w_{t1w_workflows[t1w_file]['anat_string']}.out_facemask", + "deface_pet.facemask", + ) + ], + ) + ] + ) return workflow @@ -718,13 +737,12 @@ def __init__( self, bids_dir, output_dir=None, - anat_only=False, # TODO: currently not implemented + anat_only=False, subject="", - session="", # TODO: currently not implemented n_procs=2, skip_bids_validator=True, - remove_existing=True, # TODO: currently not implemented - placement="adjacent", # TODO: currently not implemented + remove_existing=True, + placement="adjacent", preview_pics=True, excludeparticipant=[], ): @@ -734,7 +752,6 @@ def __init__( self.output_dir = output_dir self.anat_only = anat_only self.subject = subject - self.session = session self.n_procs = n_procs self.skip_bids_validator = skip_bids_validator self.preview_pics = preview_pics @@ -747,7 +764,9 @@ def __init__( if not self.fs_license.exists(): raise ValueError("Freesurfer license is not valid") else: - print(f"Using freesurfer license at {self.fs_license} found in system env at $FREESURFER_LICENSE") + print( + f"Using freesurfer license at {self.fs_license} found in system env at $FREESURFER_LICENSE" + ) def run(self): """ @@ -760,7 +779,6 @@ def run(self): "output_dir": self.output_dir, "anat_only": self.anat_only, "subject": self.subject, - "session": self.session, "n_procs": self.n_procs, "skip_bids_validator": self.skip_bids_validator, "participant_label": self.subject, @@ -795,9 +813,9 @@ def cli(): default=None, ) parser.add_argument( - 'analysis_level', - nargs='?', - default='participant', + "analysis_level", + nargs="?", + default="participant", help="This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as " "a participant level analysis", ) @@ -817,14 +835,6 @@ def cli(): required=False, default="", ) - parser.add_argument( - "--session", - "-ses", - help="The label of the session to be processed.", - type=str, - required=False, - default="", - ) parser.add_argument( "--docker", "-d", @@ -1010,7 +1020,11 @@ def main(): # noqa: max-complexity: 12 elif args.singularity: singularity_command = f"singularity exec -e" - if args.output_dir == "None" or args.output_dir is None or args.output_dir == "": + if ( + args.output_dir == "None" + or args.output_dir is None + or args.output_dir == "" + ): args.output_dir = args.bids_dir / "derivatives" / "petdeface" # create output directory if it doesn't exist @@ -1051,7 +1065,9 @@ def main(): # noqa: max-complexity: 12 "Freesurfer license not found, please set FREESURFER_LICENSE environment variable or place license.txt in FREESURFER_HOME" ) - singularity_command += f" --bind {str(license_location)}:/opt/freesurfer/license.txt" + singularity_command += ( + f" --bind {str(license_location)}:/opt/freesurfer/license.txt" + ) singularity_command += f" docker://openneuropet/petdeface:{__version__}" singularity_command += f" petdeface" singularity_command += args_string @@ -1060,14 +1076,12 @@ def main(): # noqa: max-complexity: 12 subprocess.run(singularity_command, shell=True) - else: petdeface = PetDeface( bids_dir=args.bids_dir, output_dir=args.output_dir, anat_only=args.anat_only, subject=args.participant_label, - session=args.session, n_procs=args.n_procs, skip_bids_validator=args.skip_bids_validator, remove_existing=args.remove_existing, diff --git a/pyproject.toml b/pyproject.toml index 119151b..01376b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "petdeface" -version = "0.2.0" +version = "0.2.1" description = "A nipype PET and MR defacing pipeline for BIDS datasets utilizing FreeSurfer's MiDeFace." authors = ["Martin Nørgaard ", "Anthony Galassi <28850131+bendhouseart@users.noreply.github.com>", "Murat Bilgel "] license = "MIT" From 5a4e1a601e7d60dd10958387dae02c47b5453f78 Mon Sep 17 00:00:00 2001 From: Anthony Galassi <28850131+bendhouseart@users.noreply.github.com> Date: Fri, 15 Nov 2024 15:27:37 -0600 Subject: [PATCH 3/5] added session inclusion/exclusion --- README.md | 24 ++++++++++------ docs/usage.rst | 64 +++++++++++++++++++++++------------------- petdeface/petdeface.py | 51 +++++++++++++++++++++++++-------- 3 files changed, 90 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 5596ee3..4174b51 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,10 @@ This software can be installed via source or via pip from PyPi with `pip install **_NOTE:_** This project is currently in beta release, some features listed below may not be available for version numbers < 1.0.0 ```bash -usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--session SESSION] [--docker] [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics] - [--excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...]] +usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--docker] [--singularity] [--n_procs N_PROCS] + [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics] + [--exclude_participant EXCLUDE_PARTICIPANT [EXCLUDE_PARTICIPANT ...]] [--session SESSION [SESSION ...]] + [--exclude_session EXCLUDE_SESSION [EXCLUDE_SESSION ...]] bids_dir [output_dir] [analysis_level] PetDeface @@ -44,28 +46,32 @@ PetDeface positional arguments: bids_dir The directory with the input dataset output_dir The directory where the output files should be stored, if not supplied will default to /derivatives/petdeface - analysis_level This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as a participant level analysis + analysis_level This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as a participant level + analysis options: -h, --help show this help message and exit --anat_only, -a Only deface anatomical images --participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...], -pl PARTICIPANT_LABEL [PARTICIPANT_LABEL ...] The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces. - --session SESSION, -ses SESSION - The label of the session to be processed. --docker, -d Run in docker container --singularity, -si Run in singularity container --n_procs N_PROCS Number of processors to use when running the workflow --skip_bids_validator --version, -v show program's version number and exit --placement PLACEMENT, -p PLACEMENT - Where to place the defaced images. Options are 'adjacent': next to the bids_dir (default) in a folder appended with _defaced'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir'derivatives': does all of the - defacing within the derivatives folder in bids_dir. + Where to place the defaced images. Options are 'adjacent': next to the bids_dir (default) in a folder appended with _defaced'inplace': + defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir'derivatives': does all of the defacing within + the derivatives folder in bids_dir. --remove_existing, -r Remove existing output files in output_dir. --preview_pics Create preview pictures of defacing, defaults to false for docker - --excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...] - Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02 + --exclude_participant EXCLUDE_PARTICIPANT [EXCLUDE_PARTICIPANT ...] + Exclude a subject(s) from the defacing workflow. e.g. --exclude_participant sub-01 sub-02 + --session SESSION [SESSION ...] + Select only a specific session(s) to include in the defacing workflow + --exclude_session EXCLUDE_SESSION [EXCLUDE_SESSION ...] + Select a specific session(s) to exclude from the defacing workflow ``` Working example usage: diff --git a/docs/usage.rst b/docs/usage.rst index ef357f2..84d8f23 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -86,37 +86,43 @@ The number of processors made available to PETdeface can be set by the `--n_proc Additional options can be found in the help menu:: petdeface -h - usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--session SESSION] [--docker] [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics] - [--excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...]] + usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--docker] [--singularity] [--n_procs N_PROCS] + [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics] + [--exclude_participant EXCLUDE_PARTICIPANT [EXCLUDE_PARTICIPANT ...]] [--session SESSION [SESSION ...]] + [--exclude_session EXCLUDE_SESSION [EXCLUDE_SESSION ...]] bids_dir [output_dir] [analysis_level] - PetDeface - - positional arguments: - bids_dir The directory with the input dataset - output_dir The directory where the output files should be stored, if not supplied will default to /derivatives/petdeface - analysis_level This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as a participant level analysis - - options: - -h, --help show this help message and exit - --anat_only, -a Only deface anatomical images - --participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...], -pl PARTICIPANT_LABEL [PARTICIPANT_LABEL ...] - The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces. - --session SESSION, -ses SESSION - The label of the session to be processed. - --docker, -d Run in docker container - --singularity, -si Run in singularity container - --n_procs N_PROCS Number of processors to use when running the workflow - --skip_bids_validator - --version, -v show program's version number and exit - --placement PLACEMENT, -p PLACEMENT - Where to place the defaced images. Options are 'adjacent': next to the bids_dir (default) in a folder appended with _defaced'inplace': defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir'derivatives': does all of the - defacing within the derivatives folder in bids_dir. - --remove_existing, -r - Remove existing output files in output_dir. - --preview_pics Create preview pictures of defacing, defaults to false for docker - --excludeparticipant EXCLUDEPARTICIPANT [EXCLUDEPARTICIPANT ...] - Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02 +PetDeface + +positional arguments: + bids_dir The directory with the input dataset + output_dir The directory where the output files should be stored, if not supplied will default to /derivatives/petdeface + analysis_level This BIDS app always operates at the participant level, if this argument is changed it will be ignored and run as a participant level + analysis + +options: + -h, --help show this help message and exit + --anat_only, -a Only deface anatomical images + --participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...], -pl PARTICIPANT_LABEL [PARTICIPANT_LABEL ...] + The label(s) of the participant/subject to be processed. When specifying multiple subjects separate them with spaces. + --docker, -d Run in docker container + --singularity, -si Run in singularity container + --n_procs N_PROCS Number of processors to use when running the workflow + --skip_bids_validator + --version, -v show program's version number and exit + --placement PLACEMENT, -p PLACEMENT + Where to place the defaced images. Options are 'adjacent': next to the bids_dir (default) in a folder appended with _defaced'inplace': + defaces the dataset in place, e.g. replaces faced PET and T1w images w/ defaced at bids_dir'derivatives': does all of the defacing within + the derivatives folder in bids_dir. + --remove_existing, -r + Remove existing output files in output_dir. + --preview_pics Create preview pictures of defacing, defaults to false for docker + --exclude_participant EXCLUDE_PARTICIPANT [EXCLUDE_PARTICIPANT ...] + Exclude a subject(s) from the defacing workflow. e.g. --exclude_participant sub-01 sub-02 + --session SESSION [SESSION ...] + Select only a specific session(s) to include in the defacing workflow + --exclude_session EXCLUDE_SESSION [EXCLUDE_SESSION ...] + Select a specific session(s) to exclude from the defacing workflow Docker Based ------------ diff --git a/petdeface/petdeface.py b/petdeface/petdeface.py index 29b94f4..6f3bf8a 100755 --- a/petdeface/petdeface.py +++ b/petdeface/petdeface.py @@ -249,15 +249,15 @@ def deface(args: Union[dict, argparse.Namespace]) -> None: ) # check to see if any subjects are excluded from the defacing workflow - if args.excludeparticipant != []: + if args.exclude_participant != []: print( - f"Removing the following subjects {args.excludeparticipant} from the defacing workflow" + f"Removing the following subjects {args.exclude_participant} from the defacing workflow" ) - args.excludeparticipant = [ - subject.replace("sub-", "") for subject in args.excludeparticipant + args.exclude_participant = [ + subject.replace("sub-", "") for subject in args.exclude_participant ] subjects = [ - subject for subject in subjects if subject not in args.excludeparticipant + subject for subject in subjects if subject not in args.exclude_participant ] print(f"Subjects remaining in the defacing workflow: {subjects}") @@ -277,6 +277,8 @@ def deface(args: Union[dict, argparse.Namespace]) -> None: args.bids_dir, preview_pics=args.preview_pics, anat_only=args.anat_only, + session=args.session, + exclude_session=args.exclude_session, ) except FileNotFoundError: single_subject_wf = None @@ -303,6 +305,8 @@ def init_single_subject_wf( output_dir: pathlib.Path = None, preview_pics=False, anat_only=False, + session=[], + exclude_session=[], ) -> Workflow: """ Organize the preprocessing pipeline for a single subject. @@ -317,6 +321,10 @@ def init_single_subject_wf( :type preview_pics: bool, optional :param anat_only: _description_, defaults to False :type anat_only: bool, optional + :param session: _description_, will default to only selecting session(s) supplied to this argument, defaults to [] + :type session: list, optional + :param exclude_session: _description_, will exclude any session(s) supplied to this argument, defaults to [] + :type exclude_session: list, optional :raises FileNotFoundError: _description_ :return: _description_ :rtype: Workflow @@ -333,6 +341,13 @@ def init_single_subject_wf( if subject_data is None: raise FileNotFoundError(f"Could not find data for subject sub-{subject_id}") + # we combine the sessions to include and exclude into a single set of sessions to exclude from + # the set of all sessions + if session: + sessions_to_exclude = list(set(bids_data.get_sessions()) - (set(bids_data.get_sessions()) & set(session)) | set(exclude_session)) + else: + sessions_to_exclude = exclude_session + # check if any t1w images exist for the pet images for pet_image, t1w_image in subject_data.items(): if t1w_image == "": @@ -426,6 +441,10 @@ def init_single_subject_wf( ses_id = "" pet_string = f"sub-{subject_id}" + # skip anything in the exclude list + if ses_id.replace("ses-", "") in sessions_to_exclude: + continue + # collect run info from pet file try: run_id = "_" + re.search("run-[^_|\/]*", str(pet_file)).group(0) @@ -744,7 +763,9 @@ def __init__( remove_existing=True, placement="adjacent", preview_pics=True, - excludeparticipant=[], + exclude_participant=[], + session=[], + exclude_session=[], ): self.bids_dir = bids_dir self.remove_existing = remove_existing @@ -755,7 +776,9 @@ def __init__( self.n_procs = n_procs self.skip_bids_validator = skip_bids_validator self.preview_pics = preview_pics - self.excludeparticipant = excludeparticipant + self.exclude_participant = exclude_participant + self.session = session + self.exclude_session = exclude_session # check if freesurfer license is valid self.fs_license = check_valid_fs_license() @@ -785,7 +808,9 @@ def run(self): "placement": self.placement, "remove_existing": self.remove_existing, "preview_pics": self.preview_pics, - "excludeparticipant": self.excludeparticipant, + "exclude_participant": self.exclude_participant, + "session": self.session, + "exclude_session": self.exclude_session, } ) wrap_up_defacing( @@ -886,13 +911,15 @@ def cli(): default=False, ) parser.add_argument( - "--excludeparticipant", - help="Exclude a subject(s) from the defacing workflow. e.g. --excludeparticipant sub-01 sub-02", + "--exclude_participant", + help="Exclude a subject(s) from the defacing workflow. e.g. --exclude_participant sub-01 sub-02", type=str, nargs="+", required=False, default=[], ) + parser.add_argument("--session", help="Select only a specific session(s) to include in the defacing workflow", type=str, nargs="+", required=False, default=[]) + parser.add_argument("--exclude_session", help="Select a specific session(s) to exclude from the defacing workflow", type=str, nargs="+", required=False, default=[]) arguments = parser.parse_args() return arguments @@ -1087,7 +1114,9 @@ def main(): # noqa: max-complexity: 12 remove_existing=args.remove_existing, placement=args.placement, preview_pics=args.preview_pics, - excludeparticipant=args.excludeparticipant, + exclude_participant=args.exclude_participant, + session=args.session, + exclude_session=args.exclude_session, ) petdeface.run() From 6e0039613ec40ef63211b1572343f3e99a99c76e Mon Sep 17 00:00:00 2001 From: Anthony Galassi <28850131+bendhouseart@users.noreply.github.com> Date: Fri, 15 Nov 2024 15:28:51 -0600 Subject: [PATCH 4/5] format with black --- petdeface/petdeface.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/petdeface/petdeface.py b/petdeface/petdeface.py index 6f3bf8a..cfa77be 100755 --- a/petdeface/petdeface.py +++ b/petdeface/petdeface.py @@ -341,10 +341,14 @@ def init_single_subject_wf( if subject_data is None: raise FileNotFoundError(f"Could not find data for subject sub-{subject_id}") - # we combine the sessions to include and exclude into a single set of sessions to exclude from + # we combine the sessions to include and exclude into a single set of sessions to exclude from # the set of all sessions if session: - sessions_to_exclude = list(set(bids_data.get_sessions()) - (set(bids_data.get_sessions()) & set(session)) | set(exclude_session)) + sessions_to_exclude = list( + set(bids_data.get_sessions()) + - (set(bids_data.get_sessions()) & set(session)) + | set(exclude_session) + ) else: sessions_to_exclude = exclude_session @@ -918,8 +922,22 @@ def cli(): required=False, default=[], ) - parser.add_argument("--session", help="Select only a specific session(s) to include in the defacing workflow", type=str, nargs="+", required=False, default=[]) - parser.add_argument("--exclude_session", help="Select a specific session(s) to exclude from the defacing workflow", type=str, nargs="+", required=False, default=[]) + parser.add_argument( + "--session", + help="Select only a specific session(s) to include in the defacing workflow", + type=str, + nargs="+", + required=False, + default=[], + ) + parser.add_argument( + "--exclude_session", + help="Select a specific session(s) to exclude from the defacing workflow", + type=str, + nargs="+", + required=False, + default=[], + ) arguments = parser.parse_args() return arguments From 83f337caa2af2e0d58902b7d59b0dd1d4cae1710 Mon Sep 17 00:00:00 2001 From: Anthony Galassi <28850131+bendhouseart@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:22:10 -0600 Subject: [PATCH 5/5] refactored args naming --- README.md | 12 +++++----- docs/usage.rst | 12 +++++----- petdeface/petdeface.py | 50 +++++++++++++++++++++--------------------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 4174b51..6ec8498 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ This software can be installed via source or via pip from PyPi with `pip install ```bash usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--docker] [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics] - [--exclude_participant EXCLUDE_PARTICIPANT [EXCLUDE_PARTICIPANT ...]] [--session SESSION [SESSION ...]] - [--exclude_session EXCLUDE_SESSION [EXCLUDE_SESSION ...]] + [--participant_label_exclude participant_label_exclude [participant_label_exclude ...]] [--session_label SESSION [SESSION ...]] + [--session_label_exclude session_label_exclude [session_label_exclude ...]] bids_dir [output_dir] [analysis_level] PetDeface @@ -66,11 +66,11 @@ options: --remove_existing, -r Remove existing output files in output_dir. --preview_pics Create preview pictures of defacing, defaults to false for docker - --exclude_participant EXCLUDE_PARTICIPANT [EXCLUDE_PARTICIPANT ...] - Exclude a subject(s) from the defacing workflow. e.g. --exclude_participant sub-01 sub-02 - --session SESSION [SESSION ...] + --participant_label_exclude participant_label_exclude [participant_label_exclude ...] + Exclude a subject(s) from the defacing workflow. e.g. --participant_label_exclude sub-01 sub-02 + --session_label SESSION [SESSION ...] Select only a specific session(s) to include in the defacing workflow - --exclude_session EXCLUDE_SESSION [EXCLUDE_SESSION ...] + --session_label_exclude session_label_exclude [session_label_exclude ...] Select a specific session(s) to exclude from the defacing workflow ``` diff --git a/docs/usage.rst b/docs/usage.rst index 84d8f23..be09293 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -88,8 +88,8 @@ Additional options can be found in the help menu:: petdeface -h usage: petdeface.py [-h] [--anat_only] [--participant_label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] [--docker] [--singularity] [--n_procs N_PROCS] [--skip_bids_validator] [--version] [--placement PLACEMENT] [--remove_existing] [--preview_pics] - [--exclude_participant EXCLUDE_PARTICIPANT [EXCLUDE_PARTICIPANT ...]] [--session SESSION [SESSION ...]] - [--exclude_session EXCLUDE_SESSION [EXCLUDE_SESSION ...]] + [--participant_label_exclude participant_label_exclude [participant_label_exclude ...]] [--session_label SESSION [SESSION ...]] + [--session_label_exclude session_label_exclude [session_label_exclude ...]] bids_dir [output_dir] [analysis_level] PetDeface @@ -117,11 +117,11 @@ options: --remove_existing, -r Remove existing output files in output_dir. --preview_pics Create preview pictures of defacing, defaults to false for docker - --exclude_participant EXCLUDE_PARTICIPANT [EXCLUDE_PARTICIPANT ...] - Exclude a subject(s) from the defacing workflow. e.g. --exclude_participant sub-01 sub-02 - --session SESSION [SESSION ...] + --participant_label_exclude participant_label_exclude [participant_label_exclude ...] + Exclude a subject(s) from the defacing workflow. e.g. --participant_label_exclude sub-01 sub-02 + --session_label SESSION [SESSION ...] Select only a specific session(s) to include in the defacing workflow - --exclude_session EXCLUDE_SESSION [EXCLUDE_SESSION ...] + --session_label_exclude session_label_exclude [session_label_exclude ...] Select a specific session(s) to exclude from the defacing workflow Docker Based diff --git a/petdeface/petdeface.py b/petdeface/petdeface.py index cfa77be..278c38e 100755 --- a/petdeface/petdeface.py +++ b/petdeface/petdeface.py @@ -249,15 +249,15 @@ def deface(args: Union[dict, argparse.Namespace]) -> None: ) # check to see if any subjects are excluded from the defacing workflow - if args.exclude_participant != []: + if args.participant_label_exclude != []: print( - f"Removing the following subjects {args.exclude_participant} from the defacing workflow" + f"Removing the following subjects {args.participant_label_exclude} from the defacing workflow" ) - args.exclude_participant = [ - subject.replace("sub-", "") for subject in args.exclude_participant + args.participant_label_exclude = [ + subject.replace("sub-", "") for subject in args.participant_label_exclude ] subjects = [ - subject for subject in subjects if subject not in args.exclude_participant + subject for subject in subjects if subject not in args.participant_label_exclude ] print(f"Subjects remaining in the defacing workflow: {subjects}") @@ -277,8 +277,8 @@ def deface(args: Union[dict, argparse.Namespace]) -> None: args.bids_dir, preview_pics=args.preview_pics, anat_only=args.anat_only, - session=args.session, - exclude_session=args.exclude_session, + session=args.session_label, + session_label_exclude=args.session_label_exclude, ) except FileNotFoundError: single_subject_wf = None @@ -306,7 +306,7 @@ def init_single_subject_wf( preview_pics=False, anat_only=False, session=[], - exclude_session=[], + session_label_exclude=[], ) -> Workflow: """ Organize the preprocessing pipeline for a single subject. @@ -323,8 +323,8 @@ def init_single_subject_wf( :type anat_only: bool, optional :param session: _description_, will default to only selecting session(s) supplied to this argument, defaults to [] :type session: list, optional - :param exclude_session: _description_, will exclude any session(s) supplied to this argument, defaults to [] - :type exclude_session: list, optional + :param session_label_exclude: _description_, will exclude any session(s) supplied to this argument, defaults to [] + :type session_label_exclude: list, optional :raises FileNotFoundError: _description_ :return: _description_ :rtype: Workflow @@ -347,10 +347,10 @@ def init_single_subject_wf( sessions_to_exclude = list( set(bids_data.get_sessions()) - (set(bids_data.get_sessions()) & set(session)) - | set(exclude_session) + | set(session_label_exclude) ) else: - sessions_to_exclude = exclude_session + sessions_to_exclude = session_label_exclude # check if any t1w images exist for the pet images for pet_image, t1w_image in subject_data.items(): @@ -767,9 +767,9 @@ def __init__( remove_existing=True, placement="adjacent", preview_pics=True, - exclude_participant=[], + participant_label_exclude=[], session=[], - exclude_session=[], + session_label_exclude=[], ): self.bids_dir = bids_dir self.remove_existing = remove_existing @@ -780,9 +780,9 @@ def __init__( self.n_procs = n_procs self.skip_bids_validator = skip_bids_validator self.preview_pics = preview_pics - self.exclude_participant = exclude_participant + self.participant_label_exclude = participant_label_exclude self.session = session - self.exclude_session = exclude_session + self.session_label_exclude = session_label_exclude # check if freesurfer license is valid self.fs_license = check_valid_fs_license() @@ -812,9 +812,9 @@ def run(self): "placement": self.placement, "remove_existing": self.remove_existing, "preview_pics": self.preview_pics, - "exclude_participant": self.exclude_participant, + "participant_label_exclude": self.participant_label_exclude, "session": self.session, - "exclude_session": self.exclude_session, + "session_label_exclude": self.session_label_exclude, } ) wrap_up_defacing( @@ -915,15 +915,15 @@ def cli(): default=False, ) parser.add_argument( - "--exclude_participant", - help="Exclude a subject(s) from the defacing workflow. e.g. --exclude_participant sub-01 sub-02", + "--participant_label_exclude", + help="Exclude a subject(s) from the defacing workflow. e.g. --participant_label_exclude sub-01 sub-02", type=str, nargs="+", required=False, default=[], ) parser.add_argument( - "--session", + "--session_label", help="Select only a specific session(s) to include in the defacing workflow", type=str, nargs="+", @@ -931,7 +931,7 @@ def cli(): default=[], ) parser.add_argument( - "--exclude_session", + "--session_label_exclude", help="Select a specific session(s) to exclude from the defacing workflow", type=str, nargs="+", @@ -1132,9 +1132,9 @@ def main(): # noqa: max-complexity: 12 remove_existing=args.remove_existing, placement=args.placement, preview_pics=args.preview_pics, - exclude_participant=args.exclude_participant, - session=args.session, - exclude_session=args.exclude_session, + participant_label_exclude=args.participant_label_exclude, + session=args.session_label, + session_label_exclude=args.session_label_exclude, ) petdeface.run()