Atom arrays and ligand mappings#
This advanced guide starts from a reconstructed ligand system and shows the in-memory coordinate views used for featurization and structural comparison. For file access and linked apo reconstruction, begin with Access system files with PlinderSystem.
import pandas as pd
from rdkit.Chem.Draw import IPythonConsole
from plinder.core import PlinderSystem
IPythonConsole.drawOptions.addAtomIndices = True
system = PlinderSystem(system_id="4agi__1__1.C__1.W")
/home/runner/micromamba/envs/plinder/lib/python3.12/site-packages/vcs_versioning/_backends/_git.py:709: UserWarning: "/home/runner/work/plinder/plinder" is shallow and may cause errors
pre_parse(wd)
Coordinate views#
PlinderSystem exposes the receptor and each assembly ligand as Biotite atom arrays. RDKit molecules retain the curated ligand bonds and bond orders.
pd.Series(
{
"receptor_atoms": len(system.receptor_structure),
"ligand_count": system.num_ligands,
"protein_chain_count": system.num_proteins,
"ligand_atoms": sum(len(atoms) for atoms in system.ligand_structures.values()),
}
)
receptor_atoms 2444
ligand_count 1
protein_chain_count 1
ligand_atoms 12
dtype: int64
ligand_chain = next(iter(system.ligand_mols))
system.ligand_mols[ligand_chain]
Protein masks and sequences#
holo_structure combines the receptor and ligand views and provides common masks and sequence-derived properties.
structure = system.holo_structure
pd.Series(
{
"protein_atoms": len(structure.protein_atom_array),
"backbone_atoms": int(structure.protein_backbone_mask.sum()),
"calpha_atoms": int(structure.protein_calpha_mask.sum()),
"protein_chains": len(structure.protein_chain_ordered),
}
)
protein_atoms 2443
backbone_atoms 942
calpha_atoms 314
protein_chains 1
dtype: int64
calpha = structure.protein_atom_array[structure.protein_calpha_mask]
calpha.coord.shape, structure.protein_sequence
((314, 3),
{'1.C': 'MSTPGAQQVLFRTGIAAVNSTNHLRVYFQDVYGSIRESLYEGSWANGTEKNVIGNAKLGSPVAATSKELKHIRVYTLTEGNTLQEFAYDSGTGWYNGGLGGAKFQVAPYSXIAAVFLAGTDALQLRIYAQKPDNTIQEYMWNGDGWKEGTNLGGALPGTGIGATSFRYTDYNGPSIRIWFQTDDLKLVQRAYDPHKGWYPDLVTIFDRAPPRTAIAATSFGAGNSSIYMRIYFVNSDNTIWQVCWDHGKGYHDKGTITPVIQGSEVAIISWGSFANNGPDLRLYFQNGTYISAVSEWVWNRAHGSQLGRSALPPA'})
protein_sequence is the full deposited polymer sequence. protein_sequence_from_structure is derived from resolved coordinates, so the two can differ when residues are unresolved.
Map canonical ligand atoms to resolved coordinates#
A canonical SDF can contain atoms that were not resolved, and molecular symmetry can permit several valid atom correspondences. PLINDER therefore exposes stacks of valid template-to-resolved atom orders rather than assuming a single positional zip.
template = structure.input_ligand_templates[ligand_chain]
resolved = structure.resolved_ligand_mols[ligand_chain]
template_order, resolved_order = (
structure.ligand_template2resolved_atom_order_stacks[ligand_chain]
)
template
resolved
pd.Series(
{
"valid_mappings": len(template_order),
"mapped_atoms_per_mapping": template_order.shape[1],
"template_atoms": template.GetNumAtoms(),
"resolved_atoms": resolved.GetNumAtoms(),
}
)
valid_mappings 1
mapped_atoms_per_mapping 12
template_atoms 12
resolved_atoms 12
dtype: int64
mapping_index = 0
template_coords = structure.input_ligand_conformers_coords[ligand_chain][
template_order[mapping_index]
]
resolved_coords = structure.resolved_ligand_mols_coords[ligand_chain][
resolved_order[mapping_index]
]
template_coords.shape, resolved_coords.shape
((12, 3), (12, 3))
Evaluate every valid row when a metric should be invariant to ligand automorphisms. The mapped coordinate arrays have the same shape even when the canonical and resolved molecules have different total atom counts.