def pir(selection='(all)', wrap=70): ''' DESCRIPTION Print sequence in PIR format SEE ALSO fasta ''' from . import one_letter from chempy import cpv wrap = int(wrap) for obj in cmd.get_object_list('(' + selection + ')'): seq = [] prev_coord = None model = cmd.get_model('/%s////CA and guide and (%s)' % (obj, selection)) for atom in model.atom: if prev_coord is not None and cpv.distance(atom.coord, prev_coord) > 4.0: seq.append('/\n') prev_coord = atom.coord seq.append(one_letter.get(atom.resn, 'X')) seq.append('*') print('>P1;%s' % (obj)) print('structure:%s:%s:%s:%s:%s::::' % (obj, model.atom[0].resi,model.atom[0].chain, model.atom[-1].resi,model.atom[-1].chain)) if wrap < 1: print(''.join(seq)) continue for i in range(0, len(seq), wrap): print(''.join(seq[i:i+wrap]))
def pir(selection='(all)', wrap=70): ''' DESCRIPTION Print sequence in PIR format SEE ALSO fasta ''' from . import one_letter from chempy import cpv wrap = int(wrap) for obj in cmd.get_object_list('(' + selection + ')'): seq = [] prev_coord = None model = cmd.get_model('/%s////CA and guide and (%s)' % (obj, selection)) for atom in model.atom: if prev_coord is not None and cpv.distance(atom.coord, prev_coord) > 4.0: seq.append('/\n') prev_coord = atom.coord seq.append(one_letter.get(atom.resn, 'X')) seq.append('*') print('>P1;%s' % (obj)) print('structure:%s:%s:%s:%s:%s::::' % (obj, model.atom[0].resi, model.atom[0].chain, model.atom[-1].resi, model.atom[-1].chain)) if wrap < 1: print(''.join(seq)) continue for i in range(0, len(seq), wrap): print(''.join(seq[i:i + wrap]))
def callback(model, index, resn, coord): if cpv.distance(coord, prev) > 4.0: seq_list.append('#') idx_list.append(None) seq_list.append(one_letter.get(resn, '#')) idx_list.append((model,index)) prev[:] = coord
def callback(model, index, resn, coord): if cpv.distance(coord, prev) > 4.0: seq_list.append('#') idx_list.append(None) seq_list.append(one_letter.get(resn, '#')) idx_list.append((model, index)) prev[:] = coord
def testOrigin(self): from chempy import cpv cmd.pseudoatom('m1') cmd.pseudoatom('m2') cmd.pseudoatom('m3', pos=[1,0,0]) # by selection cmd.origin('m3') cmd.rotate('y', 90, 'm1') # by position cmd.origin(position=[-1,0,0]) cmd.rotate('y', 90, 'm2') coords = [] cmd.iterate_state(1, 'm1 m2', 'coords.append([x,y,z])', space=locals()) d = cpv.distance(*coords) self.assertAlmostEqual(d, 2 * 2**0.5)
def testOrigin(self): from chempy import cpv cmd.pseudoatom('m1') cmd.pseudoatom('m2') cmd.pseudoatom('m3', pos=[1, 0, 0]) # by selection cmd.origin('m3') cmd.rotate('y', 90, 'm1') # by position cmd.origin(position=[-1, 0, 0]) cmd.rotate('y', 90, 'm2') coords = [] cmd.iterate_state(1, 'm1 m2', 'coords.append([x,y,z])', space=locals()) d = cpv.distance(*coords) self.assertAlmostEqual(d, 2 * 2**0.5)
def _common_orientation(selection, vec, visualize=1, quiet=0): """ Common part of different helix orientation functions. Does calculate the center of mass and does the visual feedback. """ stored.x = [] cmd.iterate_state(STATE, "(%s) and name CA" % (selection), "stored.x.append([x,y,z])") if len(stored.x) < 2: print("warning: count(CA) < 2") raise CmdException center = cpv.scale(_vec_sum(stored.x), 1.0 / len(stored.x)) if visualize: scale = cpv.distance(stored.x[0], stored.x[-1]) visualize_orientation(vec, center, scale, True) cmd.zoom(selection, buffer=2) if not quiet: print("Center: (%.2f, %.2f, %.2f) Direction: (%.2f, %.2f, %.2f)" % tuple(center + vec)) return center, vec
def _common_orientation(selection, vec, visualize=1, quiet=0): ''' Common part of different helix orientation functions. Does calculate the center of mass and does the visual feedback. ''' stored.x = [] cmd.iterate_state(STATE, '(%s) and name CA' % (selection), 'stored.x.append([x,y,z])') if len(stored.x) < 2: print('warning: count(CA) < 2') raise CmdException center = cpv.scale(_vec_sum(stored.x), 1. / len(stored.x)) if visualize: scale = cpv.distance(stored.x[0], stored.x[-1]) visualize_orientation(vec, center, scale, True) cmd.zoom(selection, buffer=2) if not quiet: print('Center: (%.2f, %.2f, %.2f) Direction: (%.2f, %.2f, %.2f)' % tuple(center + vec)) return center, vec
def helix_orientation(selection, state=STATE, visualize=1, cutoff=3.5, quiet=1): ''' DESCRIPTION Get the center and direction of a helix as vectors. Will only work for alpha helices and gives slightly different results than cafit_orientation. Averages direction of C(i)->O(i)->N(i+4). USAGE helix_orientation selection [, visualize [, cutoff ]] ARGUMENTS selection = string: atom selection of helix visualize = 0 or 1: show fitted vector as arrow {default: 1} cutoff = float: maximal hydrogen bond distance {default: 3.5} SEE ALSO angle_between_helices, loop_orientation, cafit_orientation ''' state, visualize, quiet = int(state), int(visualize), int(quiet) cutoff = float(cutoff) atoms = {'C': dict(), 'O': dict(), 'N': dict()} cmd.iterate_state(state, '(%s) and name N+O+C' % (selection), 'atoms[name][resv] = x,y,z', space={'atoms': atoms}) vec_list = [] for resi in atoms['C']: resi_other = resi + 4 try: aC = atoms['C'][resi] aO = atoms['O'][resi] aN = atoms['N'][resi_other] except KeyError: continue dist = cpv.distance(aN, aO) dist_weight = 1. - (2.8 - dist) angle = cpv.get_angle_formed_by(aC, aO, aN) angle_weight = 1. - (3.1 - angle) if dist_weight > 0.0 and angle_weight > 0.0: if not quiet: print ' weight:', angle_weight * dist_weight vec = cpv.scale(cpv.sub(aN, aC), angle_weight * dist_weight) vec_list.append(vec) if len(vec_list) == 0: print 'warning: count == 0' raise CmdException center = cpv.scale(_vec_sum(atoms['O'].itervalues()), 1./len(atoms['O'])) vec = _vec_sum(vec_list) vec = cpv.normalize(vec) _common_orientation(selection, center, vec, visualize, 1.5*len(vec_list), quiet) return center, vec
def get_raw_distances(names='', state=1, selection='all', quiet=1): ''' DESCRIPTION Get the list of pair items from distance objects. Each list item is a tuple of (index1, index2, distance). Based on a script from Takanori Nakane, posted on pymol-users mailing list. http://www.mail-archive.com/[email protected]/msg10143.html ARGUMENTS names = string: names of distance objects (no wildcards!) {default: all measurement objects} state = integer: object state {default: 1} selection = string: atom selection {default: all} SEE ALSO select_distances, cmd.find_pairs, cmd.get_raw_alignment ''' from chempy import cpv state, quiet = int(state), int(quiet) if state < 1: state = cmd.get_state() valid_names = cmd.get_names_of_type('object:measurement') if names == '': names = ' '.join(valid_names) else: for name in names.split(): if name not in valid_names: print(' Error: no such distance object: ' + name) raise CmdException raw_objects = cmd.get_session(names, 1, 1, 0, 0)['names'] xyz2idx = {} cmd.iterate_state(state, selection, 'xyz2idx[x,y,z] = (model,index)', space=locals()) r = [] for obj in raw_objects: try: points = obj[5][2][state-1][1] if points is None: raise ValueError except (KeyError, ValueError): continue for i in range(0, len(points), 6): xyz1 = tuple(points[i:i+3]) xyz2 = tuple(points[i+3:i+6]) try: r.append((xyz2idx[xyz1], xyz2idx[xyz2], cpv.distance(xyz1, xyz2))) if not quiet: print(' get_raw_distances: ' + str(r[-1])) except KeyError: if quiet < 0: print(' Debug: no index for %s %s' % (xyz1, xyz2)) return r
def pmf(key, cutoff=7.0, selection1='(name CB)', selection2='', state=1, quiet=1): ''' DESCRIPTION Potential of Mean Force ARGUMENTS key = string: aaindex key cutoff = float: distance cutoff {default: 7.0} cutoff = (float, float): distance shell selection1 = string: atom selection {default: (name CB)} selection2 = string: atom selection {default: selection1} NOTES Does also support a list of keys and a list of cutoffs to deal with multiple distance shells. EXAMPLES # distance dependent c-beta contact potentials pmf SIMK990101, 5, /2x19//A//CB pmf SIMK990102, [5, 7.5], /2x19//A//CB pmf [SIMK990101, SIMK990102, SIMK990103], [0, 5, 7.5, 10], /2x19//A//CB # interface potential sidechaincenters 2x19_scc, 2x19 pmf KESO980102, 7.0, /2x19_scc//A, /2x19_scc//B distance /2x19_scc//A, /2x19_scc//B, cutoff=7.0 ''' from pymol import cmd, stored from chempy import cpv if cmd.is_string(key): if key.lstrip().startswith('['): key = cmd.safe_alpha_list_eval(key) else: key = [key] if cmd.is_string(cutoff): cutoff = eval(cutoff) if not cmd.is_sequence(cutoff): cutoff = [cutoff] if len(cutoff) == len(key): cutoff = [0.0] + list(cutoff) if len(cutoff) != len(key) + 1: print 'Error: Number of keys and number of cutoffs inconsistent' return state = int(state) quiet = int(quiet) if len(selection2) == 0: selection2 = selection1 if not quiet and len(key) > 1: print 'Distance shells:' for i in range(len(key)): print '%s %.1f-%.1f' % (key[i], cutoff[i], cutoff[i + 1]) idmap = dict() cmd.iterate_state(state, '(%s) or (%s)' % (selection1, selection2), 'idmap[model,index] = [(resn,name),(x,y,z)]', space={'idmap': idmap}) twoN = cmd.count_atoms(selection1) + cmd.count_atoms(selection2) pairs = cmd.find_pairs(selection1, selection2, cutoff=max(cutoff), state1=state, state2=state) if len(pairs) == 0: print 'Empty pair list' return 0.0 matrix = map(get, key) for i in matrix: assert isinstance(i, MatrixRecord) i_list = range(len(key)) u_sum = 0 count = 0 for id1, id2 in pairs: a1 = idmap[id1] a2 = idmap[id2] r = cpv.distance(a1[1], a2[1]) for i in i_list: if cutoff[i] <= r and r < cutoff[i + 1]: try: aa1 = to_one_letter_code[a1[0][0]] aa2 = to_one_letter_code[a2[0][0]] u_sum += matrix[i].get(aa1, aa2) count += 1 except: print 'Failed for', a1[0], a2[0] value = float(u_sum) / twoN if not quiet: print 'PMF: %.4f (%d contacts, %d residues)' % (value, count, twoN) return value
def delaunay(selection='enabled', name=None, cutoff=10.0, as_cgo=0, qdelaunay_exe='qdelaunay', state=-1, quiet=1): ''' DESCRIPTION Full-atom Delaunay Tessalator Creates either a molecular object with delaunay edges as bonds, or a CGO object with edge colors according to edge length. USAGE delaunay [ selection [, name [, cutoff=10.0 [, as_cgo=0 ]]]] SEE ALSO PyDeT plugin: http://pymolwiki.org/index.php/PyDet ''' from chempy import cpv, Bond if name is None: name = cmd.get_unused_name('delaunay') cutoff = float(cutoff) as_cgo = int(as_cgo) state, quiet = int(state), int(quiet) if state < 1: state = cmd.get_state() model = cmd.get_model(selection, state) regions_iter = qdelaunay((a.coord for a in model.atom), 3, len(model.atom), qdelaunay_exe=qdelaunay_exe) edges = set(tuple(sorted([region[i-1], region[i]])) for region in regions_iter for i in range(len(region))) edgelist=[] r = [] minco = 9999 maxco = 0 for edge in edges: ii, jj = edge a = model.atom[ii] b = model.atom[jj] co = cpv.distance(a.coord, b.coord) if cutoff > 0.0 and co > cutoff: continue if as_cgo: minco=min(co,minco) maxco=max(co,maxco) edgelist.append(a.coord + b.coord + [co]) else: bnd = Bond() bnd.index = [ii, jj] model.add_bond(bnd) r.append((a,b,co)) if not as_cgo: cmd.load_model(model, name, 1) return r from pymol.cgo import CYLINDER difco = maxco-minco obj = [] mm = lambda x: max(min(x, 1.0), 0.0) for e in edgelist: co = ((e[6]-minco)/difco)**(0.75) color = [mm(1-2*co), mm(1-abs(2*co-1)), mm(2*co-1)] obj.extend([CYLINDER] + e[0:6] + [0.05] + color + color) cmd.load_cgo(obj, name) return r
def get_raw_distances(names='', state=1, selection='all', fc=2.0, amber=0, gro=0, label='ID', quiet=1, *, _self=cmd): ''' DESCRIPTION Get the list of pair items from distance objects. Each list item is a tuple of (ID1, ID2, distance). Based on a script from Takanori Nakane, posted on pymol-users mailing list. http://www.mail-archive.com/[email protected]/msg10143.html ARGUMENTS names = string: names of distance objects (no wildcards!) {default: all measurement objects} state = integer: object state {default: 1} selection = string: atom selection {default: all} amber = integer: generate AMBER rst file {default: 0} gro = integer: generate GROMACS rst file {default: 0} label = string: label type ('ID' or 'index') {default: ID} SEE ALSO select_distances, cmd.find_pairs, cmd.get_raw_alignment ''' from chempy import cpv state, quiet, fc = int(state), int(quiet), float(fc) if state < 1: state = _self.get_state() valid_names = _self.get_names_of_type('object:measurement') if names == '': names = ' '.join(valid_names) else: for name in names.split(): if name not in valid_names: print(' Error: no such distance object: ' + name) raise CmdException raw_objects = _self.get_session(names, 1, 1, 0, 0)['names'] xyz2idx = {} cmd.iterate_state(state, selection, 'xyz2idx[x,y,z] = (model, resi, resn, name, ' + label + ')', space=locals()) r = [] for obj in raw_objects: try: points = obj[5][2][state - 1][1] if points is None: raise ValueError except (KeyError, ValueError): continue for i in range(0, len(points), 6): xyz1 = tuple(points[i:i + 3]) xyz2 = tuple(points[i + 3:i + 6]) try: r.append( (xyz2idx[xyz1], xyz2idx[xyz2], cpv.distance(xyz1, xyz2))) if not quiet: print(' get_raw_distances: ' + str(r[-1])) except KeyError: if quiet < 0: print(' Debug: no index for %s %s' % (xyz1, xyz2)) # print(r) # for generate amber MD restraint file. if (int(amber)): for i in r: print("""# {0}{1} {2} - {3}{4} {5} &rst iat={6}, {7}, r1=0, r2=0.5, r3={8:.2f}, r4=8, rk2={9}, rk3={9}, /""".format(str(i[0][1]), str(i[0][2]), str(i[0][3]), str(i[1][1]), str(i[1][2]), str(i[1][3]), str(i[0][4]), str(i[1][4]), float(i[2]), float(fc))) # for generate GROMACS MD restraint file. if (int(gro)): for i in r: print( "{6} {7} 10 0.00 {8:.3f} 0.800 800 ; {0}{1} {2} - {3}{4} {5} 2kcal/mol/A2" .format(str(i[0][1]), str(i[0][2]), str(i[0][3]), str(i[1][1]), str(i[1][2]), str(i[1][3]), str(i[0][4]), str(i[1][4]), float(i[2]) / 10)) return r
def colorbyrmsd(mobile, target, doAlign=1, doPretty=1, guide=1, method='super', quiet=1): ''' DESCRIPTION Align two structures and show the structural deviations in color to more easily see variable regions. Colors each mobile/target atom-pair by distance (the name is a bit misleading). Modifies the B-factor columns in your original structures. ARGUMENTS mobile = string: atom selection for mobile atoms target = string: atom selection for target atoms doAlign = 0 or 1: Superpose selections before calculating distances {default: 1} doPretty = 0 or 1: Show nice representation and colors {default: 1} EXAMPLE fetch 1ake 4ake, async=0 remove chain B colorbyrmsd 1ake, 4ake ''' from chempy import cpv # import pdb doAlign, doPretty = int(doAlign), int(doPretty) guide, quiet = int(guide), int(quiet) aln, seleboth = '_aln', '_objSelBoth' try: align = cmd.keyword[method][0] except: print ' Error: no such method:', method raise CmdException if guide: mobile = '(%s) and guide' % mobile target = '(%s) and guide' % target try: if doAlign: # superpose zz=align(mobile, target, object=aln) else: # get alignment without superposing zz=align(mobile, target, cycles=0, transform=0, object=aln) if not quiet: print "RMSD = ", zz[0] except: print ' Error: Alignment with method %s failed' % (method) raise CmdException cmd.select(seleboth, '(%s) or (%s)' % (mobile, target)) idx2coords = dict() cmd.iterate_state(-1, seleboth, 'idx2coords[model,index] = (x,y,z)', space=locals()) if cmd.count_atoms('?' + aln, 1, 1) == 0: # this should ensure that "aln" will be available as selectable object cmd.refresh() b_dict = dict() for col in cmd.get_raw_alignment(aln): assert len(col) == 2 b = cpv.distance(idx2coords[col[0]], idx2coords[col[1]]) for idx in col: b_dict[idx] = b #pdb.set_trace() cmd.alter(seleboth, 'b = b_dict.get((model, index), -1)', space=locals()) if doPretty: cmd.orient(seleboth) cmd.show_as('cartoon', 'byobj ' + seleboth) cmd.color('gray', seleboth) cmd.spectrum('b', 'blue_red', seleboth + ' and b > -0.5') if not quiet: print " ColorByRMSD: Minimum Distance: %.2f" % (min(b_dict.values())) print " ColorByRMSD: Maximum Distance: %.2f" % (max(b_dict.values())) print " ColorByRMSD: Average Distance: %.2f" % (sum(b_dict.values()) / len(b_dict)) cmd.delete(aln) cmd.delete(seleboth)
def distancetoatom(origin='pk1', cutoff=10, filename=None, selection='all', state=0, property_name='p.dist', coordinates=0, decimals=3, sort=1, quiet=1): ''' DESCRIPTION distancetoatom.py Described at: http://www.pymolwiki.org/Distancetoatom Prints all distanced between the specified atom/coordinate/center and all atoms within cutoff distance that are part of the selection. All coordinates and distances can be saved in a csv-style text file report and can be appended to a (custom) atom property, if defined. USAGE distancetoatom [ origin [, cutoff [, filename [, selection [, state [, property_name [, coordinates [, decimals [, sort [, quiet ]]]]]]]]]] ARGUMENTS NAME TYPE FUNCTION origin: <list> defines the coordinates for the origin and can be: <str> 1. a list with coordinates [x,y,z] 2. a single atom selection string {default='pk1'} 3. a multi-atom selection string (center will be used) cutoff <float> sets the maximum distance {default: 10} filename <str> filename for optional output report. {default=None} set to e.g. 'report.txt' to create a report (omit or set to '', None, 0 or False to disable) selection <str> can be used to define/limit the measurment to specific sub-selections {default='all'} state <int> object state, {default=0} # = current property_name <str> the distance will be stored in this property {p.dist} set "" to disable coordinates <int> toggle whether atom coordinated will be reported {0} decimals <int> decimals for coordinates and distance: default = 3 # = max. PDB resolution sort <int> Sorting by distance? 1: ascending (default) 0: no sorting (by names) -1: descending quiet <bool> toggle verbosity ''' # keyword check try: selection = '(%s)' % selection ori = get_coord(origin) if not ori: print("distancetoatom: aborting - check input for 'origin'!") return False cutoff = abs(float(cutoff)) filename = str(filename) state = abs(int(state)) if (not int(state)): state = cmd.get_state() cmd.set('state', state) # distance by state property_name = str(property_name) decimals = abs(int(decimals)) sort = int(sort) coordinates = bool(int(coordinates)) quiet = bool(int(quiet)) except: print('distancetoatom: aborting - input error!') return False # round origin ori = [round(x, decimals) for x in ori] # report? if filename in ['', '0', 'False', 'None']: filename = False else: try: report = open(filename, 'w') # file for writing except: print('distancetoatom: Unable to open report file! - Aborting!') return False # temporary name for pseudoatom tempname = cmd.get_unused_name('temp_name') tempsel = cmd.get_unused_name('temp_sel') #origin cmd.pseudoatom(object=tempname, resi=1, pos=ori) # select atoms within cutoff cmd.select( tempsel, '(%s around %f) and (%s) and state %d' % (tempname, cutoff, selection, state)) cmd.delete(tempname) # single atom ori and part of selection # avoid double reporting! single_atom_ori = False try: if cmd.count_atoms('(%s) and (%s) and (%s)' % (selection, tempsel, origin)) == 1: single_atom_ori = True except: pass # pass= coordinates or multi-atom or single, not selected --> report ori # atom list stored.temp = [] cmd.iterate( tempsel, 'stored.temp.append([model, segi, chain, resn, resi, name, alt])') # custom properties? # conditional disabling if (property_name == ''): property_name = False if ((cmd.get_version()[1] < 1.7) and (property_name not in ['b', 'q'])): property_name = False # calculate the distances, creating list distance_list = [] if (not single_atom_ori): distance_list.append( ['ORIGIN: ' + str(origin), ori[0], ori[1], ori[2], 0.0]) for atom in stored.temp: atom_name = ( '/%s/%s/%s/%s`%s/%s`%s' % (atom[0], atom[1], atom[2], atom[3], atom[4], atom[5], atom[6])) atom_xyz = [round(x, decimals) for x in cmd.get_atom_coords(atom_name)] atom_dist = round(cpv.distance(ori, atom_xyz), decimals) distance_list.append( [atom_name, atom_xyz[0], atom_xyz[1], atom_xyz[2], atom_dist]) # create property with distance (can be used for coloring, labeling etc) if property_name: try: cmd.alter(atom_name, '%s=%f' % (property_name, atom_dist)) except: # I'm not sure alter raises exceptions if the property is illegal property_name = False # sort list, if selected if sort > 0: distance_list.sort(key=lambda dist: dist[4]) elif sort < 0: distance_list.sort(key=lambda dist: dist[4], reverse=True) # add header distance_list = [[ 'Atom Macro ID', 'x-coord', 'y-coord', 'z-coord', 'distance_to_origin' ]] + distance_list if ((not quiet) and (filename)): # Hijack stdout to print to file and console class logboth(object): def __init__(self, *files): self.files = files def write(self, obj): for f in self.files: f.write(obj) originalstdout = sys.stdout sys.stdout = logboth(sys.stdout, report) for entry in distance_list: if coordinates: output = '%s, %s, %s, %s, %s' % ( entry[0], entry[1], entry[2], entry[3], entry[4]) #csv style else: output = '%s, %s' % (entry[0], entry[4]) #csv style if (not quiet): print(output) elif filename: report.write(output + '\n') # restore regular stdout if ((not quiet) and (filename)): sys.stdout = originalstdout # close file if filename: report.close() if (not quiet): if property_name: print('Distances saved to property: %s' % str(property_name)) else: print('Distances NOT saved to property (illegal custom property)') # remove temp. selection cmd.delete(tempsel) # return list for potential use: if coordinates: if len(distance_list) > 2: # prevents crash if list is otherwise empty distance_list2 = list(map(distance_list.__getitem__, [1, 4])) return distance_list2 else: return distance_list else: return distance_list
def bbPlane(objSel='(all)', color='white', transp=0.0): """ DESCRIPTION Draws a plane across the backbone for a selection ARGUMENTS objSel = string: protein object or selection {default: (all)} color = string: color name or number {default: white} transp = float: transparency component (0.0--1.0) {default: 0.0} NOTES You need to pass in an object or selection with at least two amino acids. The plane spans CA_i, O_i, N-H_(i+1), and CA_(i+1) """ # format input transp = float(transp) stored.AAs = [] coords = dict() # need hydrogens on peptide nitrogen cmd.h_add('(%s) and n. N' % objSel) # get the list of residue ids for obj in cmd.get_object_list(objSel): sel = obj + " and (" + objSel + ")" for a in cmd.get_model(sel + " and n. CA").atom: key = '/%s/%s/%s/%s' % (obj,a.segi,a.chain,a.resi) stored.AAs.append(key) coords[key] = [a.coord,None,None] for a in cmd.get_model(sel + " and n. O").atom: key = '/%s/%s/%s/%s' % (obj,a.segi,a.chain,a.resi) if key in coords: coords[key][1] = a.coord for a in cmd.get_model("(hydro or n. CD) and nbr. (" + sel + " and n. N)").atom: key = '/%s/%s/%s/%s' % (obj,a.segi,a.chain,a.resi) if key in coords: coords[key][2] = a.coord # need at least two amino acids if len(stored.AAs) <= 1: print "ERROR: Please provide at least two amino acids, the alpha-carbon on the 2nd is needed." return # prepare the cgo obj = [ BEGIN, TRIANGLES, COLOR, ] obj.extend(cmd.get_color_tuple(color)) for res in range(0, len(stored.AAs)-1): curIdx, nextIdx = str(stored.AAs[res]), str(stored.AAs[res+1]) # populate the position array pos = [coords[curIdx][0], coords[curIdx][1], coords[nextIdx][2], coords[nextIdx][0]] # if the data are incomplete for any residues, ignore if None in pos: print 'peptide bond %s -> %s incomplete' % (curIdx, nextIdx) continue if cpv.distance(pos[0], pos[3]) > 4.0: print '%s and %s not adjacent' % (curIdx, nextIdx) continue # fill in the vertex data for the triangles; for i in [0,1,2,3,2,1]: obj.append(VERTEX) obj.extend(pos[i]) # finish the CGO obj.append(END) # update the UI newName = cmd.get_unused_name("backbonePlane") cmd.load_cgo(obj, newName) cmd.set("cgo_transparency", transp, newName)
def cgo_modevec(atom1='pk1', atom2='pk2', radius=0.05, gap=0.0, hlength=-1, hradius=-1, color='green', name='',scalefactor=10.0, cutoff=0.6, transparency=1.0): #was 0.6cut 12 scale ## scalefactor was 10.0 ''' DESCRIPTION Create a CGO mode vector starting at atom1 and pointint in atom2 displacement ARGUMENTS atom1 = string: single atom selection or list of 3 floats {default: pk1} atom2 = string: displacement to atom1 for modevec radius = float: arrow radius {default: 0.5} gap = float: gap between arrow tips and the two atoms {default: 0.0} hlength = float: length of head hradius = float: radius of head color = string: one or two color names {default: blue red} name = string: name of CGO object scalefactor = scale how big of an arrow to make. Default 5 transparency = 0.0 ~ 1.0, default=1.0 means being totally opaque ''' from chempy import cpv radius, gap = float(radius), float(gap) hlength, hradius = float(hlength), float(hradius) scalefactor, cutoff = float(scalefactor), float(cutoff) transparency = float(transparency) try: color1, color2 = color.split() except: color1 = color2 = color color1 = list(cmd.get_color_tuple(color1)) color2 = list(cmd.get_color_tuple(color2)) def get_coord(v): if not isinstance(v, str): return v if v.startswith('['): return cmd.safe_list_eval(v) return cmd.get_atom_coords(v) xyz1 = get_coord(atom1) xyz2 = get_coord(atom2) newxyz2 = cpv.scale(xyz2, scalefactor) newxyz2 = cpv.add(newxyz2, xyz1) xyz2 = newxyz2 # xyz2 = xyz2[0]*scalefactor, xyz2[1]*scalefactor, xyz2[2]*scalefactor normal = cpv.normalize(cpv.sub(xyz1, xyz2)) if hlength < 0: hlength = radius * 3.0 if hradius < 0: hradius = hlength * 0.6 if gap: diff = cpv.scale(normal, gap) xyz1 = cpv.sub(xyz1, diff) xyz2 = cpv.add(xyz2, diff) xyz3 = cpv.add(cpv.scale(normal, hlength), xyz2) # dont draw arrow if distance is too small distance = cpv.distance(xyz1, xyz2) if distance <= cutoff: return #### generate transparent arrows; #### The original codes are the next block #### --Ran obj = [25.0, transparency, 9.0] + xyz1 + xyz3 + [radius] + color1 + color2 + \ [25.0, transparency, 27.0] + xyz3 + xyz2 + [hradius, 0.0] + color2 + color2 + \ [1.0, 0.0] # obj = [cgo.CYLINDER] + xyz1 + xyz3 + [radius] + color1 + color2 + \ # [cgo.CONE] + xyz3 + xyz2 + [hradius, 0.0] + color2 + color2 + \ # [1.0, 0.0] if not name: name = cmd.get_unused_name('arrow') cmd.load_cgo(obj, name)
def angle_between_domains(selection1, selection2, method='align', state1=STATE, state2=STATE, visualize=1, quiet=1): ''' DESCRIPTION Angle by which a molecular selection would be rotated when superposing on a selection2. Do not use for measuring angle between helices, since the alignment of the helices might involve a rotation around the helix axis, which will result in a larger angle compared to the angle between helix axes. USAGE angle_between_domains selection1, selection2 [, method ] ARGUMENTS selection1 = string: atom selection of first helix selection2 = string: atom selection of second helix method = string: alignment command like "align" or "super" {default: align} EXAMPLE fetch 3iplA 3iplB, bsync=0 select domain1, resi 1-391 select domain2, resi 392-475 align 3iplA and domain1, 3iplB and domain1 angle_between_domains 3iplA and domain2, 3iplB and domain2 SEE ALSO align, super, angle_between_helices ''' import math try: import numpy except ImportError: print(' Error: numpy not available') raise CmdException state1, state2 = int(state1), int(state2) visualize, quiet = int(visualize), int(quiet) if cmd.is_string(method): try: method = cmd.keyword[method][0] except KeyError: print('no such method:', method) raise CmdException mobile_tmp = get_unused_name('_') cmd.create(mobile_tmp, selection1, state1, 1, zoom=0) try: method(mobile=mobile_tmp, target=selection2, mobile_state=1, target_state=state2, quiet=quiet) mat = cmd.get_object_matrix(mobile_tmp) except: print(' Error: superposition with method "%s" failed' % (method.__name__)) raise CmdException finally: cmd.delete(mobile_tmp) try: # Based on transformations.rotation_from_matrix # Copyright (c) 2006-2012, Christoph Gohlke R33 = [mat[i:i + 3] for i in [0, 4, 8]] R33 = numpy.array(R33, float) # direction: unit eigenvector of R33 corresponding to eigenvalue of 1 w, W = numpy.linalg.eig(R33.T) i = w.real.argmax() direction = W[:, i].real # rotation angle depending on direction m = direction.argmax() i, j, k, l = [[2, 1, 1, 2], [0, 2, 0, 2], [1, 0, 0, 1]][m] cosa = (R33.trace() - 1.0) / 2.0 sina = (R33[i, j] + (cosa - 1.0) * direction[k] * direction[l]) / direction[m] angle = math.atan2(sina, cosa) angle = abs(math.degrees(angle)) except: print(' Error: rotation from matrix failed') raise CmdException if not quiet: try: # make this import optional to support running this script standalone from .querying import centerofmass, gyradius except (ValueError, ImportError): gyradius = None try: # PyMOL 1.7.1.6+ centerofmass = cmd.centerofmass except AttributeError: centerofmass = lambda s: cpv.scale(cpv.add(*cmd.get_extent(s)), 0.5) center1 = centerofmass(selection1) center2 = centerofmass(selection2) print(' Angle: %.2f deg, Displacement: %.2f angstrom' % (angle, cpv.distance(center1, center2))) if visualize: center1 = numpy.array(center1, float) center2 = numpy.array(center2, float) center = (center1 + center2) / 2.0 if gyradius is not None: rg = numpy.array(gyradius(selection1), float) else: rg = 10.0 h1 = numpy.cross(center2 - center1, direction) h2 = numpy.dot(R33, h1) h1 *= rg / cpv.length(h1) h2 *= rg / cpv.length(h2) for pos in [center1, center2, center1 + h1, center1 + h2]: cmd.pseudoatom(mobile_tmp, pos=list(pos), state=1) # measurement object for angle and displacement name = get_unused_name('measurement') cmd.distance(name, *['%s`%d' % (mobile_tmp, i) for i in [1, 2]]) cmd.angle(name, *['%s`%d' % (mobile_tmp, i) for i in [3, 1, 4]]) # CGO arrow for axis of rotation visualize_orientation(direction, center1, rg, color='blue') cmd.delete(mobile_tmp) return angle
def pmf(key, cutoff=7.0, selection1='(name CB)', selection2='', state=1, quiet=1): ''' DESCRIPTION Potential of Mean Force ARGUMENTS key = string: aaindex key cutoff = float: distance cutoff {default: 7.0} cutoff = (float, float): distance shell selection1 = string: atom selection {default: (name CB)} selection2 = string: atom selection {default: selection1} NOTES Does also support a list of keys and a list of cutoffs to deal with multiple distance shells. EXAMPLES # distance dependent c-beta contact potentials pmf SIMK990101, 5, /2x19//A//CB pmf SIMK990102, [5, 7.5], /2x19//A//CB pmf [SIMK990101, SIMK990102, SIMK990103], [0, 5, 7.5, 10], /2x19//A//CB # interface potential sidechaincenters 2x19_scc, 2x19 pmf KESO980102, 7.0, /2x19_scc//A, /2x19_scc//B distance /2x19_scc//A, /2x19_scc//B, cutoff=7.0 ''' from pymol import cmd, stored from chempy import cpv if cmd.is_string(key): if key.lstrip().startswith('['): key = cmd.safe_alpha_list_eval(key) else: key = [key] if cmd.is_string(cutoff): cutoff = eval(cutoff) if not cmd.is_sequence(cutoff): cutoff = [cutoff] if len(cutoff) == len(key): cutoff = [0.0] + list(cutoff) if len(cutoff) != len(key) + 1: print('Error: Number of keys and number of cutoffs inconsistent') return state = int(state) quiet = int(quiet) if len(selection2) == 0: selection2 = selection1 if not quiet and len(key) > 1: print('Distance shells:') for i in range(len(key)): print('%s %.1f-%.1f' % (key[i], cutoff[i], cutoff[i + 1])) idmap = dict() cmd.iterate_state(state, '(%s) or (%s)' % (selection1, selection2), 'idmap[model,index] = [(resn,name),(x,y,z)]', space={'idmap': idmap}) twoN = cmd.count_atoms(selection1) + cmd.count_atoms(selection2) pairs = cmd.find_pairs(selection1, selection2, cutoff=max(cutoff), state1=state, state2=state) if len(pairs) == 0: print('Empty pair list') return 0.0 matrix = list(map(get, key)) for i in matrix: assert isinstance(i, MatrixRecord) i_list = list(range(len(key))) u_sum = 0 count = 0 for id1, id2 in pairs: a1 = idmap[id1] a2 = idmap[id2] r = cpv.distance(a1[1], a2[1]) for i in i_list: if cutoff[i] <= r and r < cutoff[i + 1]: try: aa1 = to_one_letter_code[a1[0][0]] aa2 = to_one_letter_code[a2[0][0]] u_sum += matrix[i].get(aa1, aa2) count += 1 except: print('Failed for', a1[0], a2[0]) value = float(u_sum) / twoN if not quiet: print('PMF: %.4f (%d contacts, %d residues)' % (value, count, twoN)) return value
def delaunay(selection='enabled', name=None, cutoff=10.0, as_cgo=0, qdelaunay_exe='qdelaunay', state=-1, quiet=1, *, _self=cmd): ''' DESCRIPTION Full-atom Delaunay Tessalator Creates either a molecular object with delaunay edges as bonds, or a CGO object with edge colors according to edge length. USAGE delaunay [ selection [, name [, cutoff=10.0 [, as_cgo=0 ]]]] SEE ALSO PyDeT plugin: http://pymolwiki.org/index.php/PyDet ''' from chempy import cpv, Bond if name is None: name = _self.get_unused_name('delaunay') cutoff = float(cutoff) as_cgo = int(as_cgo) state, quiet = int(state), int(quiet) if state < 1: state = _self.get_state() model = _self.get_model(selection, state) regions_iter = qdelaunay((a.coord for a in model.atom), 3, len(model.atom), qdelaunay_exe=qdelaunay_exe) edges = set( tuple(sorted([region[i - 1], region[i]])) for region in regions_iter for i in range(len(region))) edgelist = [] r = [] minco = 9999 maxco = 0 for edge in edges: ii, jj = edge a = model.atom[ii] b = model.atom[jj] co = cpv.distance(a.coord, b.coord) if cutoff > 0.0 and co > cutoff: continue if as_cgo: minco = min(co, minco) maxco = max(co, maxco) edgelist.append(a.coord + b.coord + [co]) else: bnd = Bond() bnd.index = [ii, jj] model.add_bond(bnd) r.append((a, b, co)) if not as_cgo: _self.load_model(model, name, 1) return r from pymol.cgo import CYLINDER difco = maxco - minco obj = [] mm = lambda x: max(min(x, 1.0), 0.0) for e in edgelist: co = ((e[6] - minco) / difco)**(0.75) color = [mm(1 - 2 * co), mm(1 - abs(2 * co - 1)), mm(2 * co - 1)] obj.extend([CYLINDER] + e[0:6] + [0.05] + color + color) _self.load_cgo(obj, name) return r
def distancetoatom( origin='pk1', cutoff=10, filename=None, selection='all', state=0, property_name='p.dist', coordinates=0, decimals=3, sort=1, quiet=1 ): ''' DESCRIPTION distancetoatom.py Described at: http://www.pymolwiki.org/Distancetoatom Prints all distanced between the specified atom/coordinate/center and all atoms within cutoff distance that are part of the selection. All coordinates and distances can be saved in a csv-style text file report and can be appended to a (custom) atom property, if defined. USAGE distancetoatom [ origin [, cutoff [, filename [, selection [, state [, property_name [, coordinates [, decimals [, sort [, quiet ]]]]]]]]]] ARGUMENTS NAME TYPE FUNCTION origin: <list> defines the coordinates for the origin and can be: <str> 1. a list with coordinates [x,y,z] 2. a single atom selection string {default='pk1'} 3. a multi-atom selection string (center will be used) cutoff <float> sets the maximum distance {default: 10} filename <str> filename for optional output report. {default=None} set to e.g. 'report.txt' to create a report (omit or set to '', None, 0 or False to disable) selection <str> can be used to define/limit the measurment to specific sub-selections {default='all'} state <int> object state, {default=0} # = current property_name <str> the distance will be stored in this property {p.dist} set "" to disable coordinates <int> toggle whether atom coordinated will be reported {0} decimals <int> decimals for coordinates and distance: default = 3 # = max. PDB resolution sort <int> Sorting by distance? 1: ascending (default) 0: no sorting (by names) -1: descending quiet <bool> toggle verbosity ''' # keyword check try: selection = '(%s)'%selection ori=get_coord(origin) if not ori: print "distancetoatom: aborting - check input for 'origin'!" return False cutoff = abs(float(cutoff)) filename = str(filename) state = abs(int(state)) if (not int(state)): state=cmd.get_state() cmd.set('state', state) # distance by state property_name = str(property_name) decimals = abs(int(decimals)) sort = int(sort) coordinates=bool(int(coordinates)) quiet=bool(int(quiet)) except: print 'distancetoatom: aborting - input error!' return False # round origin ori = [round(x,decimals) for x in ori] # report? if filename in ['', '0', 'False', 'None']: filename=False else: try: report=open(filename,'w') # file for writing except: print 'distancetoatom: Unable to open report file! - Aborting!' return False # temporary name for pseudoatom tempname = cmd.get_unused_name('temp_name') tempsel = cmd.get_unused_name('temp_sel') #origin cmd.pseudoatom(object=tempname, resi=1, pos=ori) # select atoms within cutoff cmd.select(tempsel, '(%s around %f) and (%s) and state %d' %(tempname, cutoff, selection, state)) cmd.delete(tempname) # single atom ori and part of selection # avoid double reporting! single_atom_ori=False try: if cmd.count_atoms('(%s) and (%s) and (%s)'%(selection, tempsel, origin))==1: single_atom_ori=True except: pass # pass= coordinates or multi-atom or single, not selected --> report ori # atom list stored.temp=[] cmd.iterate(tempsel, 'stored.temp.append([model, segi, chain, resn, resi, name, alt])') # custom properties? # conditional disabling if (property_name==''): property_name=False if ((cmd.get_version()[1]<1.7) and (property_name not in ['b','q'])): property_name=False # calculate the distances, creating list distance_list=[] if (not single_atom_ori): distance_list.append(['ORIGIN: '+str(origin), ori[0], ori[1], ori[2], 0.0]) for atom in stored.temp: atom_name = ('/%s/%s/%s/%s`%s/%s`%s'%(atom[0], atom[1], atom[2], atom[3], atom[4], atom[5], atom[6])) atom_xyz = [round(x, decimals) for x in cmd.get_atom_coords(atom_name)] atom_dist = round(cpv.distance(ori, atom_xyz), decimals) distance_list.append([atom_name,atom_xyz[0],atom_xyz[1],atom_xyz[2], atom_dist]) # create property with distance (can be used for coloring, labeling etc) if property_name: try: cmd.alter(atom_name, '%s=%f'%(property_name, atom_dist)) except: # I'm not sure alter raises exceptions if the property is illegal property_name=False # sort list, if selected if sort>0: distance_list.sort(key=lambda dist: dist[4]) elif sort<0: distance_list.sort(key=lambda dist: dist[4], reverse=True) # add header distance_list=[['Atom Macro ID', 'x-coord', 'y-coord', 'z-coord', 'distance_to_origin'] ]+distance_list if ((not quiet) and (filename)): # Hijack stdout to print to file and console class logboth(object): def __init__(self, *files): self.files = files def write(self, obj): for f in self.files: f.write(obj) originalstdout = sys.stdout sys.stdout = logboth(sys.stdout, report) for entry in distance_list: if coordinates: output= '%s, %s, %s, %s, %s' %(entry[0],entry[1],entry[2],entry[3],entry[4]) #csv style else: output= '%s, %s' %(entry[0],entry[4]) #csv style if (not quiet): print output elif filename: report.write(output+'\n') # restore regular stdout if ((not quiet) and (filename)): sys.stdout = originalstdout # close file if filename: report.close() if (not quiet): if property_name: print 'Distances saved to property: %s' %str(property_name) else: print 'Distances NOT saved to property (illegal custom property)'
def rmsd(selection = "all", chains = "", doAlign = 1, doPretty = 1, \ algorithm = 1, guide = 1, method = "super", quiet = 1, colorstyle = "blue_red", colormode = ""): """ DESCRIPTION Align all structures and show the structural. ARGUMENTS Haves following arguments: selection = "all" chains = "" : like {chains = ab"} doAlign = 0 or 1 : Superpose selections before calculating distances {default: 1} doPretty = 1 guide = 1 algorithm = 0 or 1 : method = "super" quiet = 1 EXAMPLE fetch """ from chempy import cpv #initial parameters doAlign, doPretty = int(doAlign), int(doPretty) guide, quiet = int(guide), int(quiet) algorithm = int(algorithm) #get suitable align method try: align = cmd.keyword[method][0] except: print "Error: no such method:", method raise CmdException #get object and store each atom's coordinate objects = set() idx2coords = dict() cmd.iterate_state(-1, selection, "objects.add(model) ", space=locals()) #store the compared rmsd tree for each objects, like {obj:{obj1:{(model, index):(model1, index1)}}} rmsd_stored = dict() for obj in objects: rmsd_stored[obj] = {} for obj1 in objects: if obj != obj1: if guide: guide = " and guide" else: guide = "" rmsd_stored[obj][obj1] = {} total_values = {} if chains: for eachchain in list(chains): if doAlign: align(obj1 + guide + " and chain " + eachchain, obj + guide + " and chain " + eachchain) align(obj1 + " and chain " + eachchain, obj + " and chain " + eachchain, cycles=0, transform=0, object="aln") cmd.iterate_state(-1, selection, "idx2coords[model,index] = (x,y,z)", space=locals()) if cmd.count_atoms('?' + "aln", 1, 1) == 0: # this should ensure that "aln" will be available as selectable object cmd.refresh() for col in cmd.get_raw_alignment("aln"): assert len(col) == 2 b = cpv.distance(idx2coords[col[0]], idx2coords[col[1]]) for idx in col: total_values[idx] = b if col[0][0] == obj: rmsd_stored[obj][obj1][col[0]] = [col[1], b] else: rmsd_stored[obj][obj1][col[1]] = [col[0], b] cmd.delete("aln") else: if doAlign: align(obj1 + guide, obj + guide) align(obj1 + guide, obj + guide, cycles=0, transform=0, object="aln") cmd.iterate_state(-1, selection, "idx2coords[model,index] = (x,y,z)", space=locals()) if cmd.count_atoms('?' + "aln", 1, 1) == 0: # this should ensure that "aln" will be available as selectable object cmd.refresh() for col in cmd.get_raw_alignment("aln"): assert len(col) == 2 b = cpv.distance(idx2coords[col[0]], idx2coords[col[1]]) for idx in col: total_values[idx] = b if col[0][0] == obj: rmsd_stored[obj][obj1][col[0]] = [col[1], b] else: rmsd_stored[obj][obj1][col[1]] = [col[0], b] cmd.delete("aln") if algorithm: def b_replace(model, index): n = 0 bsum = 0 for obj1 in objects: if model != obj1: if (model, index) in rmsd_stored[model][obj1]: nextmodel, nextindex = rmsd_stored[model][obj1][ model, index][0] bsum += rmsd_stored[model][obj1][model, index][1] n += 1 for nextobj1 in objects: if nextmodel != nextobj1 and nextmodel != obj1: if (nextmodel, nextindex ) in rmsd_stored[nextmodel][nextobj1]: bsum += rmsd_stored[nextmodel][nextobj1][ nextmodel, nextindex][1] n += 1 if n == 0: return -1 else: return eval("bsum / n") else: def b_replace(model, index): n = 0 bsum = 0 for obj1 in objects: if model != obj1: if (model, index) in rmsd_stored[model][obj1]: bsum += rmsd_stored[model][obj1][model, index][1] n += 1 if n == 0: return -1 else: return eval("bsum / n") cmd.alter(selection, 'b = b_replace(model, index)', space=locals()) if doPretty: mini = min(total_values.values()) maxi = max(total_values.values()) if colormode: if colormode == "lowshow": maxi = sum(total_values.values()) / len(total_values) print("This is lowshow") elif colormode == "highshow": mini = sum(total_values.values()) / len(total_values) print("This is highshow") else: raise CmdException cmd.orient(selection) cmd.show_as('cartoon', 'byobj ' + selection) cmd.color('gray', selection) cmd.spectrum('b', "blue_red", selection + ' and b > -0.5', minimum=mini, maximum=maxi) if not quiet: print " ColorByRMSD: Minimum Distance: %.2f" % (min( total_values.values())) print " ColorByRMSD: Maximum Distance: %.2f" % (max( total_values.values())) print " ColorByRMSD: Average Distance: %.2f" % ( sum(total_values.values()) / len(total_values))
def angle_between_domains(selection1, selection2, method='align', state1=STATE, state2=STATE, visualize=1, quiet=1): ''' DESCRIPTION Angle by which a molecular selection would be rotated when superposing on a selection2. Do not use for measuring angle between helices, since the alignment of the helices might involve a rotation around the helix axis, which will result in a larger angle compared to the angle between helix axes. USAGE angle_between_domains selection1, selection2 [, method ] ARGUMENTS selection1 = string: atom selection of first helix selection2 = string: atom selection of second helix method = string: alignment command like "align" or "super" {default: align} EXAMPLE fetch 3iplA 3iplB, async=0 select domain1, resi 1-391 select domain2, resi 392-475 align 3iplA and domain1, 3iplB and domain1 angle_between_domains 3iplA and domain2, 3iplB and domain2 SEE ALSO align, super, angle_between_helices ''' import math try: import numpy except ImportError: print ' Error: numpy not available' raise CmdException state1, state2 = int(state1), int(state2) visualize, quiet = int(visualize), int(quiet) if cmd.is_string(method): try: method = cmd.keyword[method][0] except KeyError: print 'no such method:', method raise CmdException mobile_tmp = get_unused_name('_') cmd.create(mobile_tmp, selection1, state1, 1, zoom=0) try: method(mobile=mobile_tmp, target=selection2, mobile_state=1, target_state=state2, quiet=quiet) mat = cmd.get_object_matrix(mobile_tmp) except: print ' Error: superposition with method "%s" failed' % (method.__name__) raise CmdException finally: cmd.delete(mobile_tmp) try: # Based on transformations.rotation_from_matrix # Copyright (c) 2006-2012, Christoph Gohlke R33 = [mat[i:i+3] for i in [0,4,8]] R33 = numpy.array(R33, float) # direction: unit eigenvector of R33 corresponding to eigenvalue of 1 w, W = numpy.linalg.eig(R33.T) i = w.real.argmax() direction = W[:, i].real # rotation angle depending on direction m = direction.argmax() i,j,k,l = [ [2,1,1,2], [0,2,0,2], [1,0,0,1]][m] cosa = (R33.trace() - 1.0) / 2.0 sina = (R33[i, j] + (cosa - 1.0) * direction[k] * direction[l]) / direction[m] angle = math.atan2(sina, cosa) angle = abs(math.degrees(angle)) except: print ' Error: rotation from matrix failed' raise CmdException if not quiet: try: # make this import optional to support running this script standalone from .querying import centerofmass, gyradius except (ValueError, ImportError): gyradius = None try: # PyMOL 1.7.1.6+ centerofmass = cmd.centerofmass except AttributeError: centerofmass = lambda s: cpv.scale(cpv.add(*cmd.get_extent(s)), 0.5) center1 = centerofmass(selection1) center2 = centerofmass(selection2) print ' Angle: %.2f deg, Displacement: %.2f angstrom' % (angle, cpv.distance(center1, center2)) if visualize: center1 = numpy.array(center1, float) center2 = numpy.array(center2, float) center = (center1 + center2) / 2.0 if gyradius is not None: rg = numpy.array(gyradius(selection1), float) else: rg = 10.0 h1 = numpy.cross(center2 - center1, direction) h2 = numpy.dot(R33, h1) h1 *= rg / cpv.length(h1) h2 *= rg / cpv.length(h2) for pos in [center1, center2, center1 + h1, center1 + h2]: cmd.pseudoatom(mobile_tmp, pos=list(pos), state=1) # measurement object for angle and displacement name = get_unused_name('measurement') cmd.distance(name, *['%s`%d' % (mobile_tmp, i) for i in [1,2]]) cmd.angle(name, *['%s`%d' % (mobile_tmp, i) for i in [3,1,4]]) # CGO arrow for axis of rotation visualize_orientation(direction, center1, rg, color='blue') cmd.delete(mobile_tmp) return angle
def get_raw_distances(names='', state=1, selection='all', quiet=1): ''' DESCRIPTION Get the list of pair items from distance objects. Each list item is a tuple of (index1, index2, distance). Based on a script from Takanori Nakane, posted on pymol-users mailing list. http://www.mail-archive.com/[email protected]/msg10143.html ARGUMENTS names = string: names of distance objects (no wildcards!) {default: all measurement objects} state = integer: object state {default: 1} selection = string: atom selection {default: all} SEE ALSO select_distances, cmd.find_pairs, cmd.get_raw_alignment ''' from chempy import cpv state, quiet = int(state), int(quiet) if state < 1: state = cmd.get_state() valid_names = cmd.get_names_of_type('object:measurement') if names == '': names = ' '.join(valid_names) else: for name in names.split(): if name not in valid_names: print((' Error: no such distance object:', name)) raise CmdException raw_objects = cmd.get_session(names, 1, 1, 0, 0)['names'] xyz2idx = {} cmd.iterate_state(state, selection, 'xyz2idx[x,y,z] = (model,index)', space=locals()) r = [] for obj in raw_objects: try: points = obj[5][2][state - 1][1] if points is None: raise ValueError except (KeyError, ValueError): continue for i in range(0, len(points), 6): xyz1 = tuple(points[i:i + 3]) xyz2 = tuple(points[i + 3:i + 6]) try: r.append( (xyz2idx[xyz1], xyz2idx[xyz2], cpv.distance(xyz1, xyz2))) if not quiet: print((' get_raw_distances:', r[-1])) except KeyError: if quiet < 0: print((' Debug: no index for', xyz1, xyz2)) return r
def helix_orientation(selection, state=STATE, visualize=1, cutoff=3.5, quiet=1): ''' DESCRIPTION Get the center and direction of a helix as vectors. Will only work for alpha helices and gives slightly different results than cafit_orientation. Averages direction of C(i)->O(i)->N(i+4). USAGE helix_orientation selection [, visualize [, cutoff ]] ARGUMENTS selection = string: atom selection of helix visualize = 0 or 1: show fitted vector as arrow {default: 1} cutoff = float: maximal hydrogen bond distance {default: 3.5} SEE ALSO angle_between_helices, loop_orientation, cafit_orientation ''' state, visualize, quiet = int(state), int(visualize), int(quiet) cutoff = float(cutoff) atoms = {'C': dict(), 'O': dict(), 'N': dict()} cmd.iterate_state(state, '(%s) and name N+O+C' % (selection), 'atoms[name][resv] = x,y,z', space={'atoms': atoms}) vec_list = [] for resi in atoms['C']: resi_other = resi + 4 try: aC = atoms['C'][resi] aO = atoms['O'][resi] aN = atoms['N'][resi_other] except KeyError: continue dist = cpv.distance(aN, aO) dist_weight = 1. - (2.8 - dist) angle = cpv.get_angle_formed_by(aC, aO, aN) angle_weight = 1. - (3.1 - angle) if dist_weight > 0.0 and angle_weight > 0.0: if not quiet: print(' weight:', angle_weight * dist_weight) vec = cpv.scale(cpv.sub(aN, aC), angle_weight * dist_weight) vec_list.append(vec) if len(vec_list) == 0: print('warning: count == 0') raise CmdException center = cpv.scale(_vec_sum(atoms['O'].values()), 1. / len(atoms['O'])) vec = _vec_sum(vec_list) vec = cpv.normalize(vec) _common_orientation(selection, center, vec, visualize, 1.5 * len(vec_list), quiet) return center, vec
def colorbyrmsd(mobile, target, doAlign=1, doPretty=1, guide=1, method='super', quiet=1): ''' DESCRIPTION Align two structures and show the structural deviations in color to more easily see variable regions. Colors each mobile/target atom-pair by distance (the name is a bit misleading). Modifies the B-factor columns in your original structures. ARGUMENTS mobile = string: atom selection for mobile atoms target = string: atom selection for target atoms doAlign = 0 or 1: Superpose selections before calculating distances {default: 1} doPretty = 0 or 1: Show nice representation and colors {default: 1} EXAMPLE fetch 1ake 4ake, async=0 remove chain B colorbyrmsd 1ake, 4ake ''' from chempy import cpv doAlign, doPretty = int(doAlign), int(doPretty) guide, quiet = int(guide), int(quiet) aln, seleboth = '_aln', '_objSelBoth' try: align = cmd.keyword[method][0] except: print(' Error: no such method: ' + str(method)) raise CmdException if guide: mobile = '(%s) and guide' % mobile target = '(%s) and guide' % target try: if doAlign: # superpose align(mobile, target) # get alignment without superposing align(mobile, target, cycles=0, transform=0, object=aln) except: print(' Error: Alignment with method %s failed' % (method)) raise CmdException cmd.select(seleboth, '(%s) or (%s)' % (mobile, target)) idx2coords = dict() cmd.iterate_state(-1, seleboth, 'idx2coords[model,index] = (x,y,z)', space=locals()) if cmd.count_atoms('?' + aln, 1, 1) == 0: # this should ensure that "aln" will be available as selectable object cmd.refresh() b_dict = dict() for col in cmd.get_raw_alignment(aln): assert len(col) == 2 b = cpv.distance(idx2coords[col[0]], idx2coords[col[1]]) for idx in col: b_dict[idx] = b cmd.alter(seleboth, 'b = b_dict.get((model, index), -1)', space=locals()) if doPretty: cmd.orient(seleboth) cmd.show_as('cartoon', 'byobj ' + seleboth) cmd.color('gray', seleboth) cmd.spectrum('b', 'blue_red', seleboth + ' and b > -0.5') if not quiet: print(" ColorByRMSD: Minimum Distance: %.2f" % (min(b_dict.values()))) print(" ColorByRMSD: Maximum Distance: %.2f" % (max(b_dict.values()))) print(" ColorByRMSD: Average Distance: %.2f" % (sum(b_dict.values()) / len(b_dict))) cmd.delete(aln) cmd.delete(seleboth)
def rmsd(selection = "all", chains = "", doAlign = 1, doPretty = 1, \ algorithm = 1, guide = 1, method = "super", quiet = 1, colorstyle = "blue_red", colormode = ""): """ DESCRIPTION Align all structures and show the structural. ARGUMENTS Haves following arguments: selection = "all" chains = "" : like {chains = ab"} doAlign = 0 or 1 : Superpose selections before calculating distances {default: 1} doPretty = 1 guide = 1 algorithm = 0 or 1 : method = "super" quiet = 1 EXAMPLE fetch """ from chempy import cpv #initial parameters doAlign, doPretty = int(doAlign), int(doPretty) guide, quiet = int(guide), int(quiet) algorithm = int(algorithm) #get suitable align method try: align = cmd.keyword[method][0] except: print "Error: no such method:", method raise CmdException #get object and store each atom's coordinate objects = set() idx2coords = dict() cmd.iterate_state(-1, selection, "objects.add(model) ", space=locals()) #store the compared rmsd tree for each objects, like {obj:{obj1:{(model, index):(model1, index1)}}} rmsd_stored = dict() for obj in objects: rmsd_stored[obj] = {} for obj1 in objects: if obj != obj1: if guide: guide = " and guide" else: guide = "" rmsd_stored[obj][obj1] = {} total_values = {} if chains: for eachchain in list(chains): if doAlign: align(obj1 + guide + " and chain " + eachchain, obj + guide + " and chain " + eachchain) align(obj1 + " and chain " + eachchain, obj + " and chain " + eachchain, cycles = 0, transform = 0, object="aln") cmd.iterate_state(-1, selection, "idx2coords[model,index] = (x,y,z)", space=locals()) if cmd.count_atoms('?' + "aln", 1, 1) == 0: # this should ensure that "aln" will be available as selectable object cmd.refresh() for col in cmd.get_raw_alignment("aln"): assert len(col) == 2 b = cpv.distance(idx2coords[col[0]], idx2coords[col[1]]) for idx in col: total_values[idx] = b if col[0][0] == obj: rmsd_stored[obj][obj1][col[0]] = [col[1],b] else: rmsd_stored[obj][obj1][col[1]] = [col[0],b] cmd.delete("aln") else: if doAlign: align(obj1 + guide, obj + guide) align(obj1 + guide, obj + guide, cycles=0, transform=0, object="aln") cmd.iterate_state(-1, selection, "idx2coords[model,index] = (x,y,z)", space=locals()) if cmd.count_atoms('?' + "aln", 1, 1) == 0: # this should ensure that "aln" will be available as selectable object cmd.refresh() for col in cmd.get_raw_alignment("aln"): assert len(col) == 2 b = cpv.distance(idx2coords[col[0]], idx2coords[col[1]]) for idx in col: total_values[idx] = b if col[0][0] == obj: rmsd_stored[obj][obj1][col[0]] = [col[1],b] else: rmsd_stored[obj][obj1][col[1]] = [col[0],b] cmd.delete("aln") if algorithm: def b_replace(model, index): n = 0 bsum = 0 for obj1 in objects: if model != obj1: if (model, index) in rmsd_stored[model][obj1]: nextmodel, nextindex = rmsd_stored[model][obj1][model, index][0] bsum += rmsd_stored[model][obj1][model, index][1] n += 1 for nextobj1 in objects: if nextmodel != nextobj1 and nextmodel != obj1 : if (nextmodel, nextindex) in rmsd_stored[nextmodel][nextobj1]: bsum += rmsd_stored[nextmodel][nextobj1][nextmodel, nextindex][1] n += 1 if n == 0 : return -1 else: return eval("bsum / n") else: def b_replace(model, index): n = 0 bsum = 0 for obj1 in objects: if model != obj1: if (model, index) in rmsd_stored[model][obj1]: bsum += rmsd_stored[model][obj1][model, index][1] n += 1 if n == 0 : return -1 else: return eval("bsum / n") cmd.alter(selection, 'b = b_replace(model, index)', space=locals()) if doPretty: mini = min(total_values.values()) maxi = max(total_values.values()) if colormode: if colormode == "lowshow": maxi = sum(total_values.values()) / len(total_values) print("This is lowshow") elif colormode == "highshow": mini = sum(total_values.values()) / len(total_values) print("This is highshow") else: raise CmdException cmd.orient(selection) cmd.show_as('cartoon', 'byobj ' + selection) cmd.color('gray', selection) cmd.spectrum('b', "blue_red", selection + ' and b > -0.5',minimum = mini, maximum = maxi) if not quiet: print " ColorByRMSD: Minimum Distance: %.2f" % (min(total_values.values())) print " ColorByRMSD: Maximum Distance: %.2f" % (max(total_values.values())) print " ColorByRMSD: Average Distance: %.2f" % (sum(total_values.values()) / len(total_values))
def get_raw_distances(names='', state=1, selection='all', quiet=1, filename='intrs.txt'): ''' DESCRIPTION Get the list of pair items from distance objects. Each list item is a tuple of (index1, index2, distance). Based on a script from Takanori Nakane, posted on pymol-users mailing list. http://www.mail-archive.com/[email protected]/msg10143.html ARGUMENTS names = string: names of distance objects (no wildcards!) {default: all measurement objects} state = integer: object state {default: 1} selection = string: atom selection {default: all} quiet = boolen filename SEE ALSO select_distances, cmd.find_pairs, cmd.get_raw_alignment ''' foo = cmd.do('l = [];') ## ugly hack! from chempy import cpv state, quiet = int(state), int(quiet) if state < 1: state = cmd.get_state() valid_names = cmd.get_names_of_type('object:measurement') if names == '': names = ' '.join(valid_names) else: for name in names.split(): if name not in valid_names: print(' Error: no such distance object: ' + name) raise CmdException raw_objects = cmd.get_session(names, 1, 1, 0, 0)['names'] xyz2idx = {} cmd.iterate_state(state, selection, 'xyz2idx[x,y,z] = (model,index)', space=locals()) r = [] rresi = [] for obj in raw_objects: try: points = obj[5][2][state - 1][1] if not quiet: print(points) if points is None: raise ValueError except (KeyError, ValueError): continue for i in range(0, len(points), 6): xyz1 = tuple(points[i:i + 3]) xyz2 = tuple(points[i + 3:i + 6]) try: r.append( (xyz2idx[xyz1], xyz2idx[xyz2], cpv.distance(xyz1, xyz2))) # (('yC_5lj3_U6', 1183) if not quiet: print(' get_raw_distances: ' + str(r[-1])) rresi.append([ unid(xyz2idx[xyz1][0], xyz2idx[xyz1][1]), unid(xyz2idx[xyz2][0], xyz2idx[xyz2][1]) ]) if not quiet: print(' ', unid(xyz2idx[xyz1][0], xyz2idx[xyz1][1]), '<->', unid(xyz2idx[xyz2][0], xyz2idx[xyz2][1])) except KeyError: if quiet < 0: print(' Debug: no index for %s %s' % (xyz1, xyz2)) if rresi: with open(filename, 'w') as f: for r in rresi: # not fully correct # f.write('Prp8' +',' + r[0] + '\n') f.write(r[0] + ',' + r[1] + '\n') print('File saved:', filename) return r, rresi
def bbPlane(selection='(all)', color='gray', transp=0.3, state=-1, name=None, quiet=1): """ DESCRIPTION Draws a plane across the backbone for a selection ARGUMENTS selection = string: protein object or selection {default: (all)} color = string: color name or number {default: white} transp = float: transparency component (0.0--1.0) {default: 0.0} state = integer: object state, 0 for all states {default: 1} NOTES You need to pass in an object or selection with at least two amino acids. The plane spans CA_i, O_i, N-H_(i+1), and CA_(i+1) """ from pymol.cgo import BEGIN, TRIANGLES, COLOR, VERTEX, END from pymol import cgo from chempy import cpv # format input transp = float(transp) state, quiet = int(state), int(quiet) if name is None: name = cmd.get_unused_name("backbonePlane") if state < 0: state = cmd.get_state() elif state == 0: for state in range(1, cmd.count_states(selection) + 1): bbPlane(selection, color, transp, state, name, quiet) return AAs = [] coords = dict() # need hydrogens on peptide nitrogen cmd.h_add('(%s) and n. N' % selection) # get the list of residue ids for obj in cmd.get_object_list(selection): sel = obj + " and (" + selection + ")" for a in cmd.get_model(sel + " and n. CA", state).atom: key = '/%s/%s/%s/%s' % (obj, a.segi, a.chain, a.resi) AAs.append(key) coords[key] = [a.coord, None, None] for a in cmd.get_model(sel + " and n. O", state).atom: key = '/%s/%s/%s/%s' % (obj, a.segi, a.chain, a.resi) if key in coords: coords[key][1] = a.coord for a in cmd.get_model(sel + " and ((n. N extend 1 and e. H) or (r. PRO and n. CD))", state).atom: key = '/%s/%s/%s/%s' % (obj, a.segi, a.chain, a.resi) if key in coords: coords[key][2] = a.coord # need at least two amino acids if len(AAs) <= 1: print("ERROR: Please provide at least two amino acids, the alpha-carbon on the 2nd is needed.") return # prepare the cgo obj = [ BEGIN, TRIANGLES, COLOR, ] obj.extend(cmd.get_color_tuple(color)) for res in range(0, len(AAs) - 1): curIdx, nextIdx = str(AAs[res]), str(AAs[res + 1]) # populate the position array pos = [coords[curIdx][0], coords[curIdx][1], coords[nextIdx][2], coords[nextIdx][0]] # if the data are incomplete for any residues, ignore if None in pos: if not quiet: print(' bbPlane: peptide bond %s -> %s incomplete' % (curIdx, nextIdx)) continue if cpv.distance(pos[0], pos[3]) > 4.0: if not quiet: print(' bbPlane: %s and %s not adjacent' % (curIdx, nextIdx)) continue normal = cpv.normalize(cpv.cross_product( cpv.sub(pos[1], pos[0]), cpv.sub(pos[2], pos[0]))) obj.append(cgo.NORMAL) obj.extend(normal) # need to order vertices to generate correct triangles for plane if cpv.dot_product(cpv.sub(pos[0], pos[1]), cpv.sub(pos[2], pos[3])) < 0: vorder = [0, 1, 2, 2, 3, 0] else: vorder = [0, 1, 2, 3, 2, 1] # fill in the vertex data for the triangles; for i in vorder: obj.append(VERTEX) obj.extend(pos[i]) # finish the CGO obj.append(END) # update the UI cmd.load_cgo(obj, name, state, zoom=0) cmd.set("cgo_transparency", transp, name)
def cgo_arrow(atom1='pk1', atom2='pk2', radius=0.5, gap=0.0, hlength=-1, hradius=-1, color='blue red', name='', state=0): ''' DESCRIPTION Create a CGO arrow between two picked atoms. ARGUMENTS atom1 = string: single atom selection or list of 3 floats {default: pk1} atom2 = string: single atom selection or list of 3 floats {default: pk2} radius = float: arrow radius {default: 0.5} gap = float: gap between arrow tips and the two atoms {default: 0.0} hlength = float: length of head hradius = float: radius of head color = string: one or two color names {default: blue red} name = string: name of CGO object state = int: arrow state index ''' from chempy import cpv radius, gap = float(radius), float(gap) hlength, hradius = float(hlength), float(hradius) state = int(state) try: color1, color2 = color.split() except: color1 = color2 = color color1 = list(cmd.get_color_tuple(color1)) color2 = list(cmd.get_color_tuple(color2)) def get_coord(v): if not isinstance(v, str): return v if v.startswith('['): return cmd.safe_list_eval(v) return cmd.get_atom_coords(v) xyz1 = get_coord(atom1) xyz2 = get_coord(atom2) normal = cpv.normalize(cpv.sub(xyz1, xyz2)) if hlength < 0: hlength = radius * 3.0 if hradius < 0: hradius = hlength * 0.6 if gap: diff = cpv.scale(normal, gap) xyz1 = cpv.sub(xyz1, diff) xyz2 = cpv.add(xyz2, diff) xyz3 = cpv.add(cpv.scale(normal, hlength), xyz2) obj = [cgo.CONE] + xyz3 + xyz2 + [hradius, 0.0 ] + color2 + color2 + [1.0, 0.0] if cpv.distance(xyz1, xyz2) > hlength: # draw cylinder obj += [cgo.CYLINDER] + xyz1 + xyz3 + [radius] + color1 + color2 if not name: name = cmd.get_unused_name('arrow') cmd.load_cgo(obj, name, state)