Chimera Programming Frequently Asked Questions

Last updated May 10, 2010. The most recent copy of the FAQ is at http://www.cgl.ucsf.edu/chimera/docs/ProgrammersGuide/faq.html

  1. Where is the programming documentation?
  2. How to emulate command-line functionality.
  3. Passing arguments to scripts.
  4. How to rotate/translate the camera.
  5. How to rotate/translate individual models.
  6. How to save the current view as an image.
  7. Some attributes return a copy of an object.
  8. Explanation of transparency for Surface_Model, MSMSModel and VRMLModel.
  9. Transparency displayed incorrectly when 2 or more models are transparent.
  10. Explanation of openState attribute.
  11. Memory leaks in scripts.
  12. Getting the size of a volume data set.
  13. How to write out a PDB file containing the crystal unit cell.
  14. How to access files within the Chimera app on Macs.

1) Where is the programming documentation?

The Programming Examples are a good source of information. More information can be gleamed from the C++ header files for the Chimera objects. Those header files are available in the source code download. Another source of object info is the help() function in the Chimera's IDLE Python shell (under General Controls). For example, help(chimera.Atom) will show (C++) methods and attributes of Atom objects. Even more information is available via chimera developer's mailing list, chimera-dev@cgl.ucsf.edu. The archived mailing list is at http://www.cgl.ucsf.edu/pipermail/chimera-dev.

2) How to emulate command-line functionality.

Commands available at the type-in command line are almost all implemented in the Midas module's __init__.py file. You can use the commands for convenience in implementing the same functionality in your extension. For example, to color iron atoms red:

import Midas
Midas.color('red', '@/element=Fe')

A few commands related to processing command text (e.g. handling files of commands) are in Midas.midas_text. One in particular, makeCommand(), allows you to use command-line syntax directly instead of determining the proper arguments to a Midas module function. So the above example of coloring atoms red would look like this using runCommand():

from chimera import runCommand
runCommand("color red @/element=Fe")

Note that if the command text may contain errors (e.g. it is based on user input), runCommand() can raise MidasError (defined in the Midas module) so in such cases you may want to embed the runCommand() in a try/except block.

In pre-1.0 build 2107 versions of Chimera, the runCommand() convenience function doesn't exist, so you'd have to use the functionally identical makeCommand() as follows:

import Midas
from Midas.midas_text import makeCommand
makeCommand("color red @/element=Fe")

3) Passing arguments to scripts.

Use the --script option to invoke a Python script after all of the other arguments have been processed. If more than than one script option is given, the scripts are executed in the order given. Each script is executed using the arguments enclosed along with it in quotes. Any data files specified in the shell command line are opened before the script is called. For example:

chimera --nogui --nostatus --script "script.py -r 2.3 -- -1.pdb" -- -4.pdb
Chimera would open the -4.pdb file, and invoke script.py with the runscript command so sys.argv would be set to ['script.py', '-r', '2.3', '--', '-1.pdb']. The -- argument terminates the options list and is only necessary if the next non-option argument has a leading dash.

3a) Turning scripts into programs.

To make your Python script look like any other shell program, you could provide an executable shell script as shown below. The shell script accepts a subset of chimera options and options for the Python script, adds in a chimera option to show the Reply Log at startup, then packages the Python script options into a single chimera option, and invokes chimera with those options.

#!/bin/bash
PYSCRIPT=PATH-TO-PYTHON_SCRIPT.py
CHIMERA=PATH-TO-CHIMERA
# Parse arguments to decide which are script arguments
# and which are chimera arguments.  In this case, --debug,
# --stereo, -n, --nogui, --nostatus, and --silent are chimera
# arguments.  And -r, and --radius are the script arguments.
# Note that accepting --argument options in shell scripts
# depends on having a newer version of getopt.

if `getopt -T >/dev/null 2>&1` ; [ $? = 4 ]
then
	TEMP=`getopt -o nr: --long radius:,debug,stereo:,nogui,nostatus,silent -n "$0" -- "$@"`
else
	TEMP=`getopt nr: "$@"`
fi
if [ $? != 0 ]
then
	printf "Usage: %s: [-r|--radius value] args\n" $0
	exit 2
fi
eval set -- "$TEMP"

