con un clic
coot-essential-api
// API documentation to be loaded at startup - when starting a Coot session, immediately call get_function_descriptions() with the functions listed in this skill.
// API documentation to be loaded at startup - when starting a Coot session, immediately call get_function_descriptions() with the functions listed in this skill.
Best Practices for using Coot MCP
Using Density-Fit Correlations in Coot
Best Practices for Model-Building Tools and Refinement
Best practices for protein structure refinement and validation in Coot. Use when performing (1) Residue refinement operations, (2) Model building and fitting, (3) Rotamer fixing, (4) Scripted/automated refinement workflows, (5) Validation and correlation checking.
Comprehensive structure validation combining model-to-map analysis and unmodeled density detection
Best practices for creating publication-quality molecular graphics figures in Coot using user-defined colors, ribbons, and molecular representations
| name | coot-essential-api |
| description | API documentation to be loaded at startup - when starting a Coot session, immediately call get_function_descriptions() with the functions listed in this skill. |
This document contains the core Coot API functions needed for typical validation and model-building workflows. Reading these function signatures at session start eliminates the need for searching.
coot.set_refinement_immediate_replacement(1)
# CRITICAL: Call this before any refinement operations to make them synchronous
# Without this, refinement results may not be available immediately
coot.set_imol_refinement_map(imol_map)
# CRITICAL: Call this to tell Coot which map to use for refinement.
# Must be called once per session (or whenever the map changes).
# Without this, refine_residues_py() will fail silently.
# Example: coot.set_imol_refinement_map(1)
coot.is_valid_model_molecule(imol) -> int # Returns 1 if valid model, 0 otherwise
coot.is_valid_map_molecule(imol) -> int # Returns 1 if valid map, 0 otherwise
coot.molecule_name(imol) -> str # Returns the molecule filename/description
coot.n_chains(imol) -> int # Returns number of chains
coot.coot_version() -> str # Returns Coot version string
coot.load_tutorial_model_and_data() # Loads tutorial RNase structure + maps
# Download structures and data from PDBe
coot.network_get_accession_code_entity(pdb_accession_code, mode)
# Downloads model and/or structure factors from PDBe
# Parameters:
# pdb_accession_code: str - PDB accession code (e.g., "4wa9")
# mode: int - 0 for coordinates (.pdb or .cif), 1 for structure factors (.mtz)
# Example - fetch both model and data:
# coot.network_get_accession_code_entity("4wa9", 0) # Get coordinates
# coot.network_get_accession_code_entity("4wa9", 1) # Get structure factors to make a map
When experimenting with the various model building tools available to address a particular model-building problem it is useful to create backup checkpoints. This allows you to return to a particular state, so that you can try alternative model-building parameters or functions, or combinations of functions.
coot.make_backup_checkpoint(imol, description_string) -> int
# Creates a named checkpoint of the molecule's current state
# Returns: checkpoint index for later restoration
#
# Parameters:
# imol: Model molecule index
# description_string: Human-readable description (e.g., "before rotamer fix")
#
# CRITICAL: Always checkpoint before experimental or risky operations
#
# Example:
checkpoint_idx = coot.make_backup_checkpoint(0, "before rotamer fix")
coot.auto_fit_best_rotamer(0, "A", 42, "", "", 1, 1, 0.01)
# ... check if improvement worked ...
if not improved:
coot.restore_to_backup_checkpoint(0, checkpoint_idx)
coot.restore_to_backup_checkpoint(imol, checkpoint_index)
# Restores molecule to a previously saved checkpoint state
# Parameters:
# imol: Model molecule index
# checkpoint_index: Index returned by make_backup_checkpoint()
coot.compare_current_model_to_backup(imol, checkpoint_index) -> dict
# Compares current model state to a checkpoint to see what changed
# Parameters:
# imol: Model molecule index
# checkpoint_index: Index of checkpoint to compare against
# Requires: import coot_utils
coot_utils.chain_ids(imol) -> list # Returns list of chain IDs, e.g., ['A', 'B']
# Direct C++ functions (preferred when possible)
coot.chain_id_py(imol, chain_index) -> str # Get chain ID by index
coot.get_header_secondary_structure_info(imol) -> dict
# Returns secondary structure from PDB header
# Returns: {'helices': [...], 'strands': [...]}
#
# Each helix dict contains:
# serNum, helixID, initChainID, initSeqNum, endChainID, endSeqNum, length, comment
#
# Each strand dict contains:
# SheetID, strandNo, initChainID, initSeqNum, endChainID, endSeqNum
#
# Example - get beta barrel strands:
ss = coot.get_header_secondary_structure_info(0)
if 'strands' in ss:
for strand in ss['strands']:
print(f"Strand {strand['strandNo']}: {strand['initSeqNum']}-{strand['endSeqNum']}")
coot.set_go_to_atom_chain_residue_atom_name(chain_id, resno, atom_name) -> int
# Centers view on specified atom. Returns 1 on success.
# Example: coot.set_go_to_atom_chain_residue_atom_name("A", 42, "CA")
coot.closest_atom_simple_py() -> list
# Returns: [imol, chain_id, resno, ins_code, atom_name, alt_conf]
# Gets the atom closest to screen center across all displayed molecules
coot.closest_atom_py(imol) -> list
# Same as above but for specific molecule
coot.active_atom_spec_py() -> list
# Returns the currently "active" atom specification (or False if none found)
# (found, (imol, atom_spec))
# found: Boolean indicating if an atom exists close to the center
# molecule_number: Integer molecule ID
# atom_spec: List [chain_id, resno, ins_code, atom_name, alt_conf]
coot.residue_info_py(imol, chain_id, resno, ins_code) -> list
# Returns detailed atom information for a residue
#
# Parameters:
# imol: Model molecule index
# chain_id: Chain identifier (e.g., "A")
# resno: Residue number
# ins_code: Insertion code (use "" if none)
#
# Returns: List of atom entries, each containing:
# [[atom_name, alt_conf], [occupancy, b_factor, element, ?], [x, y, z], atom_index]
#
# Example output for a complete CYS:
# [[' N ', ''], [1.0, 12.5, ' N', ''], [x, y, z], 100],
# [[' CA ', ''], [1.0, 11.2, ' C', ''], [x, y, z], 101],
# [[' CB ', ''], [1.0, 14.3, ' C', ''], [x, y, z], 102],
# [[' SG ', ''], [1.0, 18.1, ' S', ''], [x, y, z], 103], # Sulfur!
# [[' C ', ''], [1.0, 10.8, ' C', ''], [x, y, z], 104],
# [[' O ', ''], [1.0, 11.0, ' O', ''], [x, y, z], 105]
#
# NOTE: b_factor may be a list [b_iso, B11, B22, B33, B12, B13, B23] for anisotropic
# Always handle safely:
# def get_b(atom): b = atom[1][1]; return b[0] if isinstance(b, list) else b
# Check for missing atoms in a residue
atoms = coot.residue_info_py(0, "A", 72, "")
atom_names = [a[0][0].strip() for a in atoms]
print(f"Atoms present: {atom_names}")
# Expected atoms for common residues
expected_atoms = {
'CYS': ['N', 'CA', 'CB', 'SG', 'C', 'O'],
'ILE': ['N', 'CA', 'CB', 'CG1', 'CG2', 'CD1', 'C', 'O'],
'GLY': ['N', 'CA', 'C', 'O'],
'PHE': ['N', 'CA', 'CB', 'CG', 'CD1', 'CD2', 'CE1', 'CE2', 'CZ', 'C', 'O'],
}
# Find missing atoms
res_type = coot.residue_name_py(0, "A", 72, "")
if res_type in expected_atoms:
missing = [a for a in expected_atoms[res_type] if a not in atom_names]
if missing:
print(f"WARNING: Missing atoms in {res_type}: {missing}")
coot.map_to_model_correlation_stats_per_residue_range_py(
imol, # Model molecule number
chain_id, # Chain identifier (e.g., "A")
imol_map, # Map molecule number
n_per_range, # Residues per window (use 1 for per-residue)
exclude_NOC # 0=include all atoms, 1=exclude backbone N,O,C
) -> list
# Returns: [[all_atom_stats], [sidechain_stats]]
# Each stats list: [[residue_spec, [n_points, correlation]], ...]
# residue_spec = [chain_id, resno, ins_code]
# Example - find worst fitting residues:
stats = coot.map_to_model_correlation_stats_per_residue_range_py(0, "A", 1, 1, 0)
all_atom = stats[0]
worst = sorted(all_atom, key=lambda x: x[1][1])[:5] # 5 worst by correlatio
# Mainchain vs sidechain correlation for a single residue:
coot.map_to_model_correlation_py(imol, residue_specs, neighb_specs, atom_mask_mode, imol_map)
# atom_mask_mode: 0=all atoms, 1=mainchain only, 2=sidechain only
# Use to distinguish backbone problems from sidechain problems before choosing a fix
# Per-atom density probing — the most powerful backbone diagnostic:
sigma = coot.map_sigma_py(imol_map)
d = coot.density_at_point(imol_map, x, y, z) / sigma # value in sigma units
# Backbone atom < 0.5σ = problem; carbonyl O near 0σ with good CA = pepflip needed
coot.all_molecule_ramachandran_score_py(imol) -> list
# Returns a list of exactly 6 elements (confirmed from C++ source):
# [0]: overall score (float)
# [1]: n_residues (int)
# [2]: score_non_sec_str (float)
# [3]: n_residues_non_sec_str (int)
# [4]: n_zeros (int)
# [5]: per-residue list (list of per-residue entries)
#
# Each per-residue entry: [[phi, psi], [chain_id, resno, ins_code], probability, [prev_resname, this_resname, next_resname]]
# NOTE: rama_data[5] and rama_data[-1] are equivalent and both correct.
# LOW probability = BAD (outlier). Outlier threshold: prob < 0.02
#
# Example:
# per_res = coot.all_molecule_ramachandran_score_py(imol)[5]
# outliers = [r for r in per_res if r[2] < 0.02]
# worst = min(per_res, key=lambda x: x[2])
coot.rotamer_graphs_py(imol) -> list
# Returns: [[chain_id, resno, ins_code, score_percentage, resname], ...]
# LOW score = BAD rotamer
coot.molecule_atom_overlaps_py(imol, n_pairs) -> list
# Returns worst n_pairs atom overlaps (use -1 for all)
# Each overlap: {
# 'atom-1-spec': [imol, chain, resno, ins, atom_name, alt],
# 'atom-2-spec': [imol, chain, resno, ins, atom_name, alt],
# 'overlap-volume': float # in ų, >5.0 is severe
# }
coot.find_blobs_py(imol_model, imol_map, sigma_cutoff) -> list
# Finds unmodeled density blobs
# Returns: [[position, score], ...]
# position is a list or 3 floats, (for x, y, z)
# Use sigma_cutoff=3.0 for difference maps, 1.0 for 2mFo-DFc
# Higher score = larger/stronger blob
coot.get_hydrogen_bonds_py(imol, selection_1, selection_2, mcdonald_and_thornton) -> list
# Find hydrogen bonds between two atom selections.
# selection_1, selection_2: MMDB selection strings (e.g. "//A/35", "//A")
# Note: selection_1 and selection_2 can be the same, e.g. "//A" for intra-chain H-bonds
# mcdonald_and_thornton: 0 if model has no H atoms, 1 if it does
# Returns list of H-bond candidates, each a list of 12 elements:
# [0] hydrogen atom (dict or None)
# [1] donor atom (dict)
# [2] acceptor atom (dict)
# [3] donor neighbour atom (dict or None)
# [4] acceptor neighbour atom (dict or None)
# [5] angle_1 (float, degrees)
# [6] angle_2 (float, degrees)
# [7] angle_3 (float, degrees)
# [8] distance (float, Å)
# [9] ligand_atom_is_donor (bool)
# [10] hydrogen_is_ligand_atom (bool)
# [11] bond_has_hydrogen_flag (bool)
# Atom dicts have keys: x, y, z, name, element, chain, residue_name, occ, b_iso, altLoc
#
# Example:
hbonds = coot.get_hydrogen_bonds_py(0, "//A/35", "//A", 0)
for hb in hbonds:
donor = hb[1]
acceptor = hb[2]
dist = hb[8]
d_str = donor['chain'] + " " + donor['residue_name'] + " " + donor['name'].strip()
a_str = acceptor['chain'] + " " + acceptor['residue_name'] + " " + acceptor['name'].strip()
print("H-bond: " + d_str + " -> " + a_str + " dist=" + str(dist))
coot.refine_residues_py(imol, residue_specs) -> list
# Real-space refinement of specified residues
# residue_specs = [["A", 42, ""], ["A", 43, ""], ...] # [chain, resno, ins_code]
# Returns: ['', status, lights] where:
# status: 0=converged, -2=GSL_CONTINUE (call again), 27=no progress
# lights: list of [name, label, value] refinement statistics, or False
# CRITICAL: if status == -2, call refine_residues_py() again (up to 3 times total)
# Example robust call:
# for _ in range(3):
# result = coot.refine_residues_py(imol, specs)
# if result and result[1] != -2: break
# accepted = coot.accept_moving_atoms_py() # get traffic lights
coot.auto_fit_best_rotamer(
imol, # Model molecule
chain_id, # Chain (e.g., "A")
resno, # Residue number
ins_code, # Insertion code (usually "")
altloc, # Alt conf (usually "")
imol_map, # Map for density scoring
clash_flag, # 1=check clashes, 0=ignore
lowest_probability # Minimum rotamer probability (e.g., 0.01)
) -> float
# Returns new rotamer score, or -99.9 if residue has no rotamers (GLY, ALA)
coot.pepflip(imol, chain_id, resno, ins_code, altloc)
# Flips the peptide bond at specified residue
# Use for fixing cis/trans peptide issues or Ramachandran outliers
# or other false minimum backbone conformations.
# Follow with refinement of surrounding residues
When presenting validation results, geometry analysis, per-atom density data, or any
tabular data about multiple residues, ALWAYS render an interactive SVG widget using
visualize:show_widget. Never just print a wall of text.
The user can click on each residue block to navigate directly to it in Coot or trigger a fix. This is far more useful than stdout and makes results immediately actionable.
c-red — severe issues (Rama score < 0.001, rotamer 0%, corr < 0.3, omega > 20° off)c-amber — moderate issues (Rama 0.001–0.01, rotamer < 5%, corr 0.3–0.65)c-gray — informational / OK residuesc-teal — unmodelled density blobs / features to investigatec-green — successfully fixed residues (before/after comparisons)# Navigation
onclick="sendPrompt('Go to A/41 GLU and show me the density')"
# Investigation
onclick="sendPrompt('Go to B/257 GLU and investigate — negative correlation')"
# Fix requests
onclick="sendPrompt('Fix the clash between A/2 CA and A/89 CZ')"
onclick="sendPrompt('Try pepflip at B/262 and refine')"
onclick="sendPrompt('Fix rotamer A/32 GLN — 0% score')"
# Comparative
onclick="sendPrompt('Go to A/260 ALA — worst Ramachandran in chain A')"
The onclick prompt should describe the action to take, not just what the residue is. A user clicking a red block should trigger the next useful step automatically.
<svg width="100%" viewBox="0 0 680 [H]">
<!-- Section header -->
<text class="th" x="40" y="28">Ramachandran outliers</text>
<!-- Severe issue -->
<g class="node c-red" onclick="sendPrompt('Go to A/41 GLU and investigate Ramachandran outlier')">
<rect x="40" y="38" width="280" height="50" rx="8" stroke-width="0.5"/>
<text class="th" x="180" y="57" text-anchor="middle" dominant-baseline="central">A/41 GLU</text>
<text class="ts" x="180" y="74" text-anchor="middle" dominant-baseline="central">score 0.00004 phi=112°</text>
</g>
<!-- Moderate issue -->
<g class="node c-amber" onclick="sendPrompt('Go to A/35 VAL and investigate')">
<rect x="340" y="38" width="280" height="50" rx="8" stroke-width="0.5"/>
<text class="th" x="480" y="57" text-anchor="middle" dominant-baseline="central">A/35 VAL</text>
<text class="ts" x="480" y="74" text-anchor="middle" dominant-baseline="central">score 0.006</text>
</g>
</svg>
For bond/angle/omega distortions, display as rows with severity colour. Omega torsion outliers (|omega − 180°| > 15°) are the most sensitive backbone diagnostic and should always be highlighted — they identify misplaced backbone immediately.
<g class="node c-red" onclick="sendPrompt('Go to A/259 SER and investigate distorted backbone')">
<rect x="36" y="50" width="600" height="22" rx="4" stroke-width="0.5"/>
<text class="ts" x="40" y="65">A/258→A/259 omega</text>
<text class="ts" x="380" y="65">60.0° (ideal 180°)</text>
<text class="ts" x="510" y="65" style="fill:#A32D2D">+24.0σ distorted!</text>
</g>
# 1. Setup
coot.set_refinement_immediate_replacement(1)
# 2. Check what's loaded
for i in range(10):
if coot.is_valid_model_molecule(i):
print(f"Model {i}: {coot.molecule_name(i)}")
if coot.is_valid_map_molecule(i):
print(f"Map {i}: {coot.molecule_name(i)}")
# 3. Validate density fit
stats = coot.map_to_model_correlation_stats_per_residue_range_py(0, "A", 1, 1, 0)
worst = sorted(stats[0], key=lambda x: x[1][1])[:10]
# 4. Check for clashes
overlaps = coot.molecule_atom_overlaps_py(0, 30)
severe = [o for o in overlaps if o['overlap-volume'] > 5.0]
# 5. Fix bad rotamers
coot.auto_fit_best_rotamer(0, "A", 89, "", "", 1, 1, 0.01)
coot.refine_residues_py(0, [["A", 89, ""]])
# 6. Fix backbone issues
coot.pepflip(0, "A", 41, "", "")
coot.refine_residues_py(0, [["A", 40, ""], ["A", 41, ""], ["A", 42, ""]])
# 7. Re-validate
overlaps_after = coot.molecule_atom_overlaps_py(0, 10)
# 8. ALWAYS render results as an interactive SVG widget — see section above
set_refinement_immediate_replacement(1) first - makes refinement synchronouscoot.*_py() functions directly - faster than coot_utils wrapperschain_ids()coot module is auto-imported - no import statement needed