antibody_utils.regions

Framework and CDR regions of antibody variable domains.

A numbering scheme (IMGT, Kabat, Chothia or Martin) assigns a number to each residue of a variable domain. A region definition (IMGT, Kabat, Chothia, Contact or North) says which positions belong to each complementarity- determining region (CDR) and framework region (FW). The two are independent: any definition can be applied to sequences numbered in any scheme, so long as positions can be translated between schemes.

Each definition is stored as boundaries on IMGT positions, and positions in the other schemes are mapped onto IMGT positions. That mapping is exact except where the schemes place insertions differently around CDR-H1 and CDR-L2, where annotate_regions uses heuristics to reproduce the CDR that the definition gives in its own scheme. get_region looks up a single position without those heuristics, so prefer annotate_regions when the definition and the scheme differ.

Module Attributes

REGION_GROUPS

Named groups of regions, accepted wherever region names are.

Functions

annotate_regions(numbering, chain, *, ...)

Assign each residue of a numbered sequence to its region.

get_region(position, chain, *, scheme, ...)

Find the region that a single numbered position belongs to.

Classes

Definition(*values)

A definition of the CDR and framework regions.

Region(*values)

A framework or CDR region of a heavy or light variable domain.

RegionSelector([regions])

Select positions by region, with optional extra and excluded positions.

class antibody_utils.regions.Definition(*values)[source]

Bases: _CaseInsensitiveStrEnum

A definition of the CDR and framework regions.

The North definition is that of North B, Lehmann A and Dunbrack RL Jr, “A new clustering of antibody CDR loop conformations”, J Mol Biol 406:228–256 (2011).

>>> Definition("North")
<Definition.NORTH: 'north'>
antibody_utils.regions.REGION_GROUPS: dict[str, frozenset[Region]] = {'cdrs': frozenset({Region.CDRH1, Region.CDRH2, Region.CDRH3, Region.CDRL1, Region.CDRL2, Region.CDRL3}), 'framework': frozenset({Region.FWH1, Region.FWH2, Region.FWH3, Region.FWH4, Region.FWL1, Region.FWL2, Region.FWL3, Region.FWL4}), 'fv': frozenset({Region.CDRH1, Region.CDRH2, Region.CDRH3, Region.CDRL1, Region.CDRL2, Region.CDRL3, Region.FWH1, Region.FWH2, Region.FWH3, Region.FWH4, Region.FWL1, Region.FWL2, Region.FWL3, Region.FWL4}), 'hcdrs': frozenset({Region.CDRH1, Region.CDRH2, Region.CDRH3}), 'hframework': frozenset({Region.FWH1, Region.FWH2, Region.FWH3, Region.FWH4}), 'lcdrs': frozenset({Region.CDRL1, Region.CDRL2, Region.CDRL3}), 'lframework': frozenset({Region.FWL1, Region.FWL2, Region.FWL3, Region.FWL4}), 'vh': frozenset({Region.CDRH1, Region.CDRH2, Region.CDRH3, Region.FWH1, Region.FWH2, Region.FWH3, Region.FWH4}), 'vl': frozenset({Region.CDRL1, Region.CDRL2, Region.CDRL3, Region.FWL1, Region.FWL2, Region.FWL3, Region.FWL4})}

Named groups of regions, accepted wherever region names are.

class antibody_utils.regions.Region(*values)[source]

Bases: StrEnum

A framework or CDR region of a heavy or light variable domain.

>>> Region.CDRH3 == "cdrh3"
True
>>> Region.CDRH3.chain, Region.CDRH3.is_cdr
(<Chain.HEAVY: 'H'>, True)
property chain: Chain

The chain that the region belongs to.

property is_cdr: bool

Whether the region is a CDR, rather than a framework region.

class antibody_utils.regions.RegionSelector(regions=(), *, scheme, definition)[source]

Bases: object

Select positions by region, with optional extra and excluded positions.

