Annotation¶
pandora.annotations computes derived structural summaries — nothing
here is source-backed like Metadata; every function
recomputes its result from Structure.atoms/entities each call. See
Functions for full
signatures.
All examples below use 1a3n (deoxyhemoglobin: 2 alpha + 2 beta
chains, 4 heme groups) so that the contact-based annotations have
something to find.
from pandora.parsing import mmcif_to_structure
from pandora.canonicalisation import canonicalise_structure
from pandora.schemas.canonicalisation import (
canonicalisationPolicy,
AltlocRules,
EntityRules,
LigandRules,
)
policy = canonicalisationPolicy(
policy_id="p",
policy_name="p",
policy_version="1.0.0",
altloc_rules=AltlocRules(strategy="select_best_occupancy"),
entity_rules=EntityRules(strategy="merge_equivalent_entities"),
ligand_rules=LigandRules(strategy="filter", keep_waters=False),
)
structure, _, _ = mmcif_to_structure("datasets/dev/mmcif/1a3n.cif")
canonical, _, _ = canonicalise_structure(structure, policy)
Per-entry counts¶
annotate_structure_counts() summarizes atom/residue/chain/entity/
assembly counts and a few breakdowns — a cheap sanity check to run on
every structure in a batch.
Chain-chain interfaces¶
annotate_chain_interfaces() finds every polymer chain pair with at least one pair of selected atoms within distance_cutoff angstroms. For each pair it reports the contacting residues on each side and the residue pairs themselves (residue_pairs).
| Argument | Default | Meaning |
|---|---|---|
distance_cutoff |
4.0 |
Contact distance in angstroms |
atom_set |
"heavy" |
Which atoms count; see below |
polymer_types |
None |
Keep only chains of these entity polymer types, e.g. ["polypeptide(L)"]. None keeps every polymer chain; [] keeps none |
atom_set |
Atoms | Used by |
|---|---|---|
all |
Every atom, hydrogens included | — |
heavy |
Every atom except H and D | ATOM3D (heavy-atom option), PRODIGY |
backbone |
Protein N, CA, C, O; nucleic-acid O5′, C5′, C4′, C3′, O3′ | Pinder's 10 Å pair gate |
ca |
CA atoms only | ATOM3D's 8 Å Cα default |
Changed after 0.5.6: hydrogens no longer count
Up to 0.5.6 every atom counted, including hydrogens, so structures that model H atoms got extra contacts. The default is now atom_set="heavy". Layers record atom_set in parameters, so reproduce_dataset() rebuilds them exactly. Layers from older manifests record only distance_cutoff and are rebuilt with heavy; pass atom_set="all" yourself to match the old output.
from pandora.annotations import annotate_chain_interfaces
interfaces = annotate_chain_interfaces(canonical, distance_cutoff=4.0)
print(len(interfaces.data["interfaces"]), "interfaces")
# 5 interfaces
for interface in interfaces.data["interfaces"][:2]:
print(
interface["chain_id_1"],
interface["chain_id_2"],
interface["contact_count"],
)
# A B 35
# A C 6
Pair gate, then interface (Pinder-style)¶
Pinder first keeps chain pairs with backbone atoms within 10 Å, then defines the interface with a tighter cutoff. That's two calls:
gate = annotate_chain_interfaces(
canonical, distance_cutoff=10.0, atom_set="backbone"
)
interfaces = annotate_chain_interfaces(canonical, distance_cutoff=4.0)
gated = {(i["chain_id_1"], i["chain_id_2"]) for i in gate.data["interfaces"]}
kept = [
i
for i in interfaces.data["interfaces"]
if (i["chain_id_1"], i["chain_id_2"]) in gated
]
Ligand contacts¶
annotate_ligand_contacts() finds polymer residues near each
non-polymer ligand (set include_waters=True to treat waters as
ligands too).
Pairwise sequence identity¶
annotate_pairwise_sequence_identity() compares every polymer entity
in one structure against every polymer entity in another with a
simple ungapped, position-wise comparison (no alignment step — see
examples/dataset_pipeline.py for where this genuinely fools itself
on a shifted reading frame), and reports the best-scoring pair.
from pandora.annotations import annotate_pairwise_sequence_identity
s2, _, _ = mmcif_to_structure("datasets/dev/mmcif/104m.cif")
c2, _, _ = canonicalise_structure(s2, policy)
identity = annotate_pairwise_sequence_identity(canonical, c2)
print(identity.data["best_identity"])
# 0.168 — 1a3n (hemoglobin) and 104m (myoglobin) are only distantly related
--pairwise computes this layer for every pair in the batch,
alongside whichever --layers you pick:
pandora annotate --input-dir deduped/ --layers structure_counts --pairwise --output-dir annotations/
# annotated 5 entries -> annotations/
Each pair's result is attached to both entries' entries in
annotations/annotations.json.
For a real alignment-based identity between sequences (not entities
within structures) at dataset scale, see
compute_sequence_similarity().