molframe-query
The MolFrame selection language: a short text query such as
byres (within 5 of resname HEM) and protein that picks atoms out of a
structure. Every example here runs against haemoglobin, PDB 4HHB.
The complete language -- every keyword, column, operator and distance form, named queries, and what each error means -- is in the query language reference.
Run a query
Python
=
= # a Selection
# 172 atoms
# numpy array of atom indices
# (172, 3) float32 array
Compile once when the same query runs many times; the compiled Query can be
combined with &, | and ~:
=
# the same thing
Selections combine like sets: a | b, a & b, a - b.
To see which residues a selection touched, walk the hierarchy:
"""(chain, residue name) for every residue with a selected atom."""
=
=
=
=
=
return
# [('E', 'HEM'), ('G', 'HEM'), ('H', 'HEM'), ('J', 'HEM')]
chain.label is the archive's label chain; mmCIF gives each haem its own,
which is why these are not A to D.
Rust
use ;
select_text(source, &policy) compiles and evaluates in one call. Findings
carry a byte span into the query; render them with the query quoted and
underlined:
let source = "name CA and bogus";
if let Err = compile
In MolGFX
Every MolGFX target is a MolFrame query, used unchanged:
show cartoon, protein, select pocket, byres (within 5 of $heme) and protein.
The language at a glance
| You want | Write |
|---|---|
| Everything / nothing | all, none |
| A kind of molecule | protein, nucleic, water, ligand, polymer, hetero |
| Residues by name | resname HEM, resname HIS HEM |
| A chain | chain A, chain A B |
| Residue numbers | resid 87, resid 1:10, resid 1-10 20 30 |
| Atoms by name | name CA, name N CA C O, name C* |
| Elements | element Fe, element C N |
| A numeric condition | bfactor > 50, occupancy < 1, 50 < bfactor |
| Both / either / not | protein and chain A, water or ligand, not water |
| Near something | within 5 of resname HEM |
| Whole residues | byres (within 5 of resname HEM) |
| A named query | $pocket |
Keywords are case-insensitive (PROTEIN, Resname). Values are case-sensitive
(resname HEM, not hem), except elements, which match in any case.
Everything else -- the full keyword and column tables, ranges, wildcards,
distance forms, byres and same ... as, named queries, errors and warnings,
and keywords that need extra data -- is in the
query language reference.
How it works
Text queries and Rust builder expressions converge on one representation, so how a selection is written never changes what it means.
flowchart LR
Text["Selection language"] --> Parse["Lexer / parser"]
Builder["Typed Rust builder"] --> IR["Shared expression IR"]
Parse --> IR
IR --> Logical["LogicalPlan"]
Logical --> Bind["Bind to Structure + policy"]
Bind --> Physical["PhysicalQuery"]
Physical --> Eval["Evaluator"]
Eval --> Selection["AtomSelection"]
Physical -. spatial predicates .-> Spatial["SpatialResolver"]
Binding resolves structure-local symbols and folds constant branches once, and the physical plan is reused across evaluations over the same topology. The planner reorders conjunctions by estimated cost, and spatial predicates are explicit dependencies that a spatial resolver answers.