# set initial chimera arguments, in this case always show the Reply Log
CHARGS=(--start "Reply Log")
while [ $1 != -- ]
do
        case "$1" in
	-r|--radius)
		PYSCRIPT="$PYSCRIPT $1 '$2'"
		shift 2;;
	-n|--debug|--nogui|--nostatus|--silent)
		CHARGS[${#CHARGS[@]}]=$1
		shift;;
	--stereo)
		CHARGS[${#CHARGS[@]}]=$1
		CHARGS[${#CHARGS[@]}]="$2"
		shift 2;;
	esac
done
shift # skip --
$CHIMERA "${CHARGS[@]}" --script "$PYSCRIPT" "$@"
And the Python script would parse its arguments with:
import getopt
try:
	opts, args = getopt.getopt(sys.argv[1:], 'r:', ['radius='])
except getopt.error, message:
	raise chimera.NonChimeraError("%s: %s" % (__name__, message))
radius = 1.0
for o in opts:
	if o[0] in ("-r", "--radius"):
		radius = o[1]
assert(len(args) == 0)

3b) Installing Python packages into Chimera.

To use a package from Chimera, you would need to install it with Chimera's Python. Chimera's Python has the Python version number appended to it, so it will be named python2.x (python2.7 when this was written; also on Windows add ".exe"). On non-Mac, it will be found in <your Chimera installation>/bin. On Mac it's in Chimera.app/Contents/Resources/bin — don't use the one in Chimera.app/Contents/MacOS!

The best way to install packages is with pip, using (Chimera's) python2.x -m pip install package. If the pip module is not found, you'll need to install it first with (Chimera's) python2.x -m ensurepip. Then -m pip install will work. For packages not supported by pip, you will have to follow the installation instructions that come with the package.

4) How to rotate/translate the camera.

Camera always points in -z direction. There is no way to rotate it. Instead, rotate all of the models.

>>> v = chimera.viewer
>>> c = v.camera
>>> print c.center
(5.9539999961853027, -2.186500072479248, 10.296500205993652)
>>> c.center = (3, 2.5, 10)	# to translate camera
>>> v.scaleFactor = 1.5		# to zoom camera

5) How to rotate/translate individual models.

The Xform object model.openState.xform retrieves a copy of the rotation and translation transformation for a model.

>>> om = chimera.openModels
>>> mlist = om.list()
>>> m = mlist[0]
>>> axis = chimera.Vector(1, 0, 0)
>>> angle = 90			# degrees
>>> xf = chimera.Xform.rotation(axis, angle)
>>> print m.openState.xform	# 3x3 rotation matrix
				# last column is translation
0.982695 0.121524 0.139793 -1.07064
0.0250348 0.660639 -0.750287 6.83425
-0.183531 0.740803 0.646164 6.35578
>>> m.openState.globalXform(xf)

Another method to change the transform

>>> curxform = m.openState.xform # get copy (not reference)
>>> xf.premultiply(curxform)	 # changes xf
>>> m.openState.xform = xf	 # set it

To rotate relative to model's data axes use

>>> m.openState.localXform(xf)

or

>>> curxform = m.openState.xform # get copy (not reference)
>>> xf.multiply(curxform)	 # changes xf
>>> m.openState.xform = xf	 # set it

6) How to save the current view as an image.

import Midas
Midas.copy(file='/home/goddard/hoohoo.png', format='PNG')
# format can be 'PNG', 'JPEG', 'TIFF', 'PS', 'EPS'

7) Some attributes return a copy of an object.

>>> xf = model.openState.xform	# xf is a copy of the model's Xform matrix.
>>> xf.zRotate(45)		# This will not rotate the model.
>>> c = model.atoms[0].color	# c is the MaterialColor object for the atom
>>> c.ambientDiffuse = (1,0,0)	# The Atom color changes immediately to red.

Some Chimera objects returned as attributes are always copies, some are always references to the original object. Objects that are always copied include Xform, Vector, Point, Sphere, Element, MolResId, Coord, .... Objects that are never copied include Atom, Bond, PseudoBond, CoordSet, Molecule, Residue, RibbonStyle, .... Object that can be copied have a __copy__ method. In order to know if an object type is passed by value is to look at the Chimera C++ header files. Classes without a WrapPy base class are always copied. This base class is part of the C++ to Python interface generation.

8) Explanation of transparency for Surface_Model, MSMSModel and VRMLModel.

Volume viewer isosurfaces are Surface_Model objects defined by the _surface.so C++ module. The Surface_Model interface is given in the surfmodel.h source code file. By default these surfaces use OpenGL (1,1-alpha) blending. This means the color for a triangle is added to an image plus the transparency (= 1-alpha) times the color from triangles in back of this one. As the transparency becomes greater, the brightness of the triangle does not diminish. In fact, more shows through from behind the triangle so it appears brighter. The specular highlights stay bright even if the triangle is black and fully transparent. In Chimera 1730 a Surface_Model attribute transparency_blend_mode was added to allow the more common (alpha,1-alpha) blend mode. This is like the above mode but the triangle color is multiplied by alpha before being added to the image. For highly transparent triangles alpha is close to zero, and the triangle and specular highlights become dim.

MSMS molecular surface models use (alpha, 1-alpha) blending. They also use a 2 pass algorithm which is faster than sorting all the triangles by depth, but gives the strictly correct appearance only when the viewer looks through at most 2 surface layers.

VRML models use (alpha,1) blending. That is they multiply triangle color by alpha, but add in all of the color from triangles further back without reducing it by the transparency factor. This is like complete transparency, where the triangle colors are just scaled by the alpha value. This is horrible looking unless you want complete transparency.

9) Transparency displayed incorrectly when 2 or more models are transparent.

