Skip to content

Commit

Permalink
[FIX] Fix t1-freesurfer pipeline handler (#1240)
Browse files Browse the repository at this point in the history
* fix bad kwargs passing to pipeline handlers

* use t1-freesurfer for name

* fix handling of ignore_groups

* fix special case for segmentationVolumes

* add unit tests

* trigger CI
  • Loading branch information
NicolasGensollen authored Jul 22, 2024
1 parent db2c6c5 commit 687a824
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 12 deletions.
2 changes: 2 additions & 0 deletions clinica/iotools/utils/data_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ def _add_data_to_merge_file_from_caps(
"dwi-dti": dwi_dti_pipeline,
}
merged_summary_df = pd.DataFrame()
if "group_selection" in kwargs and kwargs["group_selection"] is None:
kwargs.pop("group_selection")
if not pipelines:
for pipeline_name, pipeline_fn in pipeline_options.items():
cprint(f"Extracting from CAPS pipeline output: {pipeline_name}...")
Expand Down
36 changes: 25 additions & 11 deletions clinica/iotools/utils/pipeline_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def _get_atlas_name(atlas_path: Path, pipeline: str) -> str:
"""Helper function for _extract_metrics_from_pipeline."""
if pipeline == "dwi_dti":
splitter = "_dwi_space-"
elif pipeline in ("t1_freesurfer_longitudinal", "t1_freesurfer"):
elif pipeline in ("t1_freesurfer_longitudinal", "t1-freesurfer"):
splitter = "_parcellation-"
elif pipeline in ("t1-volume", "pet-volume"):
splitter = "_space-"
Expand Down Expand Up @@ -46,7 +46,7 @@ def _get_mod_path(ses_path: Path, pipeline: str) -> Optional[Path]:
/ "freesurfer_longitudinal"
/ "regional_measures"
)
if pipeline == "t1_freesurfer":
if pipeline == "t1-freesurfer":
return ses_path / "t1" / "freesurfer_cross_sectional" / "regional_measures"
if pipeline == "t1-volume":
return ses_path / "t1" / "spm" / "dartel"
Expand Down Expand Up @@ -189,15 +189,15 @@ def _extract_metrics_from_pipeline(
except KeyError:
raise KeyError("Fields `participant_id` and `session_id` are required.")

if group_selection is None:
try:
group_selection = [f.name for f in (caps_dir / "groups").iterdir()]
except FileNotFoundError:
return df, None
else:
group_selection = [f"group-{group}" for group in group_selection]
ignore_groups = group_selection == [""]

if not ignore_groups:
if group_selection is None:
try:
group_selection = [f.name for f in (caps_dir / "groups").iterdir()]
except FileNotFoundError:
return df, None
else:
group_selection = [f"group-{group}" for group in group_selection]
subjects_dir = caps_dir / "subjects"
records = []
for participant_id, session_id in df.index.values:
Expand Down Expand Up @@ -227,6 +227,20 @@ def _extract_metrics_from_pipeline(
)
)
for atlas_path in atlas_paths:
if metric == "segmentationVolumes":
from clinica.iotools.converters.adni_to_bids.adni_utils import (
replace_sequence_chars,
)

atlas_df = pd.read_csv(atlas_path, sep="\t")
label_list = [
f"t1-freesurfer_segmentation-volumes_ROI-{replace_sequence_chars(roi_name)}_volume"
for roi_name in atlas_df.label_name.values
]
values = atlas_df["label_value"].to_numpy()
for label, value in zip(label_list, values):
records[-1][label] = value
continue
if not _skip_atlas(
atlas_path, pipeline, pvc_restriction, tracers_selection
):
Expand Down Expand Up @@ -279,7 +293,7 @@ def _extract_metrics_from_pipeline(
t1_freesurfer_pipeline = functools.partial(
_extract_metrics_from_pipeline,
metrics=["thickness", "segmentationVolumes"],
pipeline="t1_freesurfer",
pipeline="t1-freesurfer",
group_selection=[""],
)

Expand Down
139 changes: 138 additions & 1 deletion test/unittests/iotools/utils/test_pipeline_handling.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import operator
from pathlib import Path

import pandas as pd
import pytest
Expand Down Expand Up @@ -46,7 +47,7 @@ def test_get_mod_path_errors(tmp_path):
"pipeline,expected_path",
[
("dwi_dti", ["dwi", "dti_based_processing", "atlas_statistics"]),
("t1_freesurfer", ["t1", "freesurfer_cross_sectional", "regional_measures"]),
("t1-freesurfer", ["t1", "freesurfer_cross_sectional", "regional_measures"]),
("t1-volume", ["t1", "spm", "dartel"]),
("pet-volume", ["pet", "preprocessing"]),
],
Expand Down Expand Up @@ -210,3 +211,139 @@ def test_extract_metrics_from_pipeline(tmp_path):
"group_id",
"regions_number",
}


def test_t1_freesurfer_pipeline_nothing_found(tmp_path):
from pandas.testing import assert_frame_equal

