Skip to content

data

lacuna.data

Bundled reference data for lesion decoding toolkit.

This module provides access to lightweight reference atlases bundled with the package, enabling zero-configuration usage for common analyses.

All bundled atlases use BIDS-compliant naming: - Template: tpl-{template}_res-{resolution} - Atlas: atlas-{name}_desc-{description} - Suffix: _dseg (discrete segmentation) or _probseg (probabilistic)

Available atlases: - Schaefer 2018 cortical parcellation (100, 200, 400, 1000 parcels) - Tian subcortical atlas (3 scales)

Examples:

>>> from lacuna.data import get_bundled_atlas_dir, list_bundled_atlases
>>>
>>> # List all bundled atlases
>>> atlases = list_bundled_atlases()
>>> print(atlases[:2])
['tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-1000Parcels7Networks_dseg', ...]
>>>
>>> # Get the bundled atlas directory
>>> atlas_dir = get_bundled_atlas_dir()
>>>
>>> # Use bundled atlases in analysis (default behavior)
>>> from lacuna.analysis import RegionalDamage
>>> analysis = RegionalDamage()  # Automatically uses bundled atlases!
>>>
>>> # Get specific atlas files
>>> schaefer = 'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-100Parcels7Networks_dseg'
>>> img_path, labels_path = get_bundled_atlas(schaefer)

get_atlas_citation(name)

Get the citation information for a bundled atlas.

Parameters:

Name Type Description Default
name str

Atlas base name (without extension)

required

Returns:

Type Description
str

Citation text for the atlas

Examples:

>>> from lacuna.data import get_atlas_citation
>>> schaefer = 'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-100Parcels7Networks_dseg'
>>> citation = get_atlas_citation(schaefer)
>>> print(citation[:20])
'Schaefer 2018 Atlas'
Source code in src/lacuna/data/__init__.py
def get_atlas_citation(name: str) -> str:
    """
    Get the citation information for a bundled atlas.

    Parameters
    ----------
    name : str
        Atlas base name (without extension)

    Returns
    -------
    str
        Citation text for the atlas

    Examples
    --------
    >>> from lacuna.data import get_atlas_citation
    >>> schaefer = 'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-100Parcels7Networks_dseg'
    >>> citation = get_atlas_citation(schaefer)
    >>> print(citation[:20])
    'Schaefer 2018 Atlas'
    """
    # Citation database - keys match actual bundled atlas names
    citations = {
        "tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-100Parcels7Networks_dseg": "Schaefer et al, 2018. https://doi.org/10.1093/cercor/bhx179",
        "tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-200Parcels7Networks_dseg": "Schaefer et al, 2018. https://doi.org/10.1093/cercor/bhx179",
        "tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-400Parcels7Networks_dseg": "Schaefer et al, 2018. https://doi.org/10.1093/cercor/bhx179",
        "tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-1000Parcels7Networks_dseg": "Schaefer et al, 2018. https://doi.org/10.1093/cercor/bhx179",
        "tpl-MNI152NLin6Asym_res-01_atlas-TianSubcortex_desc-3TS1_dseg": "Tian et al, 2020. https://doi.org/10.1038/s41593-020-00711-6",
        "tpl-MNI152NLin6Asym_res-01_atlas-TianSubcortex_desc-3TS2_dseg": "Tian et al, 2020. https://doi.org/10.1038/s41593-020-00711-6",
        "tpl-MNI152NLin6Asym_res-01_atlas-TianSubcortex_desc-3TS3_dseg": "Tian et al, 2020. https://doi.org/10.1038/s41593-020-00711-6",
    }

    if name not in citations:
        available = list(citations.keys())
        return f"No citation available for '{name}'. Available: {', '.join(available)}"

    return citations[name]

get_bundled_atlas(name)

Get paths to a specific bundled atlas image and labels file.

Parameters:

Name Type Description Default
name str

Atlas base name (without extension)

required

Returns:

Type Description
tuple of Path

(image_path, labels_path) for the requested atlas

Raises:

Type Description
ValueError

If the requested atlas is not found in bundled data

Examples:

