Skip to content

Vertebra Constants

Defines the shared label space used throughout TPTBox: vertebra IDs, subregion labels, sort orders, and anatomical name mappings.

Location (subregion enum)

TPTBox.core.vert_constants.Location

Bases: Abstract_lvl

IntEnum of vertebra subregion and anatomical landmark labels used as POI subregion IDs.

Values below 100 correspond to anatomical subregions of the vertebra (e.g. corpus, spinosus process, articular processes). Values ≥ 100 are used for computed locations such as intervertebral discs (100), endplates superior (200–), and endplates inferior (300–).

Members are serialised as integers (not names) because :meth:save_as_name returns False.

Source code in TPTBox/core/vert_constants.py
class Location(Abstract_lvl):
    """IntEnum of vertebra subregion and anatomical landmark labels used as POI subregion IDs.

    Values below 100 correspond to anatomical subregions of the vertebra
    (e.g. corpus, spinosus process, articular processes).  Values ≥ 100 are
    used for computed locations such as intervertebral discs (100), endplates
    superior (200–), and endplates inferior (300–).

    Members are serialised as integers (not names) because :meth:`save_as_name`
    returns ``False``.
    """

    @classmethod
    def save_as_name(cls) -> bool:
        """Always returns False; Location values are saved as integers."""
        return False

    Unknown = 0
    # S1 = 26  # SACRUM
    # Vertebral subregions
    Vertebra_Full = 40
    Arcus_Vertebrae = 41
    Spinosus_Process = 42
    Costal_Process_Left = 43
    Costal_Process_Right = 44
    Superior_Articular_Left = 45
    Superior_Articular_Right = 46
    Inferior_Articular_Left = 47
    Inferior_Articular_Right = 48
    Vertebra_Corpus_border = 49  # actual corpus body
    Vertebra_Corpus = 50
    Dens_axis = 51  # only in C2 and CT but not MRI
    Vertebral_Body_Endplate_Superior = 52
    Vertebral_Body_Endplate_Inferior = 53
    # Articulate_Process_Facet_Joint (Used anywhere?)
    # Superior_Articulate_Process_Facet_Joint_Surface_Left = 54
    # Superior_Articulate_Process_Facet_Joint_Surface_Right = 55
    # Inferior_Articulate_Process_Facet_Joint_Surface_Left = 56
    # Inferior_Articulate_Process_Facet_Joint_Surface_Right = 57
    Vertebra_Disc_Superior = 58
    Vertebra_Disc_Inferior = 59
    Vertebra_Disc = 100
    Spinal_Cord = 60
    Spinal_Canal = 61  # Center of vertebra
    Spinal_Canal_ivd_lvl = 126
    Endplate = 62
    Rib_Left = 63
    Rib_Right = 64
    # 66-80 Free
    # Sacrum Subregions
    Sacrum_Sacral_Ala_Left = 70
    Sacrum_Sacral_Ala_Right = 71
    Sacrum_Posterior_Sacral_Elements = 72
    Sacrum_Body = 73
    Sacrum_Endplate = 74
    # Muscle inserts
    # https://www.frontiersin.org/articles/10.3389/fbioe.2022.862804/full
    Metal = 80
    # 81-91
    Muscle_Inserts_Spinosus_Process = 81
    Muscle_Inserts_Transverse_Process_Left = 83
    Muscle_Inserts_Transverse_Process_Right = 82
    Muscle_Inserts_Vertebral_Body_Left = 84
    Muscle_Inserts_Vertebral_Body_Right = 85
    Muscle_Inserts_Articulate_Process_Inferior_Left = 86
    Muscle_Inserts_Articulate_Process_Inferior_Right = 87
    Muscle_Inserts_Articulate_Process_Superior_Left = 88
    Muscle_Inserts_Articulate_Process_Superior_Right = 89
    # Implants (No automatic generation)
    Implant_Entry_Left = 90
    Implant_Entry_Right = 91
    Implant_Target_Left = 92
    Implant_Target_Right = 93

    # Muscle_Inserts_Rib_left = 90
    # Muscle_Inserts_Rib_right = 91
    # Ligament attachment points
    # 101-151
    # 101-108;
    # 101-104 are the 4 corners of a center sagittal cut starting top, than front
    # 105-108; Centers between the 4 corners, same order. Starting between up-front/up-back
    Ligament_Attachment_Point_Anterior_Longitudinal_Superior_Median = 101
    Ligament_Attachment_Point_Posterior_Longitudinal_Superior_Median = 102
    Ligament_Attachment_Point_Anterior_Longitudinal_Inferior_Median = 103
    Ligament_Attachment_Point_Posterior_Longitudinal_Inferior_Median = 104
    Additional_Vertebral_Body_Middle_Superior_Median = 105
    Additional_Vertebral_Body_Posterior_Central_Median = 106
    Additional_Vertebral_Body_Middle_Inferior_Median = 107
    Additional_Vertebral_Body_Anterior_Central_Median = 108
    # 109-116 Same but shifted to the left
    Ligament_Attachment_Point_Anterior_Longitudinal_Superior_Left = 109
    Ligament_Attachment_Point_Posterior_Longitudinal_Superior_Left = 110
    Ligament_Attachment_Point_Anterior_Longitudinal_Inferior_Left = 111
    Ligament_Attachment_Point_Posterior_Longitudinal_Inferior_Left = 112
    Additional_Vertebral_Body_Middle_Superior_Left = 113
    Additional_Vertebral_Body_Posterior_Central_Left = 114
    Additional_Vertebral_Body_Middle_Inferior_Left = 115
    Additional_Vertebral_Body_Anterior_Central_Left = 116
    # 117-124 Same but shifted to the right
    Ligament_Attachment_Point_Anterior_Longitudinal_Superior_Right = 117
    Ligament_Attachment_Point_Posterior_Longitudinal_Superior_Right = 118
    Ligament_Attachment_Point_Anterior_Longitudinal_Inferior_Right = 119
    Ligament_Attachment_Point_Posterior_Longitudinal_Inferior_Right = 120
    Additional_Vertebral_Body_Middle_Superior_Right = 121
    Additional_Vertebral_Body_Posterior_Central_Right = 122
    Additional_Vertebral_Body_Middle_Inferior_Right = 123
    Additional_Vertebral_Body_Anterior_Central_Right = 124

    Ligament_Attachment_Point_Flava_Superior_Median = 125
    Ligament_Attachment_Point_Flava_Inferior_Median = 127
    # Vertebra orientation (compute Vertebra_Direction - Vertebra_Corpus)
    Vertebra_Direction_Posterior = 128
    Vertebra_Direction_Inferior = 129
    Vertebra_Direction_Right = 130

    # Ligament_Attachment_Point_Flava_Superior_Right = 141
    # Ligament_Attachment_Point_Flava_Inferior_Right = 143
    # Ligament_Attachment_Point_Flava_Superior_Left = 149
    # Ligament_Attachment_Point_Flava_Inferior_Left = 151

    # Ligament_Attachment_Point_Interspinosa_Superior_Left = 133
    # Ligament_Attachment_Point_Interspinosa_Superior_Right = 134
    # Ligament_Attachment_Point_Interspinosa_Inferior_Left = 135
    # Ligament_Attachment_Point_Interspinosa_Inferior_Right = 136

    # Multi = 256

    def __repr__(self):
        return self.name

