def transpSurf(amount): if amount != -1: aopacity = opacity = min(1.0, 1 - amount) else: opacity = 1 aopacity = -1 atoms = selAtoms() import Midas surfatoms = Midas.atomMSMSModels(atoms) for s,atoms in surfatoms.items(): adjustMSMSTransparency(s, atoms, opacity, aopacity) splist = selectedSurfacePieces(implied = True) from chimera import MSMSModel for p in splist: s = p.model if isinstance(s, MSMSModel) and s.molecule: adjustMSMSTransparency(s, s.atoms, opacity, aopacity) else: adjustSurfacePieceTransparency(p, opacity) if (len(atoms) > 0 and not selection.currentEmpty() and len(surfatoms) == 0 and len(splist) == 0): from replyobj import warning warning('No surfaces shown for selected atoms.\n')
def transpSurf(amount): if amount != -1: aopacity = opacity = min(1.0, 1 - amount) else: opacity = 1 aopacity = -1 atoms = selAtoms() import Midas surfatoms = Midas.atomMSMSModels(atoms) for s, atoms in surfatoms.items(): adjustMSMSTransparency(s, atoms, opacity, aopacity) splist = selectedSurfacePieces(implied=True) from chimera import MSMSModel for p in splist: s = p.model if isinstance(s, MSMSModel) and s.molecule: adjustMSMSTransparency(s, s.atoms, opacity, aopacity) else: adjustSurfacePieceTransparency(p, opacity) if (len(atoms) > 0 and not selection.currentEmpty() and len(surfatoms) == 0 and len(splist) == 0): from replyobj import warning warning('No surfaces shown for selected atoms.\n')
def reregister(name, function): """Reregister dialog creation/display function Same function variations allowed as in register. """ global _allDialogs try: dialog = _allDialogs[name] _allDialogs[name] = function except KeyError: replyobj.warning("error dialog %s missing\n" % name)
def contextCB(app): """Display help for selected widget. contextCB(app) => None """ rootX, rootY = chimera.viewer.trackingXY("help") if rootX != -1: # find widget that was under cursor widget = app.winfo_containing(rootX, rootY) if widget: widget.event_generate('<<Help>>', rootx=rootX, rooty=rootY) return replyobj.warning('pick part of application to get context help\n')
def register(name, function, replace=0): """Register dialog creation/display function The function is called with no arguments. The function can also be a class, or an instance of a class. If it is an instance, then the enter method is called. """ global _allDialogs if not replace and _allDialogs.has_key(name): replyobj.warning("error dialog %s already registered\n" % name) return _allDialogs[name] = function
def contextCB(app): """Display help for selected widget. contextCB(app) => None """ rootX, rootY = chimera.viewer.trackingXY("help") if rootX != -1: # find widget that was under cursor widget = app.winfo_containing(rootX, rootY) if widget: widget.event_generate('<<Help>>', rootx=rootX, rooty=rootY) return replyobj.warning('pick part of application to get context help\n')
def display(name, wait=False): """Display the dialog with the given name. The registered dialog display function is called. If wait is true, then this function doesn't return until the dialog is displayed. The dialog instance is returned if available. """ if not _allDialogs.has_key(name): replyobj.warning("no known dialog named: %s\n" % name) return None dialog = find(name, create=1) if not callable(dialog) and hasattr(dialog, 'enter'): dialog.enter() if wait: import _tkinter import chimera.tkgui chimera.tkgui.update_windows() return dialog
def getSequences(molecule, asDict=False): """return all non-trivial sequences in a molecule This function is also available as molecule.sequences(...) returns a list of sequences for the given molecule, one sequence per multi-residue chain. The sequence name is "Chain X" where X is the chain ID, or "Principal chain" if there is no chain ID. The 'residues' attribute of each sequence is a list of the residues for that sequence, and the attribute 'resmap' is a dictionary that maps residue to sequence position (zero-based). The 'residues' attribute will self-delete if the corresponding model is closed. If 'asDict' is true, return a dictionary of Sequences keyed on chain ID (can throw AssertionError if multiple chains have same ID), otherwise return a list. """ from chimera import bondsBetween, openModels, triggers from copy import copy def connected(res1, res2): if res1.id.chainId != ' ' \ and res1.id.chainId == res2.id.chainId \ and not res1.isHet and not res2.isHet: return True return bondsBetween(res1, res2, onlyOne=True) if hasattr(molecule, '_SequenceSequences'): seqList, seqDict, trigIDs = molecule._SequenceSequences if asDict: if seqDict is not None: return copy(seqDict) else: return copy(seqList) chain = None prevRes = None seqs = [] # don't start a sequence until we've seen two residues in the chain for res in molecule.residues: # if a residue has only one heavy atom, and that is connected # to only one other heavy atom, then don't put the residue # in the sequence # # if heavy is connected to no other heavy atom (presumably # metal or ion), end the chain atomLists = res.atomsMap.values() # take only one atom in each list, to avoid counting # alternate locations as multiple atoms atoms = map(lambda l: l[0], atomLists) heavys = filter(lambda a: a.element.number > 1, atoms) chainBreak = prevRes == None if len(heavys) == 0: continue # heavys more reliably connected than hydrogens if prevRes and not connected(prevRes, res): didMod = 0 if seq: for sr in seq.residues: if connected(sr, res): didMod = 1 if didMod: continue chainBreak = 1 elif prevRes and prevRes.id == res.id and len(heavys) == 1: continue elif chain is not None: # HET residues in named chains get the chain name, # but in blank chains they get 'het' -- allow for this truePrevID = chain trueResID = res.id.chainId if truePrevID != trueResID: if truePrevID in (" ", "het"): prevID = " " else: prevID = truePrevID if trueResID in (" ", "het"): resID = " " else: resID = trueResID if resID != prevID: chainBreak = 1 if chainBreak: # if chain ID changes in middle of connected chain # need to remember new chain ID... chain = res.id.chainId startRes = res prevRes = res seq = None continue # to avoid starting single-residues chains if not seq: if not chain or chain == " ": name = PRINCIPAL chain = " " else: name = CHAIN_FMT % chain seq = StructureSequence(startRes.molecule, name) seq.chain = chain seqs.append(seq) seq.append(startRes) seq.append(res) prevRes = res sd = {} for seq in seqs[:]: # set 'fromSeqres' in this loop so that all sequences have it seq.fromSeqres = None if seq.chain in sd: # a sequence of all 'X' residues or all het loses if str(seq).replace('X', ' ').isspace() \ or len([r for r in seq.residues if not r.isHet]) == 0: seqs.remove(seq) continue elif str(sd[seq.chain]).replace('X', ' ').isspace() \ or len([r for r in sd[seq.chain].residues if not r.isHet]) == 0: seqs.remove(sd[seq.chain]) sd[seq.chain] = seq continue if asDict: raise AssertionError("Multiple chains with" " same ID: '%s'" % seq.chain) sd = None break sd[seq.chain] = seq # use full sequence if available... seqresSeqs = seqresSequences(molecule, asDict=True) for chain, seq in sd.items(): try: srSeq = seqresSeqs[chain] except (KeyError, TypeError): continue seq.fromSeqres = True if len(srSeq) == len(seq): # no adjustment needed continue if len(srSeq) < len(seq): seq.fromSeqres = False import replyobj replyobj.warning("SEQRES record for chain %s of %s is incomplete.\n" "Ignoring record as basis for sequence." % (chain, molecule)) continue from MultAlignViewer.structAssoc import estimateAssocParams, tryAssoc estLen, segments, gaps = estimateAssocParams(seq) # if a jump in numbering is in an unresolved part of the # structure, the estimated length can be too long... estLen = min(estLen, len(srSeq)) try: # since gapping a structure sequence is considered an # "error", need to allow a lot more errors than normal... matchMap, numErrors = tryAssoc(srSeq, seq, segments, gaps, estLen, maxErrors=int(len(seq)/2)) except ValueError: seq.fromSeqres = False continue for i in range(len(srSeq)): if i in matchMap: del matchMap[i] else: seq.residues.insert(i, None) seq.resMap = matchMap seq[:] = srSeq[:] # try to avoid identical names baseNames = {} for seq in seqs: baseNames.setdefault(seq.name, []).append(seq) for baseName, sameNamedSeqs in baseNames.items(): if len(sameNamedSeqs) > 1: for i, seq in enumerate(sameNamedSeqs): seq.name += " [%d]" % (i+1) if hasattr(molecule, '_SequenceSequences'): # deregister from previous sequence's triggers... # (don't destroy the old sequences, may be in use elsewhere) seqList, seqDict, trigIDs = molecule._SequenceSequences for i, seq in enumerate(seqList): seq.triggers.deleteHandler(seq.TRIG_DELETE, trigIDs[i]) else: # invalidate the sequences cache if residues added/deleted molecule.__cacheHandlerID = triggers.addHandler('Residue', _invalidateCacheCB, molecule) # register for current sequence's triggers trigIDs = [] for seq in seqs: trigIDs.append( seq.triggers.addHandler(seq.TRIG_DELETE, _delSeq, None)) molecule._SequenceSequences = (seqs, sd, trigIDs) if asDict: return copy(sd) return copy(seqs)
def display(widgetOrURL, package=chimera, newWindow=False): """Display given html help file. display(widgetOrURL, package=chimera, newWindow=False) => None The url may be either a string, or a "widget" that has been registered. In the latter case it is mapped according to how it was registered. """ try: # compensate for Pmw megawidgets not being Tk widgets widgetOrURL = widgetOrURL.component('hull') except: pass if isinstance(widgetOrURL, basestring): url = widgetOrURL elif hasattr(widgetOrURL, 'winfo_parent'): # show help associated with widget or parent widget while widgetOrURL: if _helpMap.has_key(widgetOrURL): url, package = _helpMap[widgetOrURL] break parent = widgetOrURL.winfo_parent() if not isinstance(parent, str): widgetOrURL = parent elif parent == "": widgetOrURL = None else: widgetOrURL = widgetOrURL._nametowidget(parent) if not widgetOrURL: replyobj.warning('internal error -- no help found for widget\n') return elif isinstance(widgetOrURL, tuple): url, package = widgetOrURL if isinstance(package, basestring): package = __import__(package) else: replyobj.warning("internal error -- no help avaiable for: %s\n" % widgetOrURL) return protocol, location, path, parameters, query, fragment = \ urlparse.urlparse(url, allow_fragments=True) path = urllib.quote(path) parameters = urllib.quote(parameters) query = urllib.quote(query) fragment = urllib.quote(fragment) if path and path[0] != '/': file = os.path.join(package.__path__[0], "helpdir", path) if os.path.exists(file): protocol = 'file' if sys.platform == 'darwin': # # Setting location to localhost is needed on # Mac OS X with Internet Explorer because # urlunparse() produces urls like # file:/index.blah instead of # file:///index.html or # file://localhost/index.html # required by the browser. # location = 'localhost' path = urllib.pathname2url(file) if path[0:3] == '///': path = path[2:] url = urlparse.urlunparse( (protocol, location, path, parameters, query, fragment)) else: # Fetch development version of docs -- a released # version would have the help files included. protocol = 'http' url = urlparse.urljoin('http://www.cgl.ucsf.edu/chimera/docs/', url) replyobj.status("See web browser for %s\n" % url, blankAfter=10) import webbrowser try: webbrowser.open(url, newWindow) except webbrowser.Error: from chimera import NonChimeraError raise NonChimeraError( "Could not locate a web browser to use.\n" "\nTry setting your BROWSER environment variable to\n" "the command-line name of the web browser you want\n" "to use and restart Chimera.") except OSError, e: from chimera import NonChimeraError import errno if e.errno == errno.ENOENT: if protocol == 'file' \ and not os.path.exists(urllib.url2pathname(path)): raise # Bug starting webbrowser (firefox, bug 1512), # Windows usually opens it eventually raise NonChimeraError( "Error or delay starting default web browser.\n" "\n" "Wait a little and if the default web browser\n" "doesn't start up, start it by hand, and try\n" "again.") raise NonChimeraError("Unable to start web browswer.\n" "Open <%s> in your web browswer.\n" "(%s)" % (path, e))
def saveImage(filename=None, width=None, height=None, format=None, units="pixels", description=None, supersample=None, master=None, printMode=None, raytrace=False, raytracePreview=None, raytraceWait=None, raytraceKeepInput=None, hideDialogs=True, statusMessages=True, raiseWindow=True, task=None): if chimera.nogui and chimera.opengl_platform() != 'OSMESA': raise chimera.UserError, "Need graphics to save images (or use headless Linux version)" if statusMessages: from replyobj import status else: def status(*args, **kw): pass if printMode is None: printMode = chimera.viewer.camera.mode() horizPixels, vertPixels, supersample = \ imageArgs(units, width, height, supersample) savedSD = None # saved screen distance if units != 'pixels': adjustFOV = preferences.get(IMAGE_SETUP, ADJUST_FOV) if adjustFOV == 1 or (adjustFOV == ONLY_STEREO_CAMERAS and printMode != 'mono'): # if image is twice as wide as screen, # screenDistance is half as much savedSD = chimera.viewer.camera.screenDistance adjust = convert[units] / convert['millimeters'] image_width = width * adjust adjust = chimera.viewer.camera.windowWidth / image_width chimera.viewer.camera.screenDistance *= adjust if raytrace: if not checkPovrayLicense(): return # TODO: make default an argument or preference if raytraceWait is None: raytraceWait = preferences.get(POVRAY_SETUP, WAIT_POVRAY) if raytraceKeepInput is None: raytraceKeepInput = preferences.get(POVRAY_SETUP, KEEP_INPUT) if raytracePreview is None: raytracePreview = preferences.get(POVRAY_SETUP, SHOW_PREVIEW) quality = DEFAULT_JPEG_QUALITY format = 'PNG' if not chimera.nogui and not filename: if not master: master = tkgui.app chooseDialog = _ChooseFileDialog(filterSet='povray', format=format) result = chooseDialog.run(master) if result is None: status("Image save cancelled.") return filename, format = result[0] quality = chooseDialog.quality.get() if not filename: replyobj.error("Need filename for POV-Ray output") return if filename.endswith('.png') or filename.endswith('.jpg'): povfilename = filename[:-4] + '.pov' inifilename = filename[:-4] + '.ini' else: povfilename = filename + '.pov' inifilename = filename + '.ini' if task is None: from chimera.tasks import Task task = Task("raytrace image", None) task.updateStatus("Generating POV-Ray data file") import exports exports.doExportCommand('POV-Ray', povfilename) task.updateStatus("Generating POV-Ray parameter file") if savedSD is not None: chimera.viewer.camera.screenDistance = savedSD import SubprocessMonitor as SM cmd = [ preferences.get(POVRAY_SETUP, POVRAY_EXE), inifilename, "+I%s" % povfilename, "+O%s" % filename, "+V" # need verbose to monitor progress ] inifile = open(inifilename, 'w') print >> inifile, ( "Width=%d\n" "Height=%d\n" # add font path, CHIMERA/share/fonts "Library_Path=\"%s\"\n" "Bounding=On\n" "Bounding_Threshold=1\n" "Split_Unions=On\n" "Remove_Bounds=On\n" "Quality=%d" ) % ( horizPixels, vertPixels, os.path.join(os.environ['CHIMERA'], 'share', 'fonts'), preferences.get(POVRAY_SETUP, POV_QUALITY) ) if not preferences.get(POVRAY_SETUP, ANTIALIAS): print >> inifile, "Antialias=Off" else: print >> inifile, ( "Antialias=On\n" "Antialias_Threshold=%f\n" "Antialias_Depth=%d\n" "Sampling_Method=%d" ) % ( preferences.get(POVRAY_SETUP, ANTIALIAS_THRESHOLD), preferences.get(POVRAY_SETUP, ANTIALIAS_DEPTH), preferences.get(POVRAY_SETUP, ANTIALIAS_METHOD) ) if not preferences.get(POVRAY_SETUP, JITTER): print >> inifile, "Jitter=Off" else: print >> inifile, ( "Jitter=On\n" "Jitter_Amount=%f\n" ) % ( preferences.get(POVRAY_SETUP, JITTER_AMOUNT), ) oa = preferences.get(POVRAY_SETUP, OUTPUT_ALPHA) if oa == 1 or (oa == 2 and chimera.bgopacity): if chimera.viewer.depthCue: replyobj.warning("Depth-cueing disables transparent background") print >> inifile, "Output_Alpha=On" if format in ('PNG', 'Stereo PNG'): print >> inifile, ("; output PNG\n" "Output_File_Type=N8") elif format in ('JPEG', 'Stereo JPEG'): print >> inifile, ("; output JPEG\n" "Output_File_Type=J%d") % quality elif format in ('PPM'): print >> inifile, ("; output PPM\n" "Output_File_Type=P") if chimera.nogui or not raytracePreview: print >> inifile, "Display=Off" else: print >> inifile, "Display=On" if not raytraceWait: print >> inifile, "Pause_when_Done=On" inifile.close() if raytraceKeepInput: inputs = [] else: inputs = [ povfilename, inifilename ] def afterCB(aborted, inputs=inputs, outputs=[filename]): import os for fn in inputs: try: os.remove(fn) except OSError: pass if aborted: for fn in outputs: try: os.remove(fn) except OSError: pass task.updateStatus("Starting POV-Ray") try: subproc = SM.Popen(cmd, stdin=None, stdout=None, stderr=SM.PIPE, daemon=True) except OSError, e: raise chimera.UserError, "Unable run POV-Ray executable: %s" % e progress = povrayProgress(subproc) progress.start() subproc.setProgress(progress) info = 'running "%s"' % '" "'.join(cmd) if not chimera.nogui and statusMessages: from chimera import dialogs, tkgui dialogs.display(tkgui._ReplyDialog.name) replyobj.info(info + '\n') task.updateStatus(info) subprog = SM.monitor('running POV-Ray', subproc, title="POV-Ray progress", task=task, afterCB=afterCB) if raytraceWait: subprog.wait() return
def display(widgetOrURL, package=chimera, newWindow=False): """Display given html help file. display(widgetOrURL, package=chimera, newWindow=False) => None The url may be either a string, or a "widget" that has been registered. In the latter case it is mapped according to how it was registered. """ try: # compensate for Pmw megawidgets not being Tk widgets widgetOrURL = widgetOrURL.component('hull') except: pass if isinstance(widgetOrURL, basestring): url = widgetOrURL elif hasattr(widgetOrURL, 'winfo_parent'): # show help associated with widget or parent widget while widgetOrURL: if _helpMap.has_key(widgetOrURL): url, package = _helpMap[widgetOrURL] break parent = widgetOrURL.winfo_parent() if not isinstance(parent, str): widgetOrURL = parent elif parent == "": widgetOrURL = None else: widgetOrURL = widgetOrURL._nametowidget(parent) if not widgetOrURL: replyobj.warning('internal error -- no help found for widget\n') return elif isinstance(widgetOrURL, tuple): url, package = widgetOrURL if isinstance(package, basestring): package = __import__(package) else: replyobj.warning("internal error -- no help avaiable for: %s\n" % widgetOrURL) return protocol, location, path, parameters, query, fragment = \ urlparse.urlparse(url, allow_fragments=True) path = urllib.quote(path) parameters = urllib.quote(parameters) query = urllib.quote(query) fragment = urllib.quote(fragment) if path and path[0] != '/': file = os.path.join(package.__path__[0], "helpdir", path) if os.path.exists(file): protocol = 'file' if sys.platform == 'darwin': # # Setting location to localhost is needed on # Mac OS X with Internet Explorer because # urlunparse() produces urls like # file:/index.blah instead of # file:///index.html or # file://localhost/index.html # required by the browser. # location = 'localhost' path = urllib.pathname2url(file) if path[0:3] == '///': path = path[2:] url = urlparse.urlunparse((protocol, location, path, parameters, query, fragment)) else: # Fetch development version of docs -- a released # version would have the help files included. protocol = 'http' url = urlparse.urljoin( 'http://www.cgl.ucsf.edu/chimera/docs/', url) replyobj.status("See web browser for %s\n" % url, blankAfter=10) import webbrowser try: webbrowser.open(url, newWindow) except webbrowser.Error: from chimera import NonChimeraError raise NonChimeraError("Could not locate a web browser to use.\n" "\nTry setting your BROWSER environment variable to\n" "the command-line name of the web browser you want\n" "to use and restart Chimera.") except OSError, e: from chimera import NonChimeraError import errno if e.errno == errno.ENOENT: if protocol == 'file' \ and not os.path.exists(urllib.url2pathname(path)): raise # Bug starting webbrowser (firefox, bug 1512), # Windows usually opens it eventually raise NonChimeraError( "Error or delay starting default web browser.\n" "\n" "Wait a little and if the default web browser\n" "doesn't start up, start it by hand, and try\n" "again.") raise NonChimeraError("Unable to start web browswer.\n" "Open <%s> in your web browswer.\n" "(%s)" % (path, e))