Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Fix t1-freesurfer pipeline handler #1240

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
]
Loading