save_as_name classmethod

save_as_name() -> bool

Always returns False; Location values are saved as integers.

Source code in TPTBox/core/vert_constants.py
@classmethod
def save_as_name(cls) -> bool:
    """Always returns False; Location values are saved as integers."""
    return False

Vertebra_Instance

TPTBox.core.vert_constants.Vertebra_Instance

Bases: Abstract_lvl

Enum of individual vertebra instances with associated rib, IVD, and endplate labels.

Each member represents one vertebra identified by its integer label (see module docstring for the full numbering scheme). Associated structure labels are computed from fixed offsets and exposed as properties:

  • :attr:VERTEBRA — the raw vertebra label value.
  • :attr:RIB — rib label (only for T1–T12 and C6–C7).
  • :attr:IVD — intervertebral disc label (label + 100).
  • :attr:ENDPLATE — endplate label (label + 200).

Class methods :meth:cervical, :meth:thoracic, :meth:lumbar, and :meth:sacrum return tuples of members for each spinal region. :meth:order provides the full cranio-caudal sequence.

Source code in TPTBox/core/vert_constants.py
class Vertebra_Instance(Abstract_lvl):
    """Enum of individual vertebra instances with associated rib, IVD, and endplate labels.

    Each member represents one vertebra identified by its integer label (see module
    docstring for the full numbering scheme).  Associated structure labels are
    computed from fixed offsets and exposed as properties:

    - :attr:`VERTEBRA` — the raw vertebra label value.
    - :attr:`RIB`      — rib label (only for T1–T12 and C6–C7).
    - :attr:`IVD`      — intervertebral disc label (label + 100).
    - :attr:`ENDPLATE` — endplate label (label + 200).

    Class methods :meth:`cervical`, :meth:`thoracic`, :meth:`lumbar`, and
    :meth:`sacrum` return tuples of members for each spinal region.
    :meth:`order` provides the full cranio-caudal sequence.
    """

    def __new__(cls, *args):
        """Create a new Vertebra_Instance enum member, storing the vertebra label as its value."""
        obj = object.__new__(cls)
        obj._value_ = args[0]
        return obj

    def __init__(
        self,
        vertebra_label: int,
        has_rib: bool = False,
        has_ivd: bool = True,
    ):
        self._rib = None
        self._ivd = None
        self._endplate = None
        self.has_rib = has_rib
        if has_rib:
            self._rib = (
                vertebra_label + VERTEBRA_INSTANCE_RIB_LABEL_OFFSET if vertebra_label != 28 else 21 + VERTEBRA_INSTANCE_RIB_LABEL_OFFSET
            )
            # 40 - 8 + 21 = 53 = rib for T13
            # 52 rib for L1
        if has_ivd:
            self._ivd = vertebra_label + VERTEBRA_INSTANCE_IVD_LABEL_OFFSET
            self._endplate = vertebra_label + VERTEBRA_INSTANCE_ENDPLATE_LABEL_OFFSET

    @classmethod
    def vertebra_label_without_sacrum(cls) -> list[int]:
        """Return the list of vertebra label integers excluding sacrum/coccyx (C1–L6 + T13)."""
        # TODO add sacrum label and similar flags into init (also C, T, L)
        l = list(range(1, 26))
        l.append(28)
        return l

    @classmethod
    def rib_label(cls) -> list[int]:
        """Return all rib label integers for vertebrae that have ribs."""
        return [i._rib for i in Vertebra_Instance if i._rib is not None]

    @classmethod
    def endplate_label(cls) -> list[int]:
        """Return all endplate label integers for vertebrae that have endplates."""
        return [i._endplate for i in Vertebra_Instance if i._endplate is not None]

    # TODO maybe easier to have a nested enum where the inner enum stands for vertebra, rib, ivd, ... makes naming independent of hard-coded attribute names
    @classmethod
    def name2idx(cls) -> dict[str, int]:
        """Return a cached mapping from vertebra/structure name to integer label.

        Names include plain vertebra names (e.g. ``"L1"``) as well as derived names
        for ribs, IVDs, and endplates (e.g. ``"L1_rib"``, ``"L1_ivd"``).
        """
        global _vname2idx  # noqa: PLW0603
        if _vname2idx is not None:
            return _vname2idx
        name2idx = {}
        for instance in Vertebra_Instance:
            name2idx[instance.name] = instance.value
            for structure in ["rib", "ivd", "endplate"]:
                attrname = f"_{structure}"
                assert hasattr(instance, attrname)
                attr = getattr(instance, attrname)
                if attr is not None:
                    name2idx[instance.name + attrname] = attr
        _vname2idx = name2idx
        return name2idx

    @classmethod
    def idx2name(cls) -> dict[int, str]:
        """Return a cached mapping from integer label to vertebra/structure name."""
        global _vidx2name  # noqa: PLW0603
        if _vidx2name is not None:
            return _vidx2name
        _vidx2name = {value: key for key, value in Vertebra_Instance.name2idx().items()}
        return _vidx2name

    @classmethod
    def is_sacrum(cls, i: int) -> bool:
        """Return True if integer label ``i`` corresponds to a sacral or coccyx vertebra."""
        try:
            return cls(i) in cls.sacrum()
        except KeyError:
            return False
        except ValueError:
            return False

    @classmethod
    def cervical(cls) -> tuple[Vertebra_Instance, ...]:
        """Return a tuple of all cervical vertebra members (C1–C7)."""
        return (cls.C1, cls.C2, cls.C3, cls.C4, cls.C5, cls.C6, cls.C7)

    @classmethod
    def thoracic(cls) -> tuple[Vertebra_Instance, ...]:
        """Return a tuple of all thoracic vertebra members (T1–T13)."""
        return (
            cls.T1,
            cls.T2,
            cls.T3,
            cls.T4,
            cls.T5,
            cls.T6,
            cls.T7,
            cls.T8,
            cls.T9,
            cls.T10,
            cls.T11,
            cls.T12,
            cls.T13,
        )

    @classmethod
    def lumbar(cls) -> tuple[Vertebra_Instance, ...]:
        """Return a tuple of all lumbar vertebra members (L1–L6)."""
        return (cls.L1, cls.L2, cls.L3, cls.L4, cls.L5, cls.L6)

    @classmethod
    def sacrum(cls) -> tuple[Vertebra_Instance, ...]:
        """Return a tuple of sacral and coccyx members (S1–S6, COCC)."""
        return (cls.S1, cls.S2, cls.S3, cls.S4, cls.S5, cls.S6, cls.COCC)

    @classmethod
    def order(cls) -> tuple[Vertebra_Instance, ...]:
        """Return all vertebra members in cranio-caudal anatomical order (C1 → COCC)."""
        return cls.cervical() + cls.thoracic() + cls.lumbar() + cls.sacrum()

    @classmethod
    def order_dict(cls) -> dict[int, int]:
        """Return a mapping from vertebra label value to its position in :meth:`order`."""
        return {a.value: e for e, a in enumerate(cls.order())}

    def get_next_poi(self, poi: POI | NII | list[int]) -> Vertebra_Instance | None:
        """Return the next vertebra (caudally) that is present in ``poi``.

        Args:
            poi: A POI container, NII segmentation, or list of label integers.
                The method checks which vertebra labels are present.

        Returns:
            The next :class:`Vertebra_Instance` below ``self`` that is present
            in ``poi``, or ``None`` if no such vertebra exists.
        """
        r = poi if isinstance(poi, list) else poi.keys_region() if hasattr(poi, "keys_region") else poi.unique()  # type: ignore
        o = self.order()
        idx = o.index(self)
        for vert in o[idx + 1 :]:
            if vert.value in r:
                return vert
        return None

    def get_previous_poi(self, poi: POI | NII | list[int]) -> Vertebra_Instance | None:
        """Return the previous vertebra (cranially) that is present in ``poi``.

        Args:
            poi: A POI container, NII segmentation, or list of label integers.
                The method checks which vertebra labels are present.

        Returns:
            The nearest :class:`Vertebra_Instance` above ``self`` that is present
            in ``poi``, or ``None`` if no such vertebra exists.
        """
        r = poi if isinstance(poi, list) else poi.keys_region() if hasattr(poi, "keys_region") else poi.unique()  # type: ignore
        o = self.order()
        idx = o.index(self)
        for vert in reversed(o[:idx]):
            if vert.value in r:
                return vert
        return None

    C1 = 1
    C2 = 2
    C3 = 3
    C4 = 4
    C5 = 5
    C6 = 6, True, True
    C7 = 7, True, True
    T1 = 8, True, True
    T2 = 9, True, True
    T3 = 10, True, True
    T4 = 11, True, True
    T5 = 12, True, True
    T6 = 13, True, True
    T7 = 14, True, True
    T8 = 15, True, True
    T9 = 16, True, True
    T10 = 17, True, True
    T11 = 18, True, True
    T12 = 19, True, True
    T13 = 28, True, True
    L1 = 20, True, True
    L2 = 21
    L3 = 22
    L4 = 23
    L5 = 24
    L6 = 25
    S1 = 26
    COCC = 27
    S2 = 29
    S3 = 30
    S4 = 31
    S5 = 32
    S6 = 33

    @property
    def VERTEBRA(self) -> int:
        """Integer label of this vertebra (same as ``self.value``)."""
        return self.value

    @property
    def RIB(self) -> int:
        """Integer label of the rib associated with this vertebra.

        Raises:
            AssertionError: If this vertebra has no associated rib.
        """
        assert self._rib is not None, (self.name, self.value)
        return self._rib

    @classmethod
    def rib2vert(cls, riblabel: int) -> int:
        """Convert a rib label integer back to its parent vertebra label integer.

        Args:
            riblabel (int): A valid rib label from :meth:`rib_label`.

        Returns:
            int: The vertebra label corresponding to ``riblabel``.

        Raises:
            AssertionError: If ``riblabel`` is not a known rib label.
        """
        assert riblabel in Vertebra_Instance.rib_label(), riblabel
        return riblabel - VERTEBRA_INSTANCE_RIB_LABEL_OFFSET if riblabel != 21 + VERTEBRA_INSTANCE_RIB_LABEL_OFFSET else 28

    @property
    def IVD(self) -> int:
        """Integer label of the intervertebral disc at this level (vertebra label + 100).

        Raises:
            AssertionError: If this vertebra has no associated IVD.
        """
        assert self._ivd is not None, (self.name, self.value)
        return self._ivd

    @property
    def ENDPLATE(self) -> int:
        """Integer label of the endplate at this level (vertebra label + 200).

        Raises:
            AssertionError: If this vertebra has no associated endplate.
        """
        assert self._endplate is not None, (self.name, self.value)
        return self._endplate

    def __str__(self):
        return str(self.name)

