Last updated November 29, 2005. The most recent copy of the FAQ is at http://www.cgl.ucsf.edu/chimera/docs/ProgrammersGuide/faq.html
The Chimera Programmer's Reference manual is automatically generated from comments in the code and is of varying utility. 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 from the Programmer's Guide index. 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.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")
Chimera handles all command-line arguments itself, so there is no direct way to pass arguments to scripts. However, you can use environment variables for the same purpose. So if you ran your Chimera script like so:
env PDB="1jhg" chimera --nogui script.py
then your script could access the value of the PDB environment variable like this:
import os pdb = os.environ["PDB"]
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 uncopied 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, .... These objects that are not copied do not have any any method for copying them. 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 copied. Those with a WrapPy base class are not 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 tranparent. 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.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 UnitCell center = UnitCell.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, 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)