from clinica.iotools.utils.pipeline_handling import t1_freesurfer_pipeline

caps = tmp_path / "caps"
caps.mkdir()
merged_df = pd.DataFrame(
{
"participant_id": ["sub-01"],
"session_id": ["ses-M000"],
"age": [85],
}
)
merged_df.set_index(
["participant_id", "session_id"], inplace=True, verify_integrity=True
)
merged_df_with_t1_freesurfer_metrics, summary = t1_freesurfer_pipeline(
caps, merged_df
)
merged_df_with_t1_freesurfer_metrics.set_index(
["participant_id", "session_id"], inplace=True, verify_integrity=True
)

assert_frame_equal(merged_df_with_t1_freesurfer_metrics, merged_df)
assert summary.empty


def test_t1_freesurfer_longitudinal_pipeline_nothing_found(tmp_path):
from pandas.testing import assert_frame_equal

from clinica.iotools.utils.pipeline_handling import (
t1_freesurfer_longitudinal_pipeline,
)

caps = tmp_path / "caps"
caps.mkdir()
merged_df = pd.DataFrame(
{
"participant_id": ["sub-01"],
"session_id": ["ses-M000"],
"age": [85],
}
)
merged_df.set_index(
["participant_id", "session_id"], inplace=True, verify_integrity=True
)
merged_df_with_t1_freesurfer_metrics, summary = t1_freesurfer_longitudinal_pipeline(
caps, merged_df
)
merged_df_with_t1_freesurfer_metrics.set_index(
["participant_id", "session_id"], inplace=True, verify_integrity=True
)

assert_frame_equal(merged_df_with_t1_freesurfer_metrics, merged_df)
assert summary.empty


def write_fake_statistics(tsv_file: Path):
fake = pd.DataFrame(
{
"label_name": ["foo", "bar", "baz"],
"label_value": [1.2, 2.3, 3.4],
}
)
fake.to_csv(tsv_file, sep="\t")


def test_t1_freesurfer_pipeline(tmp_path):
from clinica.iotools.utils.pipeline_handling import t1_freesurfer_pipeline

caps = tmp_path / "caps"
regional_measures_folder = (
caps
/ "subjects"
/ "sub-01"
/ "ses-M000"
/ "t1"
/ "freesurfer_cross_sectional"
/ "regional_measures"
)
regional_measures_folder.mkdir(parents=True)
for file in (
"sub-01_ses-M000_parcellation-desikan_thickness.tsv",
"sub-01_ses-M000_parcellation-desikan_area.tsv",
"sub-01_ses-M000_parcellation-destrieux_thickness.tsv",
"sub-01_ses-M000_segmentationVolumes.tsv",
):
write_fake_statistics(regional_measures_folder / file)

assert len([f for f in regional_measures_folder.iterdir()]) == 4
merged_df = pd.DataFrame(
{
"participant_id": ["sub-01"],
"session_id": ["ses-M000"],
"age": [85],
}
)
merged_df.set_index(
["participant_id", "session_id"], inplace=True, verify_integrity=True
)
merged_df_with_t1_freesurfer_metrics, summary = t1_freesurfer_pipeline(
caps, merged_df
)
merged_df_with_t1_freesurfer_metrics.set_index(
["participant_id", "session_id"], inplace=True, verify_integrity=True
)

assert len(merged_df_with_t1_freesurfer_metrics) == 1
assert set(merged_df_with_t1_freesurfer_metrics.columns) == {
"age",
"t1-freesurfer_atlas-desikan_ROI-bar_thickness",
"t1-freesurfer_atlas-desikan_ROI-baz_thickness",
"t1-freesurfer_atlas-desikan_ROI-foo_thickness",
"t1-freesurfer_atlas-destrieux_ROI-bar_thickness",
"t1-freesurfer_atlas-destrieux_ROI-baz_thickness",
"t1-freesurfer_atlas-destrieux_ROI-foo_thickness",
"t1-freesurfer_segmentation-volumes_ROI-bar_volume",
"t1-freesurfer_segmentation-volumes_ROI-baz_volume",
"t1-freesurfer_segmentation-volumes_ROI-foo_volume",
}
assert summary.pipeline_name.to_list() == ["t1-freesurfer"] * 3
assert summary.atlas_id.to_list() == ["desikan", "destrieux", "volumes"]
assert summary.regions_number.to_list() == [3, 3, 3]
assert summary.first_column_name.to_list() == [
"t1-freesurfer_atlas-desikan_ROI-foo_thickness",
"t1-freesurfer_atlas-destrieux_ROI-foo_thickness",
"t1-freesurfer_segmentation-volumes_ROI-foo_volume",
]
assert summary.last_column_name.to_list() == [
"t1-freesurfer_atlas-desikan_ROI-baz_thickness",
"t1-freesurfer_atlas-destrieux_ROI-baz_thickness",
"t1-freesurfer_segmentation-volumes_ROI-baz_volume",
]

0 comments on commit 687a824

Please sign in to comment.