diff --git a/.gitignore b/.gitignore index de501e0..e23936e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bids-examples +report.txt # do not track _version.py for hatch bids/ext/reports/_version.py diff --git a/bids/ext/reports/parsing.py b/bids/ext/reports/parsing.py index 780b541..3e37e56 100644 --- a/bids/ext/reports/parsing.py +++ b/bids/ext/reports/parsing.py @@ -71,6 +71,9 @@ def func_info(files: list[BIDSFile], config: dict[str, dict[str, str]], layout: A dictionary with relevant information regarding sequences, sequence variants, phase encoding directions, and task names. + layout : :obj:`bids.layout.BIDSLayout` + Layout object for a BIDS dataset. + Returns ------- desc : :obj:`str` @@ -131,6 +134,9 @@ def anat_info(files: list[BIDSFile], config: dict[str, dict[str, str]], layout: A dictionary with relevant information regarding sequences, sequence variants, phase encoding directions, and task names. + layout : :obj:`bids.layout.BIDSLayout` + Layout object for a BIDS dataset. + Returns ------- desc : :obj:`str` @@ -167,6 +173,9 @@ def dwi_info(files: list[BIDSFile], config: dict[str, dict[str, str]], layout: B A dictionary with relevant information regarding sequences, sequence variants, phase encoding directions, and task names. + layout : :obj:`bids.layout.BIDSLayout` + Layout object for a BIDS dataset. + Returns ------- desc : :obj:`str` @@ -196,14 +205,11 @@ def dwi_info(files: list[BIDSFile], config: dict[str, dict[str, str]], layout: B return templates.dwi_info(desc_data) -def fmap_info(layout: BIDSLayout, files: list[BIDSFile], config: dict[str, dict[str, str]]) -> str: +def fmap_info(files: list[BIDSFile], config: dict[str, dict[str, str]], layout: BIDSLayout) -> str: """Generate a paragraph describing field map acquisition information. Parameters ---------- - layout : :obj:`bids.layout.BIDSLayout` - Layout object for a BIDS dataset. - files : :obj:`list` of :obj:`bids.layout.models.BIDSFile` List of nifti files in layout corresponding to field map scan. @@ -211,6 +217,10 @@ def fmap_info(layout: BIDSLayout, files: list[BIDSFile], config: dict[str, dict[ A dictionary with relevant information regarding sequences, sequence variants, phase encoding directions, and task names. + layout : :obj:`bids.layout.BIDSLayout` + Layout object for a BIDS dataset. + + Returns ------- desc : :obj:`str` @@ -238,6 +248,44 @@ def fmap_info(layout: BIDSLayout, files: list[BIDSFile], config: dict[str, dict[ return templates.fmap_info(desc_data) +def perf_info(files: list[BIDSFile], config: dict[str, dict[str, str]], layout: BIDSLayout) -> str: + first_file = files[0] + metadata = first_file.get_metadata() + img = try_load_nii(first_file.path) + if img is None: + files_not_found_warning(Path(first_file.path).relative_to(layout.root)) + + all_runs = sorted(list({f.get_entities().get("run", 1) for f in files})) + + desc_data = { + **common_mri_desc(img, metadata, config), + "echo_time": parameters.echo_time_ms(files), + "nb_runs": parameters.nb_runs(all_runs), + } + + return templates.perf_info(desc_data) + + +def pet_info(files: list[BIDSFile], layout: BIDSLayout) -> str: + first_file = files[0] + metadata = first_file.get_metadata() + img = try_load_nii(first_file.path) + if img is None: + files_not_found_warning(Path(first_file.path).relative_to(layout.root)) + + all_runs = sorted(list({f.get_entities().get("run", 1) for f in files})) + + desc_data = { + **metadata, + "fov": parameters.field_of_view(img), + "matrix_size": parameters.matrix_size(img), + "voxel_size": parameters.voxel_size(img), + "nb_runs": parameters.nb_runs(all_runs), + } + + return templates.pet_info(desc_data) + + def meg_info(files: list[BIDSFile]) -> str: """Generate a paragraph describing meg acquisition information. @@ -343,10 +391,13 @@ def parse_files( elif group[0].entities["datatype"] == "dwi": group_description = dwi_info(group, config, layout) + elif group[0].entities["datatype"] == "perf": + group_description = perf_info(group, config, layout) + elif (group[0].entities["datatype"] == "fmap") and group[0].entities[ "suffix" ] == "phasediff": - group_description = fmap_info(layout, group, config) + group_description = fmap_info(group, config, layout) description_list.append(group_description) @@ -358,15 +409,21 @@ def parse_files( group_description = "" - if group[0].entities["datatype"] in [ + if group[0].entities["datatype"] == [ "eeg", "meg", - "pet", "ieeg", + ]: + group_description = meg_info(group, config, layout) + + if group[0].entities["datatype"] == "pet": + group_description = pet_info(group, layout) + + if group[0].entities["datatype"] in [ "beh", - "perf", "fnirs", "microscopy", + "motion", ]: LOGGER.warning(f" '{group[0].entities['datatype']}' not yet supported.") diff --git a/bids/ext/reports/templates.py b/bids/ext/reports/templates.py index fd78e01..1673bf4 100644 --- a/bids/ext/reports/templates.py +++ b/bids/ext/reports/templates.py @@ -42,16 +42,16 @@ def footer() -> str: return f"This section was (in part) generated automatically using pybids {__version__}." -def mri_scanner_info(desc_data: dict[str, Any]) -> str: - """Generate mri scanner info report.""" - return render(template_name="mri_scanner_info.mustache", data=desc_data) - - def institution_info(desc_data: dict[str, Any]) -> str: """Generate institution report.""" return render(template_name="institution.mustache", data=desc_data) +def mri_scanner_info(desc_data: dict[str, Any]) -> str: + """Generate mri scanner info report.""" + return render(template_name="mri_scanner_info.mustache", data=desc_data) + + def anat_info(desc_data: dict[str, Any]) -> str: """Generate anatomical report.""" return render(template_name="anat.mustache", data=desc_data) @@ -72,6 +72,11 @@ def fmap_info(desc_data: dict[str, Any]) -> str: return render(template_name="fmap.mustache", data=desc_data) +def perf_info(desc_data: dict[str, Any]) -> str: + """Generate ASL report.""" + return render(template_name="perf.mustache", data=desc_data) + + def pet_info(desc_data: dict[str, Any]) -> str: """Generate PET report.""" return render(template_name="pet.mustache", data=desc_data) diff --git a/bids/ext/reports/tests/test_parsing.py b/bids/ext/reports/tests/test_parsing.py index bff0df0..9ebfab2 100644 --- a/bids/ext/reports/tests/test_parsing.py +++ b/bids/ext/reports/tests/test_parsing.py @@ -62,7 +62,7 @@ def test_fmap_info_smoke(testlayout, testconfig): suffix="phasediff", extension=[".nii.gz"], ) - desc = parsing.fmap_info(testlayout, fmap_files, testconfig) + desc = parsing.fmap_info(fmap_files, testconfig, testlayout) assert isinstance(desc, str) diff --git a/tools/run_on_examples.sh b/tools/run_on_examples.sh index b8c77b2..bf16e52 100644 --- a/tools/run_on_examples.sh +++ b/tools/run_on_examples.sh @@ -1,7 +1,7 @@ #!/bin/bash rc=0; -for pre in asl ds00 eeg meg ieeg; do +for pre in asl ds00 eeg meg ieeg pet; do for i in $(find bids-examples -maxdepth 1 -type d -name "${pre}*"); do if [ "$i" == "bids-examples" ]; then continue