def get_names(type='public_objects',enabled_only=0,selection="",_self=cmd): ''' DESCRIPTION "get_names" returns a list of object and/or selection names. PYMOL API cmd.get_names( [string: "objects"|"selections"|"all"|"public_objects"|"public_selections"] ) NOTES The default behavior is to return only object names. SEE ALSO get_type, count_atoms, count_states ''' selection = selector.process(selection) # this needs to be replaced with a flag & masking scheme... if type=='objects': mode = 1 elif type=='selections': mode = 2 elif type=='all': mode = 0 elif type=='public': mode = 3 elif type=='public_objects': mode = 4 elif type=='public_selections': mode = 5 elif type=='public_nongroup_objects': mode = 6 elif type=='public_group_objects': mode = 7 elif type=='nongroup_objects': mode = 8 elif type=='group_objects': mode = 9 else: raise pymol.CmdException("unknown type: '{}'".format(type)) with _self.lockcm: r = _cmd.get_names(_self._COb,int(mode),int(enabled_only),str(selection)) return r
def color_by_area(sele, mode="molecular", state=0, palette='rainbow', _self=cmd): """ DESCRIPTION Colors molecule by surface area ARGUMENTS sele = str: atom selection mode = str: "molecular" {default} or "solvent" """ asa = 1 if mode=="solvent" else 0 tmpObj = _self.get_unused_name("_tmp") tmpSel = _self.get_unused_name("_sel") orgSel = _self.get_unused_name("_org") orgN = _self.select(orgSel, sele, 0) _self.create(tmpObj, "byobj ?%s & ! solvent" % (orgSel), zoom=0) tmpN = _self.select(tmpSel, '?%s in ?%s' % (tmpObj, orgSel), 0) try: if orgN != tmpN: raise pymol.CmdException('color_by_area failed') _self.set("dot_solvent", asa, tmpObj) _self.set("dot_density", 3, tmpObj) l = [] _self.get_area(tmpSel, load_b=1) _self.spectrum("b", palette, tmpSel) _self.iterate(tmpSel, "l_a(color)", space={'l_a': l.append}) _self.alter(orgSel, "color=l_n()", space={'l_n': getattr(iter(l), _next_method_name)}) _self.recolor(orgSel) finally: _self.delete(tmpSel) _self.delete(tmpObj) _self.delete(orgSel)
def alignto(target='', method="cealign", selection='', quiet=1, _self=cmd, **kwargs): """ DESCRIPTION "alignto" aligns all other loaded objects to the target using the specified alignment algorithm. USAGE alignto target [, method [, quiet ]] NOTES Available alignment methods are "align", "super" and "cealign". EXAMPLE # fetch some calmodulins fetch 1cll 1sra 1ggz 1k95, async=0 # align them to 1cll using cealign alignto 1cll, method=cealign alignto 1cll, object=all_to_1cll SEE ALSO extra_fit, align, super, cealign, fit, rms, rms_cur, intra_fit """ if not selection: names = cmd.get_names("public_objects", 1) if not names: raise pymol.CmdException('no public objects') selection = '%' + ' %'.join(names) return extra_fit(selection, target, method, 0, quiet, _self, **kwargs)
def system(command, async_=0, _self=cmd, **kwargs): ''' DESCRIPTION "system" executes a command in a subshell under Unix or Windows. USAGE system command PYMOL API cmd.system(string command,int async=0) NOTES async can only be specified from the Python level (not the command language) if async is 0 (default), then the result code from "system" is returned in r if async is 1, then the command is run in a separate thread whose object is returned SEE ALSO ls, cd, pwd ''' async_ = int(kwargs.pop('async', async_)) if kwargs: raise pymol.CmdException('unknown argument: ' + ', '.join(kwargs)) r = None if async_: r = threading.Thread(target=_cmd.system,args=(str(command),1)) r.start() else: r = _cmd.system(_self._COb,str(command),0) return r # special meaning
def get_gltf(filename, quiet=1, *, _self=cmd): ''' DESCRIPTION "get_gltf" saves a gltf file representing the content currently displayed. PYMOL API cmd.get_gltf() ''' import shutil exe = shutil.which('collada2gltf') or shutil.which('COLLADA2GLTF-bin') if exe is None: raise pymol.CmdException('could not find collada2gltf') # https://github.com/schrodinger/pymol-open-source/issues/107 _self.set('collada_geometry_mode', 1, quiet=quiet) r = _self.get_collada() # write collada file with open(filename, 'w') as handle: handle.write(r) import subprocess result = subprocess.call([exe, '-i', filename, '-o', filename]) # convert collada file to gltf by using collada2gltf binary if not quiet: if result == 0: print(' Save: wrote "' + filename + '".') else: print(' Save-Error: no file written') return result
def cd(dir="~",complain=1,quiet=1): ''' DESCRIPTION "cd" changes the current working directory. USAGE cd <path> SEE ALSO pwd, ls, system ''' dir = exp_path(dir) try: os.chdir(dir) # raises on error if not quiet: print(" cd: now in %s" % getcwdu()) except BaseException as e: if complain: raise pymol.CmdException(str(e)) return DEFAULT_SUCCESS
def fab(input,name=None,mode='peptide',resi=1,chain='',segi='',state=-1, dir=1,hydro=-1,ss=0,async_=-1,quiet=1,_self=cmd, **kwargs): ''' DESCRIPTION Build a peptide ARGUMENTS input = str: sequence in one-letter code name = str: name of object to create {default: } ss = int: Secondary structure 1=alpha helix, 2=antiparallel beta, 3=parallel beta, 4=flat EXAMPLE fab ACDEFGH fab ACDEFGH, helix, ss=1 ''' async_ = int(kwargs.pop('async', async_)) if kwargs: raise pymol.CmdException('unknown argument: ' + ', '.join(kwargs)) if async_ < 1: r = _fab(input,name,mode,resi,chain,segi, state,dir,hydro,ss,quiet,_self) else: fab_thread = threading.Thread(target=_fab, args=(input,name,mode, resi,chain, segi,state,dir, hydro,ss,quiet,_self)) fab_thread.setDaemon(1) fab_thread.start() r = DEFAULT_SUCCESS return r
def attach_fragment(selection, fragment, hydrogen, anchor, *, _self=cmd): ''' ARGUMENTS selection = str: Name of a single-atom selection. If no such named selection exists, then create a new object with name `fragment`. fragment = str: fragment name to load from fragment library hydrogen = int: atom ID in fragment to fuse anchor = int: (unused) ''' remove_hydrogens = _self.get_setting_boolean("auto_remove_hydrogens") if selection not in _self.get_names("selections"): if fragment in _self.get_names("objects"): raise pymol.CmdException("an object with that name already exists") _self.fragment(fragment) if remove_hydrogens: _self.remove(f"(hydro and {fragment})") else: fragment_label = _self.get_unused_name(_prefix + "_attach_fragment") _self.fragment(fragment, fragment_label, origin=0) try: _self.fuse(f"{fragment_label} and id {hydrogen}", f"({selection})", 1) if remove_hydrogens: _self.remove("(hydro and pkmol)") elif _self.count_atoms('hydro and (neighbor pk2)'): _self.h_fill() finally: _self.delete(fragment_label)
def dumpexcel(selection='all', props='chain segi resi resn name b q', state=STATELESS): ''' DESCRIPTION Open a new Excel spreadsheet with atom property data from the given selection. ''' try: import xlwings except ImportError: raise pymol.CmdException('Requires xlwings (conda install xlwings)') try: sheet = xlwings.Book().sheets[0] except IndexError: sheet = None if not isinstance(props, (list, tuple)): props = props.split() table = [props] kwargs = { 'expression': '_append((' + ','.join(props) + '))', 'space': { '_append': table.append }, } if state == STATELESS: pymol.cmd.iterate(selection, **kwargs) else: pymol.cmd.iterate_state(state, selection, **kwargs) xlwings.view(table, sheet)
def get_gltf(filename, quiet=1, _self=cmd): ''' DESCRIPTION "get_gltf" saves a gltf file representing the content currently displayed. PYMOL API cmd.get_gltf() ''' from distutils.spawn import find_executable exe = find_executable('collada2gltf') if exe is None: raise pymol.CmdException('could not find collada2gltf') COLLADA_VERSION = 2 r = _self.get_collada(COLLADA_VERSION) # write collada file with open(filename, 'w') as handle: handle.write(r) import subprocess result = subprocess.call([exe, '-i', filename, '-o', filename]) # convert collada file to gltf by using collada2gltf binary if not quiet: if result == 0: print(' Save: wrote "' + filename + '".') else: print(' Save-Error: no file written') return result
def get_stereo_labels_schrodinger(molstr): '''R/S labels with SCHRODINGER backend ''' if 'SCHRODINGER' not in os.environ: raise pymol.CmdException('SCHRODINGER environment variable not set') import subprocess import tempfile schrun = os.path.join(os.environ['SCHRODINGER'], 'run') script = os.path.join(os.path.dirname(__file__), 'schrodinger-helper.py') filename = tempfile.mktemp('.mol') args = [schrun, script, filename] env = dict(os.environ) env.pop('PYTHONEXECUTABLE', '') # messes up on Mac with open(filename, 'w') as handle: handle.write(molstr) try: p = subprocess.Popen( args, env=env, universal_newlines=True, stdin=subprocess.PIPE, # Windows fix stderr=subprocess.PIPE, # Windows fix stdout=subprocess.PIPE) stdout, stderr = p.communicate() finally: os.unlink(filename) if stderr: print(stderr) return stdout.splitlines()
def ramp_new(name, map_name, range=[-1.0, 0.0, 1.0], color=['red', [1.0, 1.0, 1.0], 'blue'], state=1, selection='', beyond=2.0, within=6.0, sigma=2.0, zero=1, quiet=1, _self=cmd): ''' DESCRIPTION "ramp_new" creates a color ramp based on a map potential value or based on proximity to a molecular object. USAGE ramp_new name, map_name [, range [, color [, state [, selection [, beyond [, within [, sigma [, zero ]]]]]]]] ARGUMENTS name = string: name of the ramp object map_name = string: name of the map (for potential) or molecular object (for proximity) range = list: values corresponding to slots in the ramp color = list: colors corresponding to slots in the ramp state = integer: state identifier selection = selection: for automatic ranging beyond = number: with automatic ranging, are we excluding values beyond a certain distance from the selection? within = number: with automatic ranging, are we only including valuess within a certain distance from the selection? sigma = number: with automatic ranging, how many standard deviations from the mean do we go? zero = integer: with automatic ranging, do we force the central value to be zero? EXAMPLES ramp_new e_pot_color, e_pot_map, [-10,0,10], [red,white,blue] NOTES Color ramps are extremely powerful but complicated to use. In the simplest case, they can be used to color representations based on the potential values found in a map object at the corresponding positions in space. In another simple case, representations can be colored based on proximity to a target. Note that since ramp targets must themselves be real objects (not merely selections), the "create" command may be needed in order to generate an appropriate target. In more complicated cases, they can be used to color representations on one object based atoms found in another. Ramps can operate recursively. In other words, the output color from one ramp can be used as the input color for another. For example, you could color by map potential within a certain distance of the target object, beyond which, a uniform color is applied. PYMOL API def ramp_new(string name, string map_name, list range, list color, int state, string selection, float beyond, float within, float sigma, int zero, int quiet) SEE ALSO ramp_update, load, color, create, slice, gradient ''' r = DEFAULT_ERROR safe_color = str(color).strip() if (safe_color[0:1] == "["): # looks like a list color = safe_alpha_list_eval(str(safe_color)) else: # looks like a literal color = str(color) new_color = [] # preprocess selection if selection != '': selection = selector.process(selection) # coerce range try: if isinstance(range, str): range = safe_list_eval(range) range = list(map(float, range)) except: raise pymol.CmdException('invalid range') if is_list(color): for a in color: if not is_list(a): new_color.append(list(_self.get_color_tuple( a, 4))) # incl negative RGB special colors else: new_color.append(a) elif is_string(color): new_color = ramp_spectrum_dict[ramp_spectrum_sc.auto_err( str(color), 'ramp color spectrum')] else: new_color = int(color) try: _self.lock(_self) r = _cmd.ramp_new(_self._COb, str(name), str(map_name), range, new_color, int(state) - 1, str(selection), float(beyond), float(within), float(sigma), int(zero), int(quiet)) _self._invalidate_color_sc(_self) finally: _self.unlock(r, _self) if _self._raising(r, _self): raise pymol.CmdException return r
def map_generate(name, reflection_file, amplitudes, phases, weights="None", reso_low=50.0, reso_high=1.0, quiet=1, zoom=1, _self=cmd): ''' DESCRIPTION "map_generate" generates a map object from a PDB object or selection and reflection data. Experimental use with caution. USAGE map_generate name, reflection_file, amplitudes, phases, weights [, reso_low [, reso_high ]] ARGUMENTS name = string: name of the map object to create or modify reflection_file = string: name of reflection file on disk; if None, then PyMOL attempts to download the CIF file from the PDB. Default = None; attempt to download from PDB. amplitudes = string: fully qualified apmlitudes column name. Properly qualified names are: project/crysta/column. For example, KINASE/cryastl1/FWT. phases = string: fully qualified phases column name. Properly qualified names are: project/crystal/column. For example, KINASE/crystal1/DELPHWT. weights = string: fully qualified phases column name. Properly qualified names are: project/crystal/column. For example, KINASE/crystal1/FOM. reso_low = float : minimum resolution; if set to equal max_reso, then reso_low and reso_high will be read from the reflection file. reso_high = float : maximum resolution; if set to equal min_reso then reso_low and reso_high will be read from the reflection file. NOTES This function can be used to synthesize x-ray maps from the reflection data. Supported reflection file formats are "mtz". Other formats coming soon. New in PyMOL v1.4 for Mac and Linux. ''' import subprocess exe = 'mtz2ccp4_px' quiet = int(quiet) r = DEFAULT_ERROR try: _self.lock(_self) if not os.path.isfile(reflection_file): print( " MapGenerate-Error: Could not find file '%s'.\n Please check the filename and try again." % reflection_file) raise pymol.CmdException # TODO: work for CIF, MTZ, and CNS from . import headering mtzFile = headering.MTZHeader(reflection_file) # FORMAT: crystal/dataset/column _, datasetName, ampColName = ('//' + amplitudes).rsplit('/', 2) # if datasetName is empty, take any dataset that has ampColName for dataset in list(mtzFile.datasets.values()): if (not datasetName or dataset["name"] == datasetName) and \ ampColName in dataset["cols"]: break else: raise pymol.CmdException("no dataset found") cellX, cellY, cellZ = dataset['x'], dataset['y'], dataset['z'] cellAlpha, cellBeta, cellGamma = dataset['alpha'], dataset[ 'beta'], dataset['gamma'] if reso_low == reso_high: reso_low, reso_high = mtzFile.reso_min, mtzFile.reso_max space_group = mtzFile.space_group phases = phases.rsplit('/', 1)[-1] if not phases: raise pymol.CmdException("phase name missing") if weights and weights != "None": weights = weights.rsplit('/', 1)[-1] if not weights: raise pymol.CmdException( "Improperly formatted weights name") else: weights = '' if not quiet: print('Info: Generating map from columns', ampColName, phases, weights) print('Info: Resolution limits low=%.2f high=%.2f' % (reso_low, reso_high)) tempFile = tempfile.NamedTemporaryFile(delete=False) tempFileName = tempFile.name tempFile.close() r = _cmd.map_generate(_self._COb, str(name), str(reflection_file), str(tempFileName), str(ampColName), str(phases), str(weights), float(reso_low), float(reso_high), str(space_group), float(cellX), float(cellY), float(cellZ), float(cellAlpha), float(cellBeta), float(cellGamma), int(quiet), int(zoom)) # With NO_MMLIBS the C function call returns None. # Try standalone executable instead. if r is None: args = [ str(arg) for arg in [ exe, space_group, cellX, cellY, cellZ, cellAlpha, cellBeta, cellGamma, reso_high, reso_low, reflection_file, ampColName, phases, weights, tempFileName ] ] subprocess.check_call(args) r = tempFileName if r != None: if not quiet: print("Loading map '%s'" % (name)) r = _self.load(r, name, format="ccp4", finish=1) else: print(' Error: Map generation failed') os.remove(tempFileName) except OSError as e: raise pymol.CmdException('cannot run %s: %s' % (exe, e)) except subprocess.CalledProcessError as e: raise pymol.CmdException('%s failed: %s' % (exe, e)) except ImportError: print( " MapGenerate-Error: Cannot import headering module. Cannot read MTZ file or make map." ) finally: _self.unlock(r, _self) if _self._raising(r, _self): raise pymol.CmdException return name
def save(filename, selection='(all)', state=-1, format='', ref='', ref_state=-1, quiet=1, partial=0, *, _self=cmd): ''' DESCRIPTION "save" writes content to a file. USAGE save filename [, selection [, state [, format ]]] ARGUMENTS filename = string: file path to be written selection = string: atoms to save {default: (all)} state = integer: state to save {default: -1 (current state)} PYMOL API cmd.save(string file, string selection, int state, string format) NOTES The file format is automatically chosen if the extesion is one of the supported output formats: pdb, pqr, mol, sdf, pkl, pkla, mmd, out, dat, mmod, cif, pov, png, pse, psw, aln, fasta, obj, mtl, wrl, dae, idtf, or mol2. If the file format is not recognized, then a PDB file is written by default. For molecular files and where applicable and supported: * if state = -1 (default), then only the current state is written. * if state = 0, then a multi-state output file is written. SEE ALSO load, get_model ''' quiet = int(quiet) # preprocess selection selection = selector.process(selection) # r = DEFAULT_ERROR # analyze filename from pymol.importing import filename_to_format, _eval_func _, _, format_guessed, zipped = filename_to_format(filename) filename = _self.exp_path(filename) # file format if not format: if not format_guessed: raise pymol.CmdException('Unrecognized file format') format = format_guessed # PyMOL session if format in ( 'pse', 'psw', ): _self.set( "session_file", # always use unix-like path separators filename.replace("\\", "/"), quiet=1) if not quiet: print(" Save: Please wait -- writing session file...") func_type4 = { 'mmod': io.mmd.toFile, 'pkl': io.pkl.toFile, # binary pickle 'pkla': lambda model, filename: io.pkl.toFile( model, filename, bin=0), # ascii pickle } contents = None if format in savefunctions: # generic forwarding to format specific save functions func = savefunctions[format] func = _eval_func(func) kw_all = { 'filename': filename, 'selection': selection, 'name': selection, # alt (get_ccp4str) 'state': state, 'format': format, 'ref': ref, 'ref_state': ref_state, 'quiet': quiet, 'partial': partial, '_self': _self, } import inspect sig = inspect.signature(func, follow_wrapped=False) kw = {} for n, param in sig.parameters.items(): if param.kind == inspect.Parameter.VAR_KEYWORD: kw = kw_all break if param.kind == inspect.Parameter.VAR_POSITIONAL: print('FIXME: savefunctions[%s]: *args' % (format)) elif param.kind == inspect.Parameter.POSITIONAL_ONLY: raise Exception('positional-only arguments not supported') elif n in kw_all: kw[n] = kw_all[n] contents = func(**kw) if 'filename' in sig.parameters: # assume function wrote directly to file and returned a status return contents elif format in func_type4: func_type4[format](_self.get_model(selection, state, ref, ref_state), filename) r = DEFAULT_SUCCESS else: raise pymol.CmdException('File format not supported for export') # function returned sequence of strings or bytes if isinstance(contents, (tuple, list)) and contents: contents = contents[0][:0].join(contents) if cmd.is_string(contents): if not isinstance(contents, bytes): contents = contents.encode() if zipped == 'gz': import gzip fopen = gzip.open else: fopen = open if zipped == 'bz2': import bz2 contents = bz2.compress(contents) with fopen(filename, 'wb') as handle: handle.write(contents) r = DEFAULT_SUCCESS if _self._raising(r): raise QuietException if not quiet: if r == DEFAULT_SUCCESS: print(' Save: wrote "' + filename + '".') else: print(' Save-Error: no file written') return r
def multisave(filename, pattern="all", state=-1, append=0, format='', quiet=1, *, _self=cmd): ''' DESCRIPTION "multisave" will save a multi-entry PDB file. Every object in the given selection (pattern) will have a HEADER and a CRYST (if symmetry is defined) record, and is terminated with END. Loading such a multi-entry PDB file into PyMOL will load each entry as a separate object. This behavior is different to the "save" command, where a multi-object selection is written "flat" to a PDB file, without HEADER or CRYST records. ARGUMENTS filename = string: file path to be written pattern = str: atom selection (before 1.8.4: object name pattern) state = int: object state (-1=current, 0=all) {default: -1} append = 0/1: append to existing file {default: 0} format = str: file format {default: guess from extension, or 'pdb'} ''' from pymol.importing import filename_to_format _, _, format_guessed, zipped = filename_to_format(filename) if zipped: raise pymol.CmdException(zipped + ' not supported with multisave') if not format: format = format_guessed or 'pdb' if format == 'pmo': raise pymol.CmdException('pmo format not supported anymore') if format not in ('pdb', 'cif'): raise pymol.CmdException(format + ' format not supported with multisave') s = _self.get_str(format, pattern, state, '', -1, 1, quiet) if s is None: raise QuietException filename = _self.exp_path(filename) with open(filename, 'a' if int(append) else 'w') as handle: handle.write(s) return DEFAULT_SUCCESS
def png(filename, width=0, height=0, dpi=-1.0, ray=0, quiet=1, prior=0, format=0, *, _self=cmd): ''' DESCRIPTION "png" saves a PNG format image file of the current display. USAGE png filename [, width [, height [, dpi [, ray]]]] ARGUMENTS filename = string: file path to be written width = integer or string: width in pixels (without units), inches (in) or centimeters (cm). If unit suffix is given, dpi argument is required as well. If only one of width or height is given, the aspect ratio of the viewport is preserved. {default: 0 (current)} height = integer or string: height (see width) {default: 0 (current)} dpi = float: dots-per-inch {default -1.0 (unspecified)} ray = 0 or 1: should ray be run first {default: 0 (no)} EXAMPLES png image.png png image.png, dpi=300 png image.png, 10cm, dpi=300, ray=1 NOTES PNG is the only image format supported by PyMOL. SEE ALSO mpng, save PYMOL API cmd.png(string filename, int width, int height, float dpi, int ray, int quiet) ''' ray = int(ray) PRIOR_TRY = -1 PRIOR_NO = 0 PRIOR_YES = 1 prior = int(prior) assert prior in (PRIOR_TRY, PRIOR_YES, PRIOR_NO) FORMAT_GUESS = -1 FORMAT_PNG = 0 FORMAT_PPM = 1 if format == 'png': format = FORMAT_PNG assert format in (FORMAT_PNG, FORMAT_PPM, FORMAT_GUESS) if format == FORMAT_GUESS: if filename and filename.endswith(".ppm"): format = FORMAT_PPM else: format = FORMAT_PNG if filename and not filename.startswith('\x01'): if format == FORMAT_PNG and not filename.endswith(".png"): filename += ".png" filename = cmd.exp_path(filename) dpi = float(dpi) if dpi < 0: dpi = _self.get_setting_float('image_dots_per_inch') width = _unit2px(width, dpi) height = _unit2px(height, dpi) def func(): with _self.lockcm: return _cmd.png(_self._COb, filename, int(width), int(height), dpi, ray, int(quiet), prior, format) if prior: # fetch the prior image, without doing any work (fast-path / non-GLUT thread-safe) r = func() if r: return r if prior != PRIOR_TRY: raise pymol.CmdException("no prior image available") print("no prior image available, fall back to rendering") prior = PRIOR_NO if ray: return func() return _self._call_with_opengl_context(func)
def _get_mtl_obj(format, _self): # TODO mtl not implemented, always returns empty string if format == 'mtl': raise pymol.CmdException('.MTL export not implemented') i = {'mtl': 0, 'obj': 1}.get(format) return _self.get_mtl_obj()[i]
def clean(selection, present='', state=-1, fix='', restrain='', method='mmff', async_=0, save_undo=1, message=None, _self=cmd_module, **kwargs): ''' DESCRIPTION Note: This operation is limited to 999 atoms. Run energy minimization on the given selection, using an MMFF94 force field. ARGUMENTS selection = str: atom selection to minimize present = str: selection of fixed atoms to restrain the minimization state = int: object state {default: -1 (current)} fix = UNUSED restraing = UNUSED method = UNUSED async = 0/1: run in separate thread {default: 0} save_undo = UNUSED message = Message to display during async minimization EXAMPLE # minimize ligand in binding pocket clean organic, all within 8 of organic ''' if int(state) == 0: raise pymol.CmdException('cleaning all states not supported') async_ = int(kwargs.pop('async', async_)) if kwargs: raise pymol.CmdException('unknown argument: ' + ', '.join(kwargs)) args = (selection, present, state, fix, restrain, method, save_undo, message, _self) if not async_: return _clean(*args) else: try: t = threading.Thread(target=_clean, args=args) t.setDaemon(1) t.start() except: traceback.print_exc() return 0
def focal_blur(aperture=2.0, samples=10, ray=0, filename='', quiet=1, _self=cmd): ''' DESCRIPTION Creates fancy figures by introducing a focal blur to the image. The object at the origin will be in focus. USAGE focal_blur [ aperture [, samples [, ray [, filename ]]]] ARGUMENTS aperture = float: aperture angle in degrees {default: 2.0} samples = int: number of images for averaging {default: 10} ray = 0/1: {default: 0} filename = str: write image to file {default: temporary} AUTHORS Jarl Underhaug, Jason Vertrees and Thomas Holder EXAMPLES focal_blur 3.0, 50 ''' from tempfile import mkdtemp from shutil import rmtree from math import sin, cos, pi, sqrt try: import Image except ImportError: try: from PIL import Image except ImportError: raise pymol.CmdException( "Python Image Library (PIL) not available") aperture, samples = float(aperture), int(samples) ray, quiet = int(ray), int(quiet) avg = None handle_list = [] # make sure we have a still image _self.mstop() _self.unset('rock') _self.unset('text') # we need at least two samples if samples < 2: raise pymol.CmdException("need samples > 1") # Get the orientation of the camera and the light view = _self.get_view() lights_names = [ 'light', 'light2', 'light3', 'light4', 'light5', 'light6', 'light7', 'light8', 'light9' ] lights = [ _self.get_setting_tuple(lights_names[i])[1] for i in range(_self.get_setting_int('light_count') - 1) ] # Create a temporary directory tmpdir = mkdtemp() try: # Rotate the camera and the light in order to create the blur for frame in range(samples): # Populate angles as Fermat's spiral theta = frame * pi * 110.0 / 144.0 radius = 0.5 * aperture * sqrt(frame / float(samples - 1)) x = cos(theta) * radius y = sin(theta) * radius xr = x / 180.0 * pi yr = y / 180.0 * pi # Rotate the camera _self.turn('x', x) _self.turn('y', y) # Rotate the light for light, light_name in zip(lights, lights_names): ly = light[1] * cos(xr) - light[2] * sin(xr) lz = light[2] * cos(xr) + light[1] * sin(xr) lx = light[0] * cos(yr) + lz * sin(yr) lz = lz * cos(yr) - lx * sin(yr) _self.set(light_name, [lx, ly, lz]) # Save the image to temporary directory curFile = "%s/frame-%04d.png" % (tmpdir, frame) _self.png(curFile, ray=ray, quiet=1) if not quiet: print(" Created frame %i/%i (%0.0f%%)" % (frame + 1, samples, 100 * (frame + 1) / samples)) # Create the average/blured image handle = open(curFile, "rb") handle_list.append(handle) img = Image.open(handle) avg = Image.blend(avg, img, 1.0 / (frame + 1)) if avg else img del img # Return the camera and the light to the original orientation _self.set_view(view) for light, light_name in zip(lights, lights_names): _self.set(light_name, light) if not filename: filename = '%s/avg.png' % (tmpdir) # Load the blured image avg.save(filename) _self.load(filename) finally: del avg # needed for Windows for handle in handle_list: handle.close() # Delete the temporary files rmtree(tmpdir)
def extra_fit(selection='(all)', reference='', method='align', zoom=1, quiet=0, *, _self=cmd, **kwargs): ''' DESCRIPTION Like "intra_fit", but for multiple objects instead of multiple states. ARGUMENTS selection = string: atom selection of multiple objects {default: all} reference = string: reference object name {default: first object in selection} method = string: alignment method (command that takes "mobile" and "target" arguments, like "align", "super", "cealign" {default: align} ... extra arguments are passed to "method" SEE ALSO align, super, cealign, intra_fit, util.mass_align ''' zoom, quiet = int(zoom), int(quiet) sele_name = _self.get_unused_name('_') _self.select(sele_name, selection, 0) models = _self.get_object_list(sele_name) if not reference: reference = models[0] models = models[1:] elif reference in models: models.remove(reference) else: _self.select(sele_name, reference, merge=1) if _self.is_string(method): if method in _self.keyword: method = _self.keyword[method][0] else: raise pymol.CmdException(method, 'Unknown method') for model in models: x = method(mobile='?%s & ?%s' % (sele_name, model), target='?%s & ?%s' % (sele_name, reference), **kwargs) if not quiet: if _self.is_sequence(x): print('%-20s RMSD = %8.3f (%d atoms)' % (model, x[0], x[1])) elif isinstance(x, float): print('%-20s RMSD = %8.3f' % (model, x)) elif isinstance(x, dict) and 'RMSD' in x: natoms = x.get('alignment_length', 0) suffix = (' (%s atoms)' % natoms) if natoms else '' print('%-20s RMSD = %8.3f' % (model, x['RMSD']) + suffix) else: print('%-20s' % (model, )) if zoom: _self.zoom(sele_name) _self.delete(sele_name)
def callout(name, label, pos='', screen='auto', state=-1, color='front', quiet=1, _wiz=0, _self=cmd): ''' DESCRIPTION Create a new screen-stabilized callout object. ARGUMENTS name = str: object name label = str: label text pos = str or list: anchor in model space as 3-float coord list or atom selection. If empty, don't draw an arrow. {default: } screen = str or list: position on screen as 2-float list between [-1,-1] (lower left) and [1,1] (upper right) or "auto" for smart placement. {default: auto} ''' state, quiet = int(state), int(quiet) sele = '' if state == -1: state = _self.get_setting_int('state') if isinstance(pos, basestring): if ',' in pos: pos = _self.safe_list_eval(pos) else: sele, pos = pos, None if isinstance(screen, basestring): if screen == 'auto': screen = (0.0, 0.0) else: screen = _self.safe_list_eval(screen) if len(screen) == 2: screen += (0.0, ) elif len(screen) != 3: raise pymol.CmdException('invalid screen argument') if isinstance(screen[0], int): relative_mode = 2 # pixels else: relative_mode = 1 # [-1.0 .. +1.0] if not name: name = _self.get_unused_name('callout', 1) _self.pseudoatom(name, sele, 'CALL', 'CAL', str(_self.count_atoms('?' + name) + 1), 'C', 'CALL', 'PS', 0.5, color=color, label=label, pos=pos, state=state, quiet=quiet) expr = ('(' 's["label_relative_mode"],' 's["label_connector"],' 's["label_connector_color"],' 's["label_color"],' ') = (%d, %s, "default", "default",)' % ( relative_mode, bool(pos or sele), )) expr_state = ('(' 's["label_screen_point"],' ') = (%s,)' % (screen, )) _self.alter("last " + name, expr) _self.alter_state(state, "last " + name, expr_state) if int(_wiz): _self.wizard('labeledit', 'last ' + name)
def load_mtz_cctbx(filename, prefix='', amplitudes='', phases='', quiet=1, _self=pymol.cmd): ''' DESCRIPTION Load maps from an MTZ file, using iotbx (via "cctbx.python"). Map objects will be named: <prefix>_<amplitudes>_<phases> ARGUMENTS filename = str: path to mtz file prefix = str: object name prefix for new map objects amplitudes = str: amplitudes column label (optional). If not given, load all maps. If given, the 'phases' argument is required as well. phases = str: phases column label (required if and only if amplitudes is given as well) ''' import subprocess import shutil if not prefix: prefix = os.path.basename(filename).rpartition('.')[0] args = [filename, prefix, amplitudes, phases] try: # try with "cctbx.python" process = subprocess.Popen(['cctbx.python', this_file] + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() if stderr: raise pymol.CmdException(stderr) outdir = stdout.strip() if not isinstance(outdir, str): outdir = outdir.decode() except OSError: try: # try inside this Python interpreter outdir = mtz2ccp4maps(*args) except ImportError: raise pymol.CmdException( "can't import iotbx and can't run cctbx.python") # normalization is done by apply_sigma_scaling() normalize = _self.get_setting_int('normalize_ccp4_maps') if normalize: _self.set('normalize_ccp4_maps', 0) for mapfilename in os.listdir(outdir): _self.load(os.path.join(outdir, mapfilename), quiet=quiet) if normalize: _self.set('normalize_ccp4_maps', normalize) shutil.rmtree(outdir)
def set_key(key, fn=None, arg=(), kw={}, _self=cmd): ''' DESCRIPTION "set_key" binds a specific python function to a key press. New in PyMOL 1.6.1: second argument can also be a string in PyMOL command syntax. USAGE set_key key, command EXAMPLE set_key F1, as cartoon, polymer; as sticks, organic PYMOL API (ONLY) cmd.set_key( string key, function fn, tuple arg=(), dict kw={}) PYTHON EXAMPLE from pymol import cmd def color_blue(object): cmd.color("blue",object) cmd.set_key( 'F1' , color_blue, ( "object1" ) ) // would turn object1 blue when the F1 key is pressed and cmd.set_key( 'F2' , color_blue, ( "object2" ) ) // would turn object2 blue when the F2 key is pressed. cmd.set_key( 'CTRL-C' , cmd.zoom ) cmd.set_key( 'ALT-A' , cmd.turn, ('x',90) ) KEYS WHICH CAN BE REDEFINED F1 to F12 left, right, pgup, pgdn, home, insert CTRL-A to CTRL-Z ALT-0 to ALT-9, ALT-A to ALT-Z SEE ALSO button, alias ''' if fn is None: def decorator(func): set_key(key, func, arg, kw, _self) return func return decorator if is_string(fn): if arg or kw: raise ValueError('arg and kw must be empty if fn is string') else: fn = (fn, arg, kw) mod, _, pat = key.rpartition('-') if mod not in internal.modifier_keys: raise pymol.CmdException("not a valid modifier key: '%s'." % mod) if len(pat) > 1: if pat[0] != 'F': pat = pat.lower() key = pat if not mod else (mod + '-' + pat) if pat not in internal.special_key_names: raise pymol.CmdException("special '%s' key not found." % pat) elif not mod: raise pymol.CmdException("Can't map regular letters.") elif mod == 'SHFT': raise pymol.CmdException("Can't map regular letters with SHFT.") _self.key_mappings[key] = fn return DEFAULT_SUCCESS
def assign_stereo(selection='all', state=-1, method='', quiet=1, prop='stereo', _self=cmd): ''' DESCRIPTION Assign "stereo" atom property (R/S stereochemistry). Requires either a Schrodinger Suite installation (SCHRODINGER environment variable set) or RDKit (rdkit Python module). USAGE assign_stereo [selection [, state [, method ]]] ARGUMENTS selection = str: atom selection {default: all} state = int: object state {default: -1 (current)} method = schrodinger or rdkit: {default: try both} ''' state, quiet = int(state), int(quiet) # method check if method and method not in methods: raise pymol.CmdException("method '{}' not in {}".format( method, list(methods))) # alt code check alt_codes = set() cmd.iterate('({})&!alt ""'.format(selection), 'alt_codes.add(alt)', space={'alt_codes': alt_codes}) if len(alt_codes) > 1: alt_codes = sorted(alt_codes) selection = '({}) & alt +{}'.format(selection, alt_codes[0]) print(' Warning: only using first alt code of: {}'.format(alt_codes)) molstr = _self.get_str('mol', selection, state) if method: labels = methods[method](molstr) else: for method in ('rdkit', 'schrodinger'): try: labels = methods[method](molstr) except BaseException as e: print(' Method "{}" not available ({})'.format( method, str(e).strip())) else: print(' Using method={}'.format(method)) break else: raise pymol.CmdException('need SCHRODINGER or rdkit') # apply new labels _self.alter_state(state, selection, prop + ' = next(label_iter)', space={ 'label_iter': iter(labels), 'next': next })
def elbow_angle(obj, light='L', heavy='H', limit_l=107, limit_h=113, draw=0): """ DESCRIPTION Calculates the integer elbow angle of an antibody Fab complex and optionally draws a graphical representation of the vectors used to determine the angle. ARGUMENTS obj = string: object light/heavy = strings: chain ID of light and heavy chains, respectively limit_l/limit_h = integers: residue numbers of the last residue in the light and heavy chain variable domains, respectively draw = boolean: Choose whether or not to draw the angle visualization REQUIRES: com.py, transformations.py, numpy (see above) """ # store current view orig_view = cmd.get_view() limit_l = int(limit_l) limit_h = int(limit_h) draw = int(draw) # for temp object names tmp_prefix = "tmp_elbow_" prefix = tmp_prefix + obj + '_' # names vl = prefix + 'VL' vh = prefix + 'VH' cl = prefix + 'CL' ch = prefix + 'CH' # selections vl_sel = 'polymer and %s and chain %s and resi 1-%i' % (obj, light, limit_l) vh_sel = 'polymer and %s and chain %s and resi 1-%i' % (obj, heavy, limit_h) cl_sel = 'polymer and %s and chain %s and not resi 1-%i' % (obj, light, limit_l) ch_sel = 'polymer and %s and chain %s and not resi 1-%i' % (obj, heavy, limit_h) v_sel = '((' + vl_sel + ') or (' + vh_sel + '))' c_sel = '((' + cl_sel + ') or (' + ch_sel + '))' # create temp objects cmd.create(vl, vl_sel) cmd.create(vh, vh_sel) cmd.create(cl, cl_sel) cmd.create(ch, ch_sel) # superimpose vl onto vh, calculate axis and angle Rv = calc_super_matrix(vl, vh) angle_v, direction_v, point_v = transformations.rotation_from_matrix(Rv) # superimpose cl onto ch, calculate axis and angle Rc = calc_super_matrix(cl, ch) angle_c, direction_c, point_c = transformations.rotation_from_matrix(Rc) # delete temporary objects cmd.delete(vl) cmd.delete(vh) cmd.delete(cl) cmd.delete(ch) # if dot product is positive, angle is acute if (numpy.dot(direction_v, direction_c) > 0): direction_c = direction_c * -1 # ensure angle is > 90 (need to standardize this) # TODO: make both directions point away from the elbow axis. elbow = int( numpy.degrees(numpy.arccos(numpy.dot(direction_v, direction_c)))) # while (elbow < 90): # elbow = 180 - elbow # limit to physically reasonable range # compare the direction_v and direction_c axes to the vector defined by # the C-alpha atoms of limit_l and limit_h of the original fab hinge_l_sel = "%s//%s/%s/CA" % (obj, light, limit_l) hinge_h_sel = "%s//%s/%s/CA" % (obj, heavy, limit_h) try: hinge_l = cmd.get_atom_coords(hinge_l_sel) hinge_h = cmd.get_atom_coords(hinge_h_sel) except pymol.CmdException: # Either hinge_l_sel or hinge_h_sel atom did not exist. raise pymol.CmdException( 'Unable to calculate elbow angle. Please check ' 'your limit and chain selections and try again.') hinge_vec = numpy.array(hinge_h) - numpy.array(hinge_l) test = numpy.dot(hinge_vec, numpy.cross(direction_v, direction_c)) if (test > 0): elbow = 360 - elbow print(" Elbow angle: %i degrees" % elbow) if (draw == 1): # there is probably a more elegant way to do this, but # it works so I'm not going to mess with it for now pre = obj + '_elbow_' # draw hinge vector cmd.pseudoatom(pre + "hinge_l", pos=hinge_l) cmd.pseudoatom(pre + "hinge_h", pos=hinge_h) cmd.distance(pre + "hinge_vec", pre + "hinge_l", pre + "hinge_h") cmd.set("dash_gap", 0) # draw the variable domain axis com_v = COM(v_sel) start_v = [a - 10 * b for a, b in zip(com_v, direction_v)] end_v = [a + 10 * b for a, b in zip(com_v, direction_v)] cmd.pseudoatom(pre + "start_v", pos=start_v) cmd.pseudoatom(pre + "end_v", pos=end_v) cmd.distance(pre + "v_vec", pre + "start_v", pre + "end_v") # draw the constant domain axis com_c = COM(c_sel) start_c = [a - 10 * b for a, b in zip(com_c, direction_c)] end_c = [a + 10 * b for a, b in zip(com_c, direction_c)] cmd.pseudoatom(pre + "start_c", pos=start_c) cmd.pseudoatom(pre + "end_c", pos=end_c) cmd.distance(pre + "c_vec", pre + "start_c", pre + "end_c") # customize appearance cmd.hide("labels", pre + "hinge_vec") cmd.hide("labels", pre + "v_vec") cmd.hide("labels", pre + "c_vec") cmd.color("green", pre + "hinge_l") cmd.color("red", pre + "hinge_h") cmd.color("black", pre + "hinge_vec") cmd.color("black", pre + "start_v") cmd.color("black", pre + "end_v") cmd.color("black", pre + "v_vec") cmd.color("black", pre + "start_c") cmd.color("black", pre + "end_c") cmd.color("black", pre + "c_vec") # draw spheres cmd.show("spheres", pre + "hinge_l or " + pre + "hinge_h") cmd.show("spheres", pre + "start_v or " + pre + "start_c") cmd.show("spheres", pre + "end_v or " + pre + "end_c") cmd.set("sphere_scale", 2) cmd.set("dash_gap", 0, pre + "hinge_vec") cmd.set("dash_width", 5) cmd.set("dash_radius", 0.3) # group drawing objects cmd.group(pre, pre + "*") # restore original view cmd.set_view(orig_view) return 0
def attach_amino_acid(selection,amino_acid,center=0,animate=-1,object="",hydro=-1,ss=-1,_self=cmd): ''' ARGUMENTS selection = str: named selection of single N or C atom amino_acid = str: fragment name to load from fragment library center = bool: center on new terminus (pk1) animate = int: animate centering object = str: name of new object (if selection is none) hydro = int (-1/0/1): keep hydrogens ss = int: Secondary structure 1=alpha helix, 2=antiparallel beta, 3=parallel beta, 4=flat ''' # global ___total, ___seg1, ___seg2, ___seg3, ___pass, ___last # ___mark0 = ___time() # ___mark1 = ___time() # ___mark2 = ___time() # ___entry = ___time() r = DEFAULT_SUCCESS ss = int(ss) center = int(center) if hydro<0: hydro = not int(_self.get_setting_boolean("auto_remove_hydrogens")) if (selection not in _self.get_names('all') if selection == 'pk1' # legacy, calling functions should pass '?pk1' else _self.count_atoms(selection) == 0): if object == "": object = amino_acid # create new object if amino_acid in _self.get_names("objects"): raise pymol.CmdException("an object with that name already exists") r = _self.fragment(amino_acid,object) if not hydro: _self.remove("(hydro and %s)"%object) if _self.count_atoms("((%s) and name C)"%object): _self.edit("((%s) and name C)"%object) elif _self.count_atoms("((%s) and name N)"%object): _self.edit("((%s) and name N)"%object) elif _self.select(tmp_connect,"(%s) & elem N,C"%selection) != 1: _self.delete(tmp_wild) raise pymol.CmdException("invalid connection point: must be one atom, name N or C.") elif amino_acid in ["nhh","nme"] and _self.select(tmp_connect,"(%s) & elem C"%selection) != 1: _self.delete(tmp_wild) raise pymol.CmdException("invalid connection point: must be C for residue '%s'"%(amino_acid)) elif amino_acid in ["ace"] and _self.select(tmp_connect,"(%s) & elem N"%selection) != 1: _self.delete(tmp_wild) raise pymol.CmdException("invalid connection point: must be N for residue '%s'"%(amino_acid)) else: if ss<0: ss = _self.get_setting_int("secondary_structure") if ss: if ss==1: # helix phi=-57.0 psi=-47.0 elif ss==2: # antipara-beta phi=-139.0 psi=135.0 elif ss==3: # para-beta phi=-119.0 psi=113.0 else: phi=180.0 psi=180.0 _self.fragment(amino_acid,tmp_editor, origin=0) if _self.count_atoms("elem N",domain=tmp_connect): tmp = [ None ] _self.iterate(tmp_connect,"tmp[0]=resv", space={ 'tmp' : tmp }) tmp[0] = str(tmp[0]-1) # counting down _self.alter(tmp_editor,"resi=tmp[0]",space={ 'tmp' : tmp}) _self.set_geometry(tmp_connect, 3, 3) # make nitrogen planar _self.fuse("(%s and name C)"%(tmp_editor),tmp_connect,2) _self.select(tmp_domain, "byresi (pk1 | pk2)") if not hydro: _self.remove("(pkmol and hydro)") if ((_self.select(tmp1,"?pk1",domain=tmp_domain)==1) and (_self.select(tmp2,"?pk2",domain=tmp_domain)==1)): if ((_self.select(tmp3,"(name CA,CH3 & nbr. ?pk1)",domain=tmp_domain)==1) and (_self.select(tmp4,"(name CA,CH3 & nbr. ?pk2)",domain=tmp_domain)==1)): _self.set_dihedral(tmp4,tmp2,tmp1,tmp3,180.0) if hydro: _self.h_fix(tmp2) # fix hydrogen position if ss: if amino_acid[0:3]!='pro': if ((_self.select(tmp4, "(!(resn PRO) & name C & nbr. (name CA & nbr. "+tmp2+"))", domain=tmp_domain)==1) and (_self.select(tmp3, "(!(resn PRO) & name CA & nbr. "+tmp2+")", domain=tmp_domain)==1)): _self.set_dihedral( # PHI tmp4, # C tmp3, # CA tmp2, # N tmp1, # C phi) if ((_self.select(tmp4,"(name N & nbr. (name CA & nbr. "+tmp1+"))", domain=tmp_domain)==1) and (_self.select(tmp3,"(name CA & nbr. "+tmp1+")",domain=tmp_domain)==1)): _self.set_dihedral( # PSI (n-1) tmp2, # N tmp1, # C tmp3, # CA tmp4, # N psi) sele = ("(name N & (byres nbr. %s) &! (byres %s))"% (tmp_connect,tmp_connect)) if _self.select(tmp1,sele,domain=tmp_domain): _self.edit(tmp1) if center: _self.center(tmp1,animate=animate) elif _self.count_atoms("elem C",domain=tmp_connect): # forward tmp = [ None ] _self.iterate(tmp_connect,"tmp[0]=resv", space={ 'tmp' : tmp }) tmp[0] = str(tmp[0]+1) # counting up _self.alter(tmp_editor,"resi=tmp[0]",space={ 'tmp' : tmp}) _self.set_geometry(tmp_editor + " & name N", 3, 3) # make nitrogen planar _self.fuse("(%s and name N)"%tmp_editor,tmp_connect,2) _self.select(tmp_domain, "byresi (pk1 | pk2)") if not hydro: _self.remove("(pkmol and hydro)") if (( _self.select(tmp1,"?pk1",domain=tmp_domain)==1) and ( _self.select(tmp2,"?pk2",domain=tmp_domain)==1)): # ___mark1 = ___time() if ((_self.select(tmp3,"(name CA,CH3 & nbr. ?pk1)",domain=tmp_domain)==1) and (_self.select(tmp4,"(name CA,CH3 & nbr. ?pk2)",domain=tmp_domain)==1)): _self.set_dihedral(tmp4,tmp2,tmp1,tmp3,180.0) if hydro: _self.h_fix("pk1") # fix hydrogen position if ss: if hydro and amino_acid[0:3]=='nhh': # fix amide hydrogens if ((_self.select(tmp3,"(name H1 & nbr. "+tmp1+")",domain=tmp_domain)==1) and (_self.select(tmp4,"(name O & nbr. "+tmp2+")",domain=tmp_domain)==1)): _self.set_dihedral( tmp4, # O tmp2, # C tmp1, # N tmp3, # H1 180) if amino_acid[0:3]!='pro': if ((_self.select(tmp3,"(name CA & nbr. "+tmp1+")",domain=tmp_domain)==1) and (_self.select(tmp4,"(name C & nbr. (name CA & nbr. "+tmp1+"))",domain=tmp_domain)==1)): _self.set_dihedral( # PHI tmp2, # C tmp1, # N tmp3, # CA tmp4, # C phi) if ((_self.select(tmp3,"(name CA & nbr. "+tmp2+")",domain=tmp_domain)==1) and (_self.select(tmp4,"(name N & nbr. (name CA & nbr. "+tmp2+"))",domain=tmp_domain)==1)): _self.set_dihedral( # PSI (n-1) tmp4, # N tmp3, # CA tmp2, # C tmp1, # N psi) # ___mark2 = ___time() sele = ("(name C & (byres nbr. %s) & !(byres %s))"% (tmp_connect,tmp_connect)) if _self.select(tmp1,sele,domain=tmp_domain): _self.edit(tmp1) if center: _self.center(tmp1,animate=animate) else: _self.unpick() elif _self.count_atoms("((%s) and elem H)"%selection): _self.delete(tmp_wild) raise pymol.CmdException("please pick a nitrogen or carbonyl carbon to grow from.") else: _self.delete(tmp_wild) raise pymol.CmdException("unable to attach fragment.") _self.delete(tmp_wild) # ___exit = ___time() # ___seg1 = ___seg1 + ___mark1 - ___entry # ___seg2 = ___seg2 + ___mark2 - ___mark1 # ___seg3 = ___seg3 + ___exit - ___mark2 # ___total = ___total + ___exit - ___entry # ___pass = ___pass + 1 # print "%0.3f %0.3f %0.3f / %0.3f + %0.3f + %0.3f = %0.3f vs %0.3f"%(___seg1/___total,___seg2/___total,___seg3/___total, # ___seg1/___pass, ___seg2/___pass, ___seg3/___pass, # ___total/___pass, (___time()-___last) - (___exit - ___entry)) # ___last = ___time() return r