The Chimera architecture only correctly displays transparency when at most one transparent model is shown. Any number of opaque models can also be shown. If two transparent models are shown, one will be drawn after the other. This will make one appear as if it is drawn entirely on top of another even if they in actuality intersect. The rearmost model, may in fact appear to be in front. This is because Chimera sorts the triangles by depth within a single model as needed for rendering transparency, but is not able to sort triangles by depth across multiple models.

10) Explanation of openState attribute.

The openState attribute of a Model controls whether that model is active for motion ('.active'), and contains the model's transformation matrix ('.xform') and center of rotation ('.cofr'). Since some models must move in synchrony (e.g. a molecule and its surface), OpenState instances may shared among multiple models. If you create a model that needs a shared openState with another model, then when adding your model to the list of open models with chimera.openModels.add(), you should use the 'sameAs' keyword to specify that other model.

11) Memory leaks in scripts.

In the 1700 release, Chimera uses a substantial amount of memory to hold molecular data, but does not have any large memory leaks to the best of our knowledge (i.e. as structures are closed their memory usage will be reclaimed). However, the memory is reclaimed by a task that runs during idle times, so therefore scripts that loop through many structures, opening and closing them, will have their memory use grow continuously until the script finishes. This will often cause the script to fail as the Chimera process runs out of memory.

You can cause the memory-reclamation task to run during your script by calling:

chimera.update.checkForChanges()

You would want to call this after closing models in your script. Since the checkForChanges() routine also allows triggers to fire, you might want to also put it after any code that opens models. For example, the code that assigns surface categories to models runs from a trigger callback, so adding a molecular surface may not work as expected if checkForChanges() is not called after a molecule is opened.

In post-1700 releases and snapshots, checkForChanges() is called automatically when models are opened or closed, so you will not need to insert these calls into your code.

12) Getting the size of a volume data set.

Here's some code to find the size of a volume data set.

import VolumeViewer
d = VolumeViewer.volume_dialog()
d0 = d.data_sets[0]	# There may be more than one data set opened
			# You could look at each one's name (= file name)
			# to find the one you want.
data = d0.data		# This is a Grid_Data object defined in
			# VolumeData/griddata.py
xsize, ysize, zsize = data.size

13) How to write out a PDB file containing the crystal unit cell.

Here's code that creates the copies of a PDB molecule needed to fill out a crystallographic unit cell, then writes all the copies to a new PDB file. This code uses the standard Chimera 1.0 build 1892 PDBmatrices module, which uses the PDB SMTRY remarks or CRYST1 record to determine the needed transformations.

You can run it without a graphical user interface as follows

% chimera --nogui myfile.pdb writeunitcell.py

where the writeunitcell.py file contains the script given below.

# Get the Molecule that has already been opened
import chimera
m = chimera.openModels.list()[0]

# Get the symmetry matrices
import PDBmatrices
tflist = PDBmatrices.crystal_symmetry_matrices(m.pdbHeaders)

# Get center of bounding box
import Molecule
center = Molecule.molecule_center(m)

# Get CRYST1 line from PDB headers
cryst1 = m.pdbHeaders['CRYST1'][0]

# Getting crystal parameters
from PDBmatrices import crystal
cp = crystal.pdb_cryst1_parameters(cryst1)
a,b,c,alpha,beta,gamma = cp[:6]

# Adjust matrices to produce close packing.
cpm = PDBmatrices.close_packing_matrices(tflist, center, center, a, b, c, alpha, beta, gamma)

# Apply transformations to copies of Molecule
mlist = []
from PDBmatrices import matrices
path = m.openedAs[0]			# Path to original PDB file
for tf in cpm:
    xf = matrices.chimera_xform(tf)	# Chimera style transform matrix
    m.openState.globalXform(xf)
    mlist.append(m)
    m = chimera.openModels.open(path)[0]	# Open another copy

# Write PDB file with transformed copies of molecule
import Midas
out_path = 'unitcell.pdb'
Midas.write(mlist, None, out_path)

14) How to access files within the Chimera app on Macs.

One way to access the Python code and other Chimera files on a Mac is to right-click on the Chimera application icon and choose "Show Package Contents" from the resulting pop-up menu. Another way is to use Terminal.app and the command "cd" to navigate into the Chimera.app directory and its subdirectories. Most files of interest can be found under Contents/Resources/share/.