Measure Atomic-Level Quantities

This example shows how to measure atomic-level (rather than volumetric) quantities such and angles, RMSDs, surface areas, and so forth.


Atomic Coordinates in Chimera

The first concept to understand is that when models are moved in Chimera, the atomic coordinates are not changed. Instead, a "transformation" matrix is updated that transforms the model's original coordinates into "world" coordinates (i.e. into the overall coordinate system). Consequently, there are two methods for obtaining a coordinate from a chimera.Atom object: coord(), which returns the Atom's original coordinate, and xformCoord(), which returns the transformed coordinate. Note that some structure-editing activities in Chimera will change the original coordinates (e.g. changing a torsion angle).

Therefore, if you are measuring quantities that might involve multiple models, you should use the xformCoord() method. If your measurements are completely intra-model you can instead use the very slightly faster coord() method.


Getting Atoms, Bonds, Residues

The "Chimera's Object Model" example discusses how to access various Chimera objects in detail, but here's an executive summary for the tl;dr crowd:

Getting a list of open chimera.Molecule models

from chimera import OpenModels, Molecule
mols = OpenModels.list(modelTypes=[Molecule])

Getting lists of chimera.Atoms/Bonds/Residues from a chimera.Molecule object

The Atoms/Bonds/Residues in a chimera.Molecule object are contained in that object's atoms/bonds/residues attributes, respectively.

Getting Atoms/Bonds/Residues from the current selection

To get the Atoms/Bonds/Residues in the current selection (perhaps set by the user or earlier in the code via the runCommand() function), use the currentAtoms/currentBonds/currentResidues functions in the chimera.selection module, e.g.:
from chimera.selection import currentAtoms
sel_atoms = currentAtoms()

Getting Atoms/Bonds/Residues/Molecules from related Atoms/Bonds/Residues

Here are some import methods/attributes for accessing Atoms/Bonds/Residues related to other Atoms/Bonds/Residues:
Atom.neighbors
Atom.primaryNeighbors()
Returns a list of the Atoms bonded to the given Atom. Some high-resolution structures can have multiple positions for a single atom, and in those cases primaryNeighbors() will only return one Atom among those positions whereas neighbors will return all of them.
Atom.bonds
Atom.primaryBonds()
Returns a list of the Bonds the Atom is involved in.  primaryBonds() is analogous to Atom.primaryNeighbors().
Atom.bondsMap
Returns a dictionary whose keys are Atoms the given Atom is bonded to, and the values are the corresponding Bonds.
Atom.residue
Returns the Residue the Atom is in.
Atom.molecule
Returns the Molecule model the Atom is in.
Bond.atoms
Returns a list of the two Atoms forming the Bond.
Residue.atoms
Returns a list of the Atoms in the Residue.
Residue.atomsMap
Returns a dictionary whose keys are atom names. The values are lists of Atoms with the corresponding name. The values are lists because in some structure formats (e.g. Mol2, XYZ) small molecules atoms are not given unique names (for example, all carbons are named "C"). Also, PDB files where an atom has alternate locations will produce multiple Atoms with the same name in a Residue.
Residue.molecule
Returns the Molecule model the Residue is in.

Point objects

Both the Atom.coord() and Atom.xformCoord() methods return chimera.Point objects. Point objects have the following built-in measurement methods:

Point.distance(Point)
Returns the distance in angstroms between the two Points.
Point.sqdistance(Point)
Returns the square of the distance in angstroms between the two Points. Taking square roots is slow, so this method is faster than the distance() method. Therefore in code where speed is important, when possible you should work with squares of distances rather than the distances themselves (e.g. when comparing a distance to a cutoff value, compare the squares instead [and make sure to only compute the square of the cutoff once!]).

Basic Measurement Functions