VERTEBRA property

VERTEBRA: int

Integer label of this vertebra (same as self.value).

RIB property

RIB: int

Integer label of the rib associated with this vertebra.

Raises:

Type Description
AssertionError

If this vertebra has no associated rib.

IVD property

IVD: int

Integer label of the intervertebral disc at this level (vertebra label + 100).

Raises:

Type Description
AssertionError

If this vertebra has no associated IVD.

ENDPLATE property

ENDPLATE: int

Integer label of the endplate at this level (vertebra label + 200).

Raises:

Type Description
AssertionError

If this vertebra has no associated endplate.

__new__

__new__(*args)

Create a new Vertebra_Instance enum member, storing the vertebra label as its value.

Source code in TPTBox/core/vert_constants.py
def __new__(cls, *args):
    """Create a new Vertebra_Instance enum member, storing the vertebra label as its value."""
    obj = object.__new__(cls)
    obj._value_ = args[0]
    return obj

vertebra_label_without_sacrum classmethod

vertebra_label_without_sacrum() -> list[int]

Return the list of vertebra label integers excluding sacrum/coccyx (C1–L6 + T13).

Source code in TPTBox/core/vert_constants.py
@classmethod
def vertebra_label_without_sacrum(cls) -> list[int]:
    """Return the list of vertebra label integers excluding sacrum/coccyx (C1–L6 + T13)."""
    # TODO add sacrum label and similar flags into init (also C, T, L)
    l = list(range(1, 26))
    l.append(28)
    return l

