Working with structures¶
antibody_utils.structure reads structure files with
GEMMI, finds the antibody chains, and maps
the numbered positions of each variable domain to residues of the structure.
Reading a structure¶
There are two ways to number a structure’s antibody chains.
With ANARCII (the numbering extra), every protein chain is numbered,
and the chains that ANARCII recognises are the antibody chains:
>>> from antibody_utils.structure import read_structure
>>> structure = read_structure("12e8.pdb.gz", "imgt")
>>> [(chain.name, chain.chain.name) for chain in structure]
[('L', 'LIGHT'), ('H', 'HEAVY'), ('M', 'LIGHT'), ('P', 'HEAVY')]
The structure itself is not renumbered: its residues keep the numbers in the file, and each antibody chain maps the numbered positions to them. In the PDB’s file for 12E8, the residue at IMGT position H111 is numbered 99:
>>> structure["H"]["111"].seqid.num
99
From the file’s own numbering, if it is already numbered, as SAbDab’s files are in the IMGT scheme. Name the antibody chains and their types, and give the scheme:
>>> from antibody_utils.structure import read_structure
>>> structure = read_structure(
... "pdb_000012e8_H_L_ab.cif.gz", "imgt", chains={"H": "H", "L": "L"}
... )
>>> structure
<AntibodyStructure 12E8 antibody chains: L, H>
The residues whose numbers fall in the scheme’s variable domain (1–128 for IMGT) are taken as the domain. The numbering is trusted as it is: a residue outside the domain that the file numbers within that range, such as the first residue of a constant domain numbered on from the end of a short domain, is read as part of the domain.
Either way, only the first variable domain on each chain is numbered, and
only one model is read (model=0 by default). An already-loaded
gemmi.Structure can be used with from_gemmi instead.
Antibody chains¶
An AntibodyChain holds the numbered domain as a NumberedSequence, so the
sequence tools work on it directly, and gives access to its residues as
gemmi.Residue objects:
>>> heavy = structure["H"]
>>> heavy
<AntibodyChain H heavy, 120 residues numbered in the imgt scheme>
>>> heavy.numbered.sequence[:10]
'EVQLQQSGAE'
>>> heavy["23"].name
'CYS'
>>> for position, residue in list(heavy)[:3]:
... print(position, residue.name)
1 GLU
2 VAL
3 GLN
region_residues groups the residues by region:
>>> regions = heavy.region_residues("imgt")
>>> {str(region): len(residues) for region, residues in regions.items()}
{'fwh1': 25, 'cdrh1': 8, 'fwh2': 17, 'cdrh2': 8, 'fwh3': 38, 'cdrh3': 13, 'fwh4': 11}
The whole GEMMI chain, including any residues outside the variable domain,
ligands and water, is heavy.gemmi_chain, and the whole structure is
structure.structure. Treat them as read-only: adding or removing chains or
residues invalidates the antibody chains’ mapping.
Fvs¶
An Fv pairs a heavy and a light chain from the same structure. Chains are
never paired automatically, so choose the pair yourself, for example from the
structure’s metadata or SAbDab’s summary file:
>>> from antibody_utils.structure import Fv
>>> fv = Fv(structure["H"], structure["L"])
>>> fv.name
'HL'
fv.numbered gives the two numbered domains, to compare with
antibody_utils.sequence.identity and similarity. For the geometry of an
Fv, see VH/VL orientation and RMSD.
Selecting and saving¶
select copies regions and atoms of antibody chains into a new
gemmi.Structure, numbered in their scheme, and leaves the original
unchanged. For example, the backbone of the Fv without CDR-H3:
>>> from antibody_utils.structure import BACKBONE_ATOMS, select
>>> copy = select(fv, exclude=["cdrh3"], definition="imgt", atoms=BACKBONE_ATOMS)
>>> len(copy[0]["H"])
107
>>> copy.write_pdb("12e8_fv_backbone.pdb")
Write mmCIF with GEMMI’s copy.make_mmcif_document().write_file(...).