Last updated May 10, 2010. The most recent copy of the FAQ is at http://www.cgl.ucsf.edu/chimera/docs/ProgrammersGuide/faq.html
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.
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")
--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.pdbChimera 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.
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)
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.
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
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
import Midas Midas.copy(file='/home/goddard/hoohoo.png', format='PNG') # format can be 'PNG', 'JPEG', 'TIFF', 'PS', 'EPS'
>>> 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.
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.
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.
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.
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.
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
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)
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/.