rib_label classmethod

rib_label() -> list[int]

Return all rib label integers for vertebrae that have ribs.

Source code in TPTBox/core/vert_constants.py
@classmethod
def rib_label(cls) -> list[int]:
    """Return all rib label integers for vertebrae that have ribs."""
    return [i._rib for i in Vertebra_Instance if i._rib is not None]

endplate_label classmethod

endplate_label() -> list[int]

Return all endplate label integers for vertebrae that have endplates.

Source code in TPTBox/core/vert_constants.py
@classmethod
def endplate_label(cls) -> list[int]:
    """Return all endplate label integers for vertebrae that have endplates."""
    return [i._endplate for i in Vertebra_Instance if i._endplate is not None]

name2idx classmethod

name2idx() -> dict[str, int]

Return a cached mapping from vertebra/structure name to integer label.

Names include plain vertebra names (e.g. "L1") as well as derived names for ribs, IVDs, and endplates (e.g. "L1_rib", "L1_ivd").

Source code in TPTBox/core/vert_constants.py
@classmethod
def name2idx(cls) -> dict[str, int]:
    """Return a cached mapping from vertebra/structure name to integer label.

    Names include plain vertebra names (e.g. ``"L1"``) as well as derived names
    for ribs, IVDs, and endplates (e.g. ``"L1_rib"``, ``"L1_ivd"``).
    """
    global _vname2idx  # noqa: PLW0603
    if _vname2idx is not None:
        return _vname2idx
    name2idx = {}
    for instance in Vertebra_Instance:
        name2idx[instance.name] = instance.value
        for structure in ["rib", "ivd", "endplate"]:
            attrname = f"_{structure}"
            assert hasattr(instance, attrname)
            attr = getattr(instance, attrname)
            if attr is not None:
                name2idx[instance.name + attrname] = attr
    _vname2idx = name2idx
    return name2idx