>>> from lacuna.data import get_bundled_atlas
>>> schaefer = 'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-100Parcels7Networks_dseg'
>>> img, labels = get_bundled_atlas(schaefer)
>>> print(img.name)
'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-100Parcels7Networks_dseg.nii.gz'
>>>
>>> # Check files exist
>>> print(img.exists(), labels.exists())
True True
Source code in src/lacuna/data/__init__.py
def get_bundled_atlas(name: str) -> tuple[Path, Path]:
    """
    Get paths to a specific bundled atlas image and labels file.

    Parameters
    ----------
    name : str
        Atlas base name (without extension)

    Returns
    -------
    tuple of Path
        (image_path, labels_path) for the requested atlas

    Raises
    ------
    ValueError
        If the requested atlas is not found in bundled data

    Examples
    --------
    >>> from lacuna.data import get_bundled_atlas
    >>> schaefer = 'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-100Parcels7Networks_dseg'
    >>> img, labels = get_bundled_atlas(schaefer)
    >>> print(img.name)
    'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-100Parcels7Networks_dseg.nii.gz'
    >>>
    >>> # Check files exist
    >>> print(img.exists(), labels.exists())
    True True
    """
    atlas_dir = get_bundled_atlas_dir()

    # Try to find image file
    img_path = atlas_dir / f"{name}.nii.gz"
    if not img_path.exists():
        available = list_bundled_atlases()
        raise ValueError(
            f"Bundled atlas '{name}' not found. Available atlases: {', '.join(available)}"
        )

    # Try to find labels file (try _labels.txt first, then .txt)
    labels_candidates = [
        atlas_dir / f"{name}_labels.txt",
        atlas_dir / f"{name}.txt",
    ]

    labels_path = None
    for candidate in labels_candidates:
        if candidate.exists():
            labels_path = candidate
            break

    if labels_path is None:
        raise ValueError(
            f"Labels file not found for atlas '{name}'. "
            f"Expected {labels_candidates[0]} or {labels_candidates[1]}"
        )

    return img_path, labels_path

get_bundled_atlas_dir()

Get the directory containing bundled reference atlases.

Returns:

Type Description
Path

Absolute path to bundled atlases directory

Examples:

>>> from lacuna.data import get_bundled_atlas_dir
>>> atlas_dir = get_bundled_atlas_dir()
>>> print(atlas_dir)
PosixPath('/home/user/env/lib/python3.10/site-packages/lacuna/data/atlases')
Source code in src/lacuna/data/__init__.py
def get_bundled_atlas_dir() -> Path:
    """
    Get the directory containing bundled reference atlases.

    Returns
    -------
    Path
        Absolute path to bundled atlases directory

    Examples
    --------
    >>> from lacuna.data import get_bundled_atlas_dir
    >>> atlas_dir = get_bundled_atlas_dir()
    >>> print(atlas_dir)
    PosixPath('/home/user/env/lib/python3.10/site-packages/lacuna/data/atlases')
    """
    return Path(__file__).parent / "atlases"

get_subject_mask_path(subject_id, session_id='ses-01')

Get the path to a subject's lesion mask.

Parameters:

Name Type Description Default
subject_id str

Subject identifier (e.g., "sub-01").

required
session_id str

Session identifier. Default: "ses-01".

'ses-01'

Returns:

Type Description
Path

Path to the lesion mask NIfTI file.

Raises:

Type Description
FileNotFoundError

If the mask file does not exist.

Examples:

>>> from lacuna.data.tutorials import get_subject_mask_path
>>> mask_path = get_subject_mask_path("sub-01")
>>> print(mask_path.name)
sub-01_ses-01_space-MNI152NLin6Asym_label-acuteinfarct_mask.nii.gz
Source code in src/lacuna/data/tutorials/__init__.py
def get_subject_mask_path(
    subject_id: str,
    session_id: str = "ses-01",
) -> Path:
    """Get the path to a subject's lesion mask.

    Parameters
    ----------
    subject_id : str
        Subject identifier (e.g., "sub-01").
    session_id : str, optional
        Session identifier. Default: "ses-01".

    Returns
    -------
    Path
        Path to the lesion mask NIfTI file.

    Raises
    ------
    FileNotFoundError
        If the mask file does not exist.

    Examples
    --------
    >>> from lacuna.data.tutorials import get_subject_mask_path
    >>> mask_path = get_subject_mask_path("sub-01")
    >>> print(mask_path.name)
    sub-01_ses-01_space-MNI152NLin6Asym_label-acuteinfarct_mask.nii.gz
    """
    bids_dir = get_tutorial_bids_dir()

    # Build expected path
    anat_dir = bids_dir / subject_id / session_id / "anat"

    if not anat_dir.exists():
        raise FileNotFoundError(
            f"Anatomical directory not found for {subject_id}/{session_id}: {anat_dir}"
        )

    # Find mask file (flexible on exact naming)
    masks = list(anat_dir.glob("*_mask.nii.gz"))
    if not masks:
        raise FileNotFoundError(
            f"No mask file found in {anat_dir}. " f"Expected pattern: *_mask.nii.gz"
        )

    # Return first match (typically only one per session)
    return masks[0]