Parameters:
  • regions (Iterable[Region | str]) – Region names (such as “cdrh3”) or group names (such as “framework”; see REGION_GROUPS) to select.

  • scheme (Scheme | str) – The scheme that positions are numbered in.

  • definition (Definition | str) – The region definition to apply.

Raises:

ValueError – If a region or group name is not recognised.

>>> selector = RegionSelector(["hcdrs"], scheme="imgt", definition="imgt")
>>> selector.accepts("111A", "H")
True
>>> selector.exclude_positions(["111A"], "H")
>>> selector.accepts("111A", "H")
False
accepts(position, chain)[source]

Whether the selection includes a position.

Parameters:
  • position (Position | str) – The position.

  • chain (Chain | str) – The chain that the position is on.

Return type:

bool

Returns:

True if the position is selected and not excluded.

add_positions(positions, chain)[source]

Select individual positions, whatever their region.

Parameters:
Return type:

None

add_regions(regions)[source]

Add regions or groups of regions to the selection.

Parameters:

regions (Iterable[Region | str]) – Region or group names.

Raises:

ValueError – If a region or group name is not recognised.

Return type:

None

exclude_positions(positions, chain)[source]

Exclude individual positions, overriding any other selection.

Parameters:
Return type:

None

antibody_utils.regions.annotate_regions(numbering, chain, *, scheme, definition)[source]

Assign each residue of a numbered sequence to its region.

Unlike get_region, this takes account of the insertions in the whole sequence, so that a definition applied in a different scheme from its own gives the same CDRs as in its own scheme. (The Contact definition cannot be reproduced exactly in Kabat numbering.)

Framework regions are assigned by their order relative to the CDRs: a residue before CDR 1 is in framework 1, one between CDRs 1 and 2 is in framework 2, and so on. The numbering must therefore start at the beginning of the domain, or at least before CDR 1.

Parameters:
  • numbering (Iterable[tuple[Position | str, str]]) – The (position, residue) pairs of the sequence, in sequence order. A residue of “-” marks a gap.

  • chain (Chain | str) – The chain type.

  • scheme (Scheme | str) – The scheme that the sequence is numbered in.

  • definition (Definition | str) – The region definition to apply.

Return type:

list[tuple[Position, str, Region | None]]

Returns:

A (position, residue, region) triple for each residue, where the region is None for residues beyond the numbered variable domain.

A sparse IMGT-numbered heavy chain, with one residue in each region:

>>> numbering = [
...     ("1", "E"),
...     ("27", "G"),
...     ("39", "M"),
...     ("56", "I"),
...     ("66", "Y"),
...     ("111A", "D"),
...     ("118", "W"),
... ]
>>> [
...     str(region)
...     for *_, region in annotate_regions(
...         numbering, "H", scheme="imgt", definition="imgt"
...     )
... ]
['fwh1', 'cdrh1', 'fwh2', 'cdrh2', 'fwh3', 'cdrh3', 'fwh4']
antibody_utils.regions.get_region(position, chain, *, scheme, definition)[source]

Find the region that a single numbered position belongs to.

This ignores the rest of the sequence, so it cannot account for insertions elsewhere in the domain. When the definition was specified in a different scheme from scheme, it can therefore misassign positions near CDR-H1 and CDR-L2; use annotate_regions for whole sequences.

Parameters:
  • position (Position | str) – The position, as a Position or a string such as “100A”.

  • chain (Chain | str) – The chain type.

  • scheme (Scheme | str) – The scheme that the position is numbered in.

  • definition (Definition | str) – The region definition to apply.

Return type:

Region | None

Returns:

The region, or None if the position lies outside the numbered variable domain.

>>> get_region("100A", "H", scheme="chothia", definition="chothia")
<Region.CDRH3: 'cdrh3'>
>>> get_region("27", "L", scheme="imgt", definition="kabat")
<Region.CDRL1: 'cdrl1'>