idx2name classmethod

idx2name() -> dict[int, str]

Return a cached mapping from integer label to vertebra/structure name.

Source code in TPTBox/core/vert_constants.py
@classmethod
def idx2name(cls) -> dict[int, str]:
    """Return a cached mapping from integer label to vertebra/structure name."""
    global _vidx2name  # noqa: PLW0603
    if _vidx2name is not None:
        return _vidx2name
    _vidx2name = {value: key for key, value in Vertebra_Instance.name2idx().items()}
    return _vidx2name

is_sacrum classmethod

is_sacrum(i: int) -> bool

Return True if integer label i corresponds to a sacral or coccyx vertebra.

Source code in TPTBox/core/vert_constants.py
@classmethod
def is_sacrum(cls, i: int) -> bool:
    """Return True if integer label ``i`` corresponds to a sacral or coccyx vertebra."""
    try:
        return cls(i) in cls.sacrum()
    except KeyError:
        return False
    except ValueError:
        return False

cervical classmethod

cervical() -> tuple[Vertebra_Instance, ...]

Return a tuple of all cervical vertebra members (C1–C7).

Source code in TPTBox/core/vert_constants.py
@classmethod
def cervical(cls) -> tuple[Vertebra_Instance, ...]:
    """Return a tuple of all cervical vertebra members (C1–C7)."""
    return (cls.C1, cls.C2, cls.C3, cls.C4, cls.C5, cls.C6, cls.C7)

