An extension often needs to respond to changes in data caused by other extensions. For instance, in the Colors and Color Wells example, a color well is used to control the color of protein backbone atoms; if another extension (e.g., Midas emulator) changes the color of some backbone atoms, the color in the well should change accordingly as well
Chimera provides the trigger mechanism for notifying interested parties of
spontaneous changes in data. A trigger is an object which monitors
changes for a set of data; an extension can register a handler to be
invoked whenever the trigger detects data modification. A standard set of triggers
is defined in chimera.triggers
. In particular, there are triggers
for objects of common classes; e.g., there is a trigger monitoring all Atom
objects. Thus, tracking changes of standard objects is very straightforward.
Besides standard object triggers, there are a few other triggers of general
interest:
chimera.selection
are used to query and manipulate the selection.
Also, chimera.openModels maintains two triggers that fire when models
are added to or removed from the list of open models. To register for
these triggers use the chimera.openModels.addAddHandler
and chimera.openModels.addRemoveHandler
functions respectively.
They each expect two arguments: a callback function and user data. They
return a handler ID. The callback function will be invoked with two
arguments: the added/removed models and the provided user data.
You can deregister from these triggers with
chimera.openModels.deleteAddHandler
and
chimera.openModels.deleteRemoveHandler
respectively.
These latter two functions expect the handler ID as an argument.
The example below derives from the code in Colors
and Color Wells, and the code description assumes that the reader is familiar
with that code. While the Colors and Color Wells
code only synchronizes the color well with backbone atom colors when the graphical
user interface is first created, the example below registers a handler with
the Atom
trigger and updates the color well whenever a backbone
atom is changed. Note that changes in atom data may have nothing to do with
colors; the Atom
trigger invokes registered handlers whenever any
change is made. However, it is computationally cheaper to recompute the well
color on any change than to keep track of atom colors and only update
the well color on color changes.
This file is identical to the ColorWellUI/__init__.py
in the Colors and Color Wells example.
The code here is very similar to the code in Colors
and Color Wells and only differences from that code
will be described.
Need to override
Whereas in the Colors and Color Wells example
Call the parent-class
Save ColorOption in instance.
Register a trigger handler to monitor changes in the
backbone atom list when we're make visible. We ignore
the event argument.
Synchronize with well color.
If no handler is currently registered, register one.
Registration occurs when the
In this case, the trigger name is the same as the name
of the class of objects being monitored, "Atom".
The handler function is
The handler function is always invoked by the trigger
with three arguments:
Note that with a newly opened model, objects will just
appear in both the
The
Check through modified atoms for backbone atoms.
If any of the changed atoms is a backbone atom, call
Check whether a handler is currently registered (i.e., the
handler identifier,
Deregistration requires two arguments: the name of the
trigger and the unique handler identifier returned by
the registration call.
Set the unique handler identifier to
Define the module variable
Define Monitoring changes in atoms can result in many handler invocations. In an attempt
to reduce computation, the example above deregisters its handler when the
user interface is not being displayed.
The example code files must be saved in a directory named This should display a button on the Chimera toolbar. Clicking the button should
bring up a window with a color well inside. The color well may be used to manipulate
the color of all protein backbone atoms. Changing atom colors through another
mechanism, e.g., the Midas emulator, should result in appropriate color
changes in the color well.
import chimera
import re
MAINCHAIN = re.compile("^(N|CA|C)$", re.I)
def mainchain(color):
for m in chimera.openModels.list(modelTypes=[chimera.Molecule]):
for a in m.atoms:
if MAINCHAIN.match(a.name):
a.color = color
Example AtomTrigger/gui.py
import os
import Tkinter
import chimera
from chimera.baseDialog import ModelessDialog
from chimera.tkoptions import ColorOption
import ColorWellUI
class ColorWellDialog(ModelessDialog):
title = 'Set Backbone Color'
__init__
to initialize our extra state.
def __init__(self, *args, **kw):
coloropt
was a local variable, here the coloropt
variable is stored
in the instance because the trigger handler (which has access
to the instance) needs to update the color well contained in
the ColorOption. A new variable, handlerId
, is created to
keep track of whether a handler is currently registered. The
handler is only created when needed. See map
and unmap
below. (Note that the instance variables must be set before
calling the base __init__ method since the dialog may be mapped
during initialization, depending on which window system is used.)
self.colorOpt = None
self.handlerId = None
__init__
.
apply(ModelessDialog.__init__, (self,) + args, kw)
def fillInUI(self, master):
self.coloropt = ColorOption(master, 0, 'Backbone Color', None, self._setBackboneColor, balloon='Protein backbone color')
self._updateBackboneColor()
def _updateBackboneColor(self):
for m in chimera.openModels.list(modelTypes=[chimera.Molecule]):
for a in m.atoms:
if ColorWellUI.MAINCHAIN.match(a.name):
try:
if a.color != theColor:
self.coloropt.setMultiple()
return
except NameError:
theColor = a.color
try:
self.coloropt.set(theColor)
except NameError:
self.coloropt.set(None)
def _setBackboneColor(self, coloroption):
ColorWellUI.mainchain(coloroption.get())
def map(self, *ignore):
self._updateBackboneColor()
if self.handlerId is None:
chimera.triggers
object
is requested to add a handler. Registration requires
three arguments:
_handler
, defined below.
And the additional argument is empty (None) -- it could
have been the ColorOption instance (coloropt
) but that
is accessible via the instance. The return value from
the registration is a unique handler identifier for
the handler/argument combination. This identifier is
required for deregistering the handler.
created
set and not in the modified
set, even though the newly created objects will normally have
various of their default attributes modified by later
code sections.
self.handlerId = chimera.triggers.addHandler('Atom', self._handler, None)
_handler
function is the trigger handler invoked when
attributes of Atom
instances change.
def _handler(self, trigger, additional, atomChanges):
for a in atomChanges.modified:
_updateBackboneColor
to synchronize the well color
with backbone atom colors.
if ColorWellUI.MAINCHAIN.match(a.name):
self._updateBackboneColor()
return
unmap
is called when the dialog disappears. We ignore the
event argument.
def unmap(self, *ignore):
handlerId
, is not None
) and
deregister it if necessary.
if self.handlerId is not None:
chimera.triggers.deleteHandler('Atom', self.handlerId)
None
to indicate
that no handler is currently registered.
self.handlerId = None
dialog
, which tracks the dialog instance.
It is initialized to None
, and is assigned a usable value when the
dialog is created.
dialog = None
showColorWellUI
, which is invoked when the Chimera
toolbar button is pressed.
def showColorWellUI():
global dialog
if dialog is not None:
dialog.enter()
return
dialog = ColorWellDialog()
dir, file = os.path.split(__file__)
icon = os.path.join(dir, 'AtomTrigger.tiff')
chimera.tkgui.app.toolbar.add(icon, showColorWellUI, 'Set Main Chain Color', None)
Code Notes
Running the Example
AtomTrigger
.
To run the example, start chimera, bring up the Tools preference category (via
the Preferences entry in the Favorites menu;
then choosing the "Tools" preference category) and use
the Add button to add the directory above the
AtomTrigger
directory.
Then type the following command into the IDLE command line:
import AtomTrigger.gui