get_tutorial_bids_dir()

Get the path to the bundled synthetic BIDS dataset.

Returns the path to the tutorial BIDS directory bundled with Lacuna. This directory contains synthetic lesion masks that can be used for learning and testing.

Returns:

Type Description
Path

Path to the synthetic BIDS dataset directory.

Examples:

>>> from lacuna.data.tutorials import get_tutorial_bids_dir
>>> bids_dir = get_tutorial_bids_dir()
>>> list(bids_dir.glob("sub-*"))
[PosixPath('.../sub-01'), PosixPath('.../sub-02'), PosixPath('.../sub-03')]
Notes

The bundled dataset includes: - 3 synthetic subjects (sub-01, sub-02, sub-03) - Binary lesion masks in MNI152NLin6 space (1mm resolution) - BIDS-compliant structure with dataset_description.json and participants.tsv

Source code in src/lacuna/data/tutorials/__init__.py
def get_tutorial_bids_dir() -> Path:
    """Get the path to the bundled synthetic BIDS dataset.

    Returns the path to the tutorial BIDS directory bundled with Lacuna.
    This directory contains synthetic lesion masks that can be used for
    learning and testing.

    Returns
    -------
    Path
        Path to the synthetic BIDS dataset directory.

    Examples
    --------
    >>> from lacuna.data.tutorials import get_tutorial_bids_dir
    >>> bids_dir = get_tutorial_bids_dir()
    >>> list(bids_dir.glob("sub-*"))
    [PosixPath('.../sub-01'), PosixPath('.../sub-02'), PosixPath('.../sub-03')]

    Notes
    -----
    The bundled dataset includes:
    - 3 synthetic subjects (sub-01, sub-02, sub-03)
    - Binary lesion masks in MNI152NLin6 space (1mm resolution)
    - BIDS-compliant structure with dataset_description.json and participants.tsv
    """
    data_dir = _get_data_dir()
    if not data_dir.exists():
        raise FileNotFoundError(
            f"Tutorial data directory not found: {data_dir}. "
            "This may indicate a corrupted installation."
        )
    return data_dir

get_tutorial_subjects()

Get a list of subject IDs in the tutorial dataset.

Returns:

Type Description
list[str]

Subject IDs (e.g., ["sub-01", "sub-02", "sub-03"]).

Examples:

>>> from lacuna.data.tutorials import get_tutorial_subjects
>>> subjects = get_tutorial_subjects()
>>> print(subjects)
['sub-01', 'sub-02', 'sub-03']
Source code in src/lacuna/data/tutorials/__init__.py
def get_tutorial_subjects() -> list[str]:
    """Get a list of subject IDs in the tutorial dataset.

    Returns
    -------
    list[str]
        Subject IDs (e.g., ["sub-01", "sub-02", "sub-03"]).

    Examples
    --------
    >>> from lacuna.data.tutorials import get_tutorial_subjects
    >>> subjects = get_tutorial_subjects()
    >>> print(subjects)
    ['sub-01', 'sub-02', 'sub-03']
    """
    bids_dir = get_tutorial_bids_dir()
    subjects = sorted(
        d.name for d in bids_dir.iterdir() if d.is_dir() and d.name.startswith("sub-")
    )
    return subjects

list_bundled_atlases()

List all bundled atlas names (base names without extensions).

Returns:

Type Description
list of str

Sorted list of atlas base names

Examples:

>>> from lacuna.data import list_bundled_atlases
>>> atlases = list_bundled_atlases()
>>> print(atlases[0])  # First Schaefer atlas
'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-1000Parcels7Networks_dseg'
>>> print(len(atlases))  # Schaefer (4) + Tian (3)
7
Source code in src/lacuna/data/__init__.py
def list_bundled_atlases() -> list[str]:
    """
    List all bundled atlas names (base names without extensions).

    Returns
    -------
    list of str
        Sorted list of atlas base names

    Examples
    --------
    >>> from lacuna.data import list_bundled_atlases
    >>> atlases = list_bundled_atlases()
    >>> print(atlases[0])  # First Schaefer atlas
    'tpl-MNI152NLin6Asym_res-01_atlas-Schaefer2018_desc-1000Parcels7Networks_dseg'
    >>> print(len(atlases))  # Schaefer (4) + Tian (3)
    7
    """
    atlas_dir = get_bundled_atlas_dir()

    # Find all .nii.gz files
    nifti_files = list(atlas_dir.glob("*.nii.gz"))

    # Extract base names (remove .nii.gz)
    parcel_names = []
    for f in nifti_files:
        base_name = f.name.replace(".nii.gz", "")
        parcel_names.append(base_name)

    return sorted(parcel_names)

setup_tutorial_data(target_dir, *, overwrite=False)

Copy tutorial data to a working directory.

Creates a copy of the synthetic BIDS dataset in the specified location. Useful for tutorials where users want to modify or experiment with the data.

Parameters:

Name Type Description Default
target_dir str or PathLike

Directory where tutorial data will be copied.

required
overwrite bool

If True, overwrite existing directory. Default: False.

False

Returns:

Type Description
Path

Path to the copied tutorial data directory.

Raises:

Type Description
FileExistsError

If target_dir exists and overwrite is False.

Examples:

>>> from lacuna.data.tutorials import setup_tutorial_data
>>> tutorial_dir = setup_tutorial_data("~/my_tutorial")
>>> print(tutorial_dir)
/home/user/my_tutorial
>>> # The directory now contains the BIDS dataset
>>> list(tutorial_dir.glob("sub-*"))
[PosixPath('/home/user/my_tutorial/sub-01'), ...]
Notes

The copied dataset is identical to the bundled data and includes: - dataset_description.json - participants.tsv - sub-01/ses-01/anat/sub-01_ses-01_space-MNI152NLin6Asym_label-acuteinfarct_mask.nii.gz - sub-02/ses-01/anat/sub-02_ses-01_space-MNI152NLin6Asym_label-acuteinfarct_mask.nii.gz - sub-03/ses-01/anat/sub-03_ses-01_space-MNI152NLin6Asym_label-acuteinfarct_mask.nii.gz

Source code in src/lacuna/data/tutorials/__init__.py
def setup_tutorial_data(
    target_dir: str | PathLike[str],
    *,
    overwrite: bool = False,
) -> Path:
    """Copy tutorial data to a working directory.

    Creates a copy of the synthetic BIDS dataset in the specified location.
    Useful for tutorials where users want to modify or experiment with the data.

    Parameters
    ----------
    target_dir : str or PathLike
        Directory where tutorial data will be copied.
    overwrite : bool, optional
        If True, overwrite existing directory. Default: False.

    Returns
    -------
    Path
        Path to the copied tutorial data directory.

    Raises
    ------
    FileExistsError
        If target_dir exists and overwrite is False.

    Examples
    --------
    >>> from lacuna.data.tutorials import setup_tutorial_data
    >>> tutorial_dir = setup_tutorial_data("~/my_tutorial")
    >>> print(tutorial_dir)
    /home/user/my_tutorial

    >>> # The directory now contains the BIDS dataset
    >>> list(tutorial_dir.glob("sub-*"))
    [PosixPath('/home/user/my_tutorial/sub-01'), ...]

    Notes
    -----
    The copied dataset is identical to the bundled data and includes:
    - dataset_description.json
    - participants.tsv
    - sub-01/ses-01/anat/sub-01_ses-01_space-MNI152NLin6Asym_label-acuteinfarct_mask.nii.gz
    - sub-02/ses-01/anat/sub-02_ses-01_space-MNI152NLin6Asym_label-acuteinfarct_mask.nii.gz
    - sub-03/ses-01/anat/sub-03_ses-01_space-MNI152NLin6Asym_label-acuteinfarct_mask.nii.gz
    """
    target = Path(target_dir).expanduser().resolve()

    if target.exists():
        if not overwrite:
            raise FileExistsError(
                f"Target directory already exists: {target}. " "Use overwrite=True to replace it."
            )
        shutil.rmtree(target)

    source = get_tutorial_bids_dir()
    shutil.copytree(source, target)

    return target