thoracic classmethod

thoracic() -> tuple[Vertebra_Instance, ...]

Return a tuple of all thoracic vertebra members (T1–T13).

Source code in TPTBox/core/vert_constants.py
@classmethod
def thoracic(cls) -> tuple[Vertebra_Instance, ...]:
    """Return a tuple of all thoracic vertebra members (T1–T13)."""
    return (
        cls.T1,
        cls.T2,
        cls.T3,
        cls.T4,
        cls.T5,
        cls.T6,
        cls.T7,
        cls.T8,
        cls.T9,
        cls.T10,
        cls.T11,
        cls.T12,
        cls.T13,
    )

lumbar classmethod

lumbar() -> tuple[Vertebra_Instance, ...]

Return a tuple of all lumbar vertebra members (L1–L6).

Source code in TPTBox/core/vert_constants.py
@classmethod
def lumbar(cls) -> tuple[Vertebra_Instance, ...]:
    """Return a tuple of all lumbar vertebra members (L1–L6)."""
    return (cls.L1, cls.L2, cls.L3, cls.L4, cls.L5, cls.L6)

sacrum classmethod

sacrum() -> tuple[Vertebra_Instance, ...]

Return a tuple of sacral and coccyx members (S1–S6, COCC).

Source code in TPTBox/core/vert_constants.py
@classmethod
def sacrum(cls) -> tuple[Vertebra_Instance, ...]:
    """Return a tuple of sacral and coccyx members (S1–S6, COCC)."""
    return (cls.S1, cls.S2, cls.S3, cls.S4, cls.S5, cls.S6, cls.COCC)