The chimera module offers several basic measurement functions:
chimera.distance(Point, Point)
chimera.sqdistance(Point, Point)
Returns the distance (or distance squared) in angstroms between the two Points. Functionally identical to Point.distance(Point) and Point.sqdistance(Point) methods respectively.
chimera.angle(Point, Point, Point)
Returns the angle in degrees formed by the points. The angle value ranges from 0 to 180.
chimera.dihedral(Point, Point, Point, Point)
Returns the dihedral angle in degrees formed by the points. The angle value ranges from -180 to 180.  Note that Residues have phi, psi, and chi1 through chi4 attributes that can be queried for the corresponding values (value will be None if the Residue lacks that kind of angle). In fact, those attributes can be set and the structure will be adjusted appropriately!
Here's a simple code snippet for finding the angle between three atoms (a1, a2, a3) that may not all be in the same model (and therefore need to have the xformCoord() method used to fetch their coordinates):
import chimera
angle = chimera.angle(a1.xformCoord(), a2.xformCoord(), a3.xformCoord())
Alternatively, if the three atoms are in a list (atoms), you can use slightly fancier Python:
import chimera
angle = chimera.angle(*[a.xformCoord() for a in atoms])

Axes, Planes, Centroids

Preliminaries

The centroid, axis, and plane functions described below utilize chimera.Point, chimera.Vector, and chimera.Plane objects for some of their return values. A chimera.Point object, described previously, abstracts a point in Cartesian 3-space. A chimera.Vector objects abstracts a direction vector in 3-space with finite length (i.e. it is not infinite and has an associated length). A chimera.Plane object abstracts an infinite plane in 3-space. Each of these objects has useful member functions that you can learn about by using the help Python function in the IDLE tool (e.g. help(chimera.Plane)). For instance, if p is a Plane and pt is a Point, then p.distance(pt) is the distance from the Point pt to the Plane p.

The axis and plane functions take an n-by-3 numpy array as one of their input arguments. The easiest way to generate such an array from Atom coordinates is to use the numpyArrayFromAtoms function from the chimera module (i.e. chimera.numpyArrayFromAtoms(Atoms) or, if transformed coordinates are required, chimera.numpyArrayFromAtoms(Atoms, xformed=True)).

The Functions

The StructMeasure module has three convenient functions for finding the best-fitting axis, centroid, or plane through a set of points. They are:

StructMeasure.centroid(points, weights=None)
Returns a chimera.Point object. points is a sequence of chimera.Point objects. weights is an optional sequence of corresponding numeric weights to give those Points when computing the centroid. weights is most frequently used when mass weighting is desired. To that end, it is useful to know that the mass of atom a is given by a.element.mass.
StructMeasure.axis(xyzs, findBounds=False, findRadius=False, iterate=True, weights=None)
Returns a chimera.Point and chimera.Vector. The Point is the center of the axis, and the Vector indicates the direction of the axis (and is of unit length). As discussed in Preliminaries, xyzs is an n-by-3 numpy array. If findBounds is True, two floating point numbers are appended to the return values, indicating the scaling values needed for the Vector to reach the approximate end of the axis given the input coordinates. One of the scaling values will be negative. If findRadius is True, a floating point number, indicating the approximate radius of the axis given the input coordinates, will be appended to the return values. If iterate is True, the best-fitting axis as determined by principal-component analysis will be iteratively tweaked to try to get the axis as equidistant as possible from the points determining the axis. For helical sets of atoms, the principal-component axis will tend to tilt towards the final atoms of the helix. The tilt is more pronounced the shorter the helix, and iterate attempts to correct the tilt. weights is the same as in the centroid function.
StructMeasure.plane(xyzs, findBounds=False)
Returns a chimera.Plane whose origin is the centroid of xyzs. As discussed in Preliminaries, xyzs is an n-by-3 numpy array. If findBounds is True, a Point, which represents the furthest xyz from the origin when projected onto the Plane, is appended to the return value.

Surface Areas

Once a surface has been computed for a model, all Atoms and Residues of that model will have an areaSAS attribute (solvent accessible surface area) and an areaSES attribute (solvent excluded surface area). One possible way to get a surface computed for a model is to call the surface command via the runCommand() function.