Quick start¶
This page takes an antibody from sequence to structure: numbering its variable domains, extracting CDRs, comparing sequences, finding sequence liabilities, and reading a structure to measure its VH/VL orientation.
Numbering raw sequences needs ANARCII, from the numbering extra (see
Installation). Everything else works with the core install, given
sequences or structures that are already numbered.
Number a sequence¶
number_sequence numbers one variable-domain sequence, in the IMGT scheme by
default. Here are trastuzumab’s VH and VL:
>>> from antibody_utils.numbering import number_sequence
>>> vh = (
... "EVQLVESGGGLVQPGGSLRLSCAASGFNIKDTYIHWVRQAPGKGLEWVARIYPTNGYTRYADSVKG"
... "RFTISADTSKNTAYLQMNSLRAEDTAVYYCSRWGGDGFYAMDYWGQGTLVTVSS"
... )
>>> vl = (
... "DIQMTQSPSSLSASVGDRVTITCRASQDVNTAVAWYQQKPGKAPKLLIYSASFLYSGVPSRFSGSR"
... "SGTDFTLTISSLQPEDFATYYCQQHYTTPPTFGQGTKVEIK"
... )
>>> heavy = number_sequence(vh)
>>> light = number_sequence(vl)
>>> heavy.chain_type, light.chain_type, len(heavy)
('H', 'K', 120)
>>> heavy.numbering[:3]
[(Position(number=1, insertion=''), 'E'), (Position(number=2, insertion=''), 'V'), (Position(number=3, insertion=''), 'Q')]
The result is a NumberedSequence: the position of each residue, the chain
type (H, or K or L for kappa and lambda light chains) and where the
domain lies in the input. To number many sequences at once, use number, or
iter_number for a stream too large to hold in memory.
Extract the CDRs¶
A numbering scheme gives each residue a position; a region definition says which positions form each CDR. Any definition can be applied to any scheme (see Numbering schemes and region definitions):
>>> from antibody_utils.sequence import cdr_sequences
>>> for cdr, sequence in cdr_sequences(heavy, "imgt").items():
... print(cdr, sequence)
cdrh1 GFNIKDTY
cdrh2 IYPTNGYT
cdrh3 SRWGGDGFYAMDY
>>> for cdr, sequence in cdr_sequences(heavy, "north").items():
... print(cdr, sequence)
cdrh1 AASGFNIKDTYIH
cdrh2 RIYPTNGYTR
cdrh3 SRWGGDGFYAMDY
Find sequence liabilities¶
find_liabilities looks for motifs that may affect developability, such as
deamidation and isomerisation sites, in the regions where they matter:
>>> from antibody_utils.liabilities import find_liabilities
>>> for liability in find_liabilities(heavy, light):
... if "deamidation" in liability.name:
... print(liability.chain, liability.residues, liability.positions)
H NG (Position(number=62, insertion=''), Position(number=63, insertion=''))
L NT (Position(number=36, insertion=''), Position(number=37, insertion=''))
Read a structure¶
read_structure reads a PDB or mmCIF file with
GEMMI, and numbers each protein chain that is
an antibody chain. The PDB entry 12E8 holds two copies of the 2E8 Fab:
>>> from antibody_utils.structure import Fv, read_structure
>>> structure = read_structure("12e8.pdb.gz")
>>> structure
<AntibodyStructure 12e8 antibody chains: L, H, M, P>
>>> [chain.name for chain in structure.heavy_chains]
['H', 'P']
Heavy and light chains are not paired automatically. Pair them yourself, from what you know of the structure:
>>> fv = Fv(structure["H"], structure["L"])
>>> fv
<Fv HL heavy=H light=L>
Compare sequences¶
identity and similarity compare numbered domains position by position, so
they need no alignment. A VH/VL pair is compared with another chain by chain:
>>> from antibody_utils.sequence import identity
>>> round(identity((heavy, light), fv.numbered, definition="imgt"), 3)
0.634
>>> round(identity((heavy, light), fv.numbered, definition="imgt", regions=["cdrs"]), 3)
0.489
Use a numbered structure file¶
Structure files from SAbDab are already numbered in the IMGT scheme. Name the antibody chains, and their numbering is used as it is, without renumbering with ANARCII:
>>> from antibody_utils.structure import Fv, read_structure
>>> sabdab = read_structure("pdb_000012e8_H_L_ab.cif.gz", chains={"H": "H", "L": "L"})
>>> fv = Fv(sabdab["H"], sabdab["L"])
>>> fv.heavy
<AntibodyChain H heavy, 120 residues numbered in the imgt scheme>
Measure the VH/VL orientation¶
abangle measures how the VH and VL domains are oriented relative to each
other (see VH/VL orientation and RMSD):
>>> from antibody_utils.geometry import abangle
>>> {name: round(value, 1) for name, value in abangle(fv).as_dict().items()}
{'HL': -71.0, 'HC1': 69.2, 'LC1': 118.6, 'HC2': 106.5, 'LC2': 74.6, 'dc': 16.0}
Save part of a structure¶
select copies chosen regions of antibody chains into a new GEMMI structure,
numbered in their scheme, ready to write out:
>>> from antibody_utils.structure import select
>>> cdrs = select(fv, ["cdrs"], definition="imgt")
>>> [(chain.name, len(chain)) for chain in cdrs[0]]
[('H', 29), ('L', 18)]
>>> cdrs.write_pdb("12e8_cdrs.pdb")