order classmethod

order() -> tuple[Vertebra_Instance, ...]

Return all vertebra members in cranio-caudal anatomical order (C1 → COCC).

Source code in TPTBox/core/vert_constants.py
@classmethod
def order(cls) -> tuple[Vertebra_Instance, ...]:
    """Return all vertebra members in cranio-caudal anatomical order (C1 → COCC)."""
    return cls.cervical() + cls.thoracic() + cls.lumbar() + cls.sacrum()

order_dict classmethod

order_dict() -> dict[int, int]

Return a mapping from vertebra label value to its position in :meth:order.

Source code in TPTBox/core/vert_constants.py
@classmethod
def order_dict(cls) -> dict[int, int]:
    """Return a mapping from vertebra label value to its position in :meth:`order`."""
    return {a.value: e for e, a in enumerate(cls.order())}

get_next_poi

get_next_poi(poi: POI | NII | list[int]) -> Vertebra_Instance | None

Return the next vertebra (caudally) that is present in poi.

Parameters:

Name Type Description Default
poi POI | NII | list[int]

A POI container, NII segmentation, or list of label integers. The method checks which vertebra labels are present.

required

Returns:

Type Description
Vertebra_Instance | None

The next :class:Vertebra_Instance below self that is present

Vertebra_Instance | None

in poi, or None if no such vertebra exists.

Source code in TPTBox/core/vert_constants.py
def get_next_poi(self, poi: POI | NII | list[int]) -> Vertebra_Instance | None:
    """Return the next vertebra (caudally) that is present in ``poi``.

    Args:
        poi: A POI container, NII segmentation, or list of label integers.
            The method checks which vertebra labels are present.

    Returns:
        The next :class:`Vertebra_Instance` below ``self`` that is present
        in ``poi``, or ``None`` if no such vertebra exists.
    """
    r = poi if isinstance(poi, list) else poi.keys_region() if hasattr(poi, "keys_region") else poi.unique()  # type: ignore
    o = self.order()
    idx = o.index(self)
    for vert in o[idx + 1 :]:
        if vert.value in r:
            return vert
    return None

get_previous_poi

get_previous_poi(poi: POI | NII | list[int]) -> Vertebra_Instance | None

Return the previous vertebra (cranially) that is present in poi.

Parameters:

Name Type Description Default
poi POI | NII | list[int]

A POI container, NII segmentation, or list of label integers. The method checks which vertebra labels are present.

required

Returns:

Type Description
Vertebra_Instance | None

The nearest :class:Vertebra_Instance above self that is present

Vertebra_Instance | None

in poi, or None if no such vertebra exists.

Source code in TPTBox/core/vert_constants.py
def get_previous_poi(self, poi: POI | NII | list[int]) -> Vertebra_Instance | None:
    """Return the previous vertebra (cranially) that is present in ``poi``.

    Args:
        poi: A POI container, NII segmentation, or list of label integers.
            The method checks which vertebra labels are present.

    Returns:
        The nearest :class:`Vertebra_Instance` above ``self`` that is present
        in ``poi``, or ``None`` if no such vertebra exists.
    """
    r = poi if isinstance(poi, list) else poi.keys_region() if hasattr(poi, "keys_region") else poi.unique()  # type: ignore
    o = self.order()
    idx = o.index(self)
    for vert in reversed(o[:idx]):
        if vert.value in r:
            return vert
    return None

