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]
../_images/5a0d9b5406ddb7dc13e164ee8fe7611386767e833ec72a72756ea5dcbc8250e3.png

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
../_images/5aa9b3fd066eef15777dd8bb72e090bccf1224a324da9a37adb904d90337db37.png
resolved
../_images/5a0d9b5406ddb7dc13e164ee8fe7611386767e833ec72a72756ea5dcbc8250e3.png
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.