rib2vert classmethod

rib2vert(riblabel: int) -> int

Convert a rib label integer back to its parent vertebra label integer.

Parameters:

Name Type Description Default
riblabel int

A valid rib label from :meth:rib_label.

required

Returns:

Name Type Description
int int

The vertebra label corresponding to riblabel.

Raises:

Type Description
AssertionError

If riblabel is not a known rib label.

Source code in TPTBox/core/vert_constants.py
@classmethod
def rib2vert(cls, riblabel: int) -> int:
    """Convert a rib label integer back to its parent vertebra label integer.

    Args:
        riblabel (int): A valid rib label from :meth:`rib_label`.

    Returns:
        int: The vertebra label corresponding to ``riblabel``.

    Raises:
        AssertionError: If ``riblabel`` is not a known rib label.
    """
    assert riblabel in Vertebra_Instance.rib_label(), riblabel
    return riblabel - VERTEBRA_INSTANCE_RIB_LABEL_OFFSET if riblabel != 21 + VERTEBRA_INSTANCE_RIB_LABEL_OFFSET else 28

Utility functions

TPTBox.core.vert_constants

Vertebra constants, enumerations, and label-mapping utilities for TPTBox.

Vertebra numbering convention

Integer label IDs follow the TPTBox spine segmentation scheme:

  • Cervical (C1–C7): labels 1–7
  • Thoracic (T1–T12): labels 8–19; T13 is label 28
  • Lumbar (L1–L6): labels 20–25
  • Sacrum (S1): label 26; S2–S6: labels 29–33; Coccyx: label 27

Associated structures use fixed offsets from the vertebra label:

  • Rib: label + 32 (VERTEBRA_INSTANCE_RIB_LABEL_OFFSET = 40 - 8)
  • IVD: label + 100 (VERTEBRA_INSTANCE_IVD_LABEL_OFFSET)
  • Endplate: label + 200 (VERTEBRA_INSTANCE_ENDPLATE_LABEL_OFFSET)

Key exports

  • :class:Vertebra_Instance — IntEnum of all vertebra instances with rib/IVD helpers.
  • :class:Location — IntEnum of vertebra subregion labels (POI types).
  • :data:v_name2idxdict[str, int] mapping name (e.g. "L1") → label.
  • :data:v_idx2namedict[int, str] mapping label → name.
  • :data:v_idx_order — List of label IDs in anatomical cranio-caudal order.

v_name2idx module-attribute

v_name2idx: dict[str, int] = {value: key for key, value in (items())}

v_idx2name module-attribute

v_idx2name = {1: 'C1', 2: 'C2', 3: 'C3', 4: 'C4', 5: 'C5', 6: 'C6', 7: 'C7', 8: 'T1', 9: 'T2', 10: 'T3', 11: 'T4', 12: 'T5', 13: 'T6', 14: 'T7', 15: 'T8', 16: 'T9', 17: 'T10', 18: 'T11', 19: 'T12', 28: 'T13', 20: 'L1', 21: 'L2', 22: 'L3', 23: 'L4', 24: 'L5', 25: 'L6', 26: 'S1', 29: 'S2', 30: 'S3', 31: 'S4', 32: 'S5', 33: 'S6', 27: 'Cocc', None: subreg_idx2name}

v_idx_order module-attribute

v_idx_order = list(keys())

Abbreviations: - SSL: Supraspinous Ligament - ALL: Anterior Longitudinal Ligament - PLL: Posterior Longitudinal Ligament - FL: Flavum Ligament - ISL: Interspinous Ligament - ITL: Intertransverse Ligament

  • CR: Cranial / Superior
  • CA: Caudal / Inferior

  • S: Sinistra / Left

  • D: Dextra / Right

ZOOMS module-attribute

ZOOMS = Union[tuple[float, float, float], Sequence[float]]

AX_CODES module-attribute

AX_CODES = tuple[DIRECTIONS, DIRECTIONS, DIRECTIONS]