def visualize_orientation(direction, center=[0, 0, 0], scale=1.0, symmetric=False, color="green", color2="red"): """ Draw an arrow. Helper function for "helix_orientation" etc. """ from pymol import cgo color_list = cmd.get_color_tuple(color) color2_list = cmd.get_color_tuple(color2) if symmetric: scale *= 0.5 end = cpv.add(center, cpv.scale(direction, scale)) radius = 0.3 obj = [cgo.SAUSAGE] obj.extend(center) obj.extend(end) obj.extend([radius, 0.8, 0.8, 0.8]) obj.extend(color_list) if symmetric: start = cpv.sub(center, cpv.scale(direction, scale)) obj.append(cgo.SAUSAGE) obj.extend(center) obj.extend(start) obj.extend([radius, 0.8, 0.8, 0.8]) obj.extend(color2_list) coneend = cpv.add(end, cpv.scale(direction, 4.0 * radius)) if cmd.get_version()[1] >= 1.2: obj.append(cgo.CONE) obj.extend(end) obj.extend(coneend) obj.extend([radius * 1.75, 0.0]) obj.extend(color_list * 2) obj.extend([1.0, 1.0]) # Caps cmd.load_cgo(obj, get_unused_name("oriVec"), zoom=0)
def loop_orientation(selection, visualize=1, quiet=0): ''' DESCRIPTION Get the center and approximate direction of a peptide. Works for any secondary structure. Averages direction of N(i)->C(i) pseudo bonds. USAGE loop_orientation selection [, visualize] SEE ALSO helix_orientation ''' visualize, quiet = int(visualize), int(quiet) stored.x = dict() cmd.iterate_state(STATE, '(%s) and name N+C' % (selection), 'stored.x.setdefault(chain + resi, dict())[name] = x,y,z') vec = cpv.get_null() count = 0 for x in stored.x.itervalues(): if 'C' in x and 'N' in x: vec = cpv.add(vec, cpv.sub(x['C'], x['N'])) count += 1 if count == 0: print 'warning: count == 0' raise CmdException vec = cpv.normalize(vec) return _common_orientation(selection, vec, visualize, quiet)
def testPairFit(self): cmd.fragment('trp') cmd.fragment('his') # 1 atom sele = ('trp and guide', 'his and guide') pos = list(map(cmd.get_atom_coords, sele)) vec = cpv.sub(*pos) mat_ref = [ 1.0, 0.0, 0.0, -vec[0], 0.0, 1.0, 0.0, -vec[1], 0.0, 0.0, 1.0, -vec[2], 0.0, 0.0, 0.0, 1.0] rms = cmd.pair_fit(*sele) self.assertEqual(rms, 0.0) mat = cmd.get_object_matrix('trp') self.assertArrayEqual(mat, mat_ref, 1e-4) # 2 atoms sele += ('trp & name CB', 'his & name CB') rms = cmd.pair_fit(*sele) self.assertAlmostEqual(rms, 0.0082, delta=1e-4) # 4 atoms sele += ('trp & name CG', 'his & name CG', 'trp & name CD1', 'his & name CD2') rms = cmd.pair_fit(*sele) self.assertAlmostEqual(rms, 0.0713, delta=1e-4)
def append_cyl(self): if self.l_vert and self.c_colr and self.l_radi: if self.tri_flag: self.tri_flag=0 self.obj.append(END) self.obj.append(SAUSAGE) d = cpv.sub(self.l_vert[1],self.l_vert[0]) d = cpv.normalize_failsafe(d) d0 = cpv.scale(d,self.l_radi/4.0) self.obj.extend(cpv.add(self.l_vert[0],d0)) self.obj.extend(cpv.sub(self.l_vert[1],d0)) self.obj.append(self.l_radi) self.obj.extend(self.c_colr[0]) self.obj.extend(self.c_colr[1]) self.l_vert=None self.c_colr=None self.l_radi=None
def _cgo_quad(pos, normal, radius): '''Return a CGO list specifying a quad.''' v1 = cpv.normalize(_perp_vec(normal)) v2 = cpv.cross_product(normal, v1) v1 = cpv.scale(v1, radius) v2 = cpv.scale(v2, radius) obj = [ cgo.BEGIN, cgo.TRIANGLE_STRIP, cgo.NORMAL] obj.extend(normal) obj.append(cgo.VERTEX) obj.extend(cpv.add(pos, v1)) obj.append(cgo.VERTEX) obj.extend(cpv.add(pos, v2)) obj.append(cgo.VERTEX) obj.extend(cpv.sub(pos, v2)) obj.append(cgo.VERTEX) obj.extend(cpv.sub(pos, v1)) obj.append(cgo.END) return obj
def append_tri(self): if self.l_vert: d0 = cpv.sub(self.l_vert[0],self.l_vert[1]) d1 = cpv.sub(self.l_vert[0],self.l_vert[2]) n0 = cpv.cross_product(d0,d1) n0 = cpv.normalize_failsafe(n0) if not self.tri_flag: self.obj.append(BEGIN) self.obj.append(TRIANGLES) self.tri_flag = 1 indices = [0, 1, 2] if not self.l_norm: # TODO could simplify this if ray tracing would support # object-level two_sided_lighting. Duplicating the # face with an offset is a hack and produces visible # lines on edges. n1 = [-n0[0],-n0[1],-n0[2]] ns = cpv.scale(n0,0.002) indices = [0, 1, 2, 4, 3, 5] l_vert_offsetted = [cpv.add(v, ns) for v in self.l_vert] l_vert_offsetted.extend(cpv.sub(v, ns) for v in self.l_vert) self.l_vert = l_vert_offsetted self.l_norm = [n0, n0, n0, n1, n1, n1] elif cpv.dot_product(self.l_norm[0], n0) < 0: indices = [0, 2, 1] for i in indices: self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[i % 3]) self.obj.append(NORMAL) self.obj.extend(self.l_norm[i]) self.obj.append(VERTEX) self.obj.extend(self.l_vert[i]) self.l_vert=None self.t_colr=None self.l_norm=None
def helix_orientation(selection, visualize=1, sigma_cutoff=1.5, quiet=0): """ DESCRIPTION Get the center and direction of a helix as vectors. Will only work for helices and gives slightly different results than loop_orientation. Averages direction of C(i)->O(i) bonds. USAGE helix_orientation selection [, visualize [, sigma_cutoff]] ARGUMENTS selection = string: atom selection of helix visualize = 0 or 1: show fitted vector as arrow {default: 1} sigma_cutoff = float: drop outliers outside (standard_deviation * sigma_cutoff) {default: 1.5} SEE ALSO angle_between_helices, helix_orientation_hbond, loop_orientation, cafit_orientation """ visualize, quiet, sigma_cutoff = int(visualize), int(quiet), float(sigma_cutoff) stored.x = dict() cmd.iterate_state( STATE, "(%s) and name C+O" % (selection), "stored.x.setdefault(chain + resi, dict())[name] = x,y,z" ) vec_list = [] count = 0 for x in stored.x.values(): if "C" in x and "O" in x: vec_list.append(cpv.sub(x["O"], x["C"])) count += 1 if count == 0: print("warning: count == 0") raise CmdException vec = _vec_sum(vec_list) if count > 2 and sigma_cutoff > 0: angle_list = [cpv.get_angle(vec, x) for x in vec_list] angle_mu, angle_sigma = _mean_and_std(angle_list) vec_list = [ vec_list[i] for i in range(len(vec_list)) if abs(angle_list[i] - angle_mu) < angle_sigma * sigma_cutoff ] if not quiet: print("Dropping %d outlier(s)" % (len(angle_list) - len(vec_list))) vec = _vec_sum(vec_list) vec = cpv.normalize(vec) return _common_orientation(selection, vec, visualize, quiet)
def compute_surface_normals(): ''' Compute average normals from all adjacent triangles on each vertex ''' from functools import reduce # don't use cpv.normalize which has an RSMALL4 limit normalize = lambda v: cpv.scale(v, 1. / cpv.length(v)) for face in table['face']: if 'vertex_index' in face: indices = face['vertex_index'] elif 'vertex_indices' in face: indices = face['vertex_indices'] else: return f_vert = [vertices[i] for i in indices] f_xyz = [(v['x'], v['y'], v['z']) for v in f_vert] try: normal = normalize(cpv.cross_product( cpv.sub(f_xyz[1], f_xyz[0]), cpv.sub(f_xyz[2], f_xyz[1]))) except ZeroDivisionError: continue for v in f_vert: v.setdefault('normals', []).append(normal) for v in vertices: try: v['nx'], v['ny'], v['nz'] = normalize( reduce(cpv.add, v.pop('normals'))) except (KeyError, ZeroDivisionError): continue
def visualize_orientation(direction, center=[0.0]*3, scale=1.0, symmetric=False, color='green', color2='red'): ''' DESCRIPTION Draw an arrow. Helper function for "helix_orientation" etc. ''' from pymol import cgo color_list = cmd.get_color_tuple(color) color2_list = cmd.get_color_tuple(color2) if symmetric: scale *= 0.5 end = cpv.add(center, cpv.scale(direction, scale)) radius = 0.3 obj = [cgo.SAUSAGE] obj.extend(center) obj.extend(end) obj.extend([ radius, 0.8, 0.8, 0.8, ]) obj.extend(color_list) if symmetric: start = cpv.sub(center, cpv.scale(direction, scale)) obj.append(cgo.SAUSAGE) obj.extend(center) obj.extend(start) obj.extend([ radius, 0.8, 0.8, 0.8, ]) obj.extend(color2_list) coneend = cpv.add(end, cpv.scale(direction, 4.0*radius/cpv.length(direction))) obj.append(cgo.CONE) obj.extend(end) obj.extend(coneend) obj.extend([ radius * 1.75, 0.0, ]) obj.extend(color_list * 2) obj.extend([ 1.0, 1.0, # Caps ]) cmd.load_cgo(obj, get_unused_name('oriVec'), zoom=0)
def __init__(self, p1, p2, radius, color1, color2=None, color3=None, hlength=None, hradius=None, hlength_scale=3.0, hradius_scale=0.6): if hlength is None: hlength = radius * hlength_scale if hradius is None: hradius = hlength * hradius_scale normal = cpv.normalize(cpv.sub(p1, p2)) pM = cpv.add(cpv.scale(normal, hlength), p2) line = Cylinder(p1, pM, radius, color1, color2) cone = Cone( pM, p2, hradius, color2 or color1, radius2=0, color2=color3 ) self._primitive = (line + cone).primitive
def scramble(self,mode): if self.cmd.count_atoms(self.sculpt_object): sc_tmp = "_scramble_tmp" if mode == 0: self.cmd.select(sc_tmp,self.sculpt_object+ " and not (fixed or restrained)") if mode == 1: self.cmd.select(sc_tmp,self.sculpt_object+ " and not (fixed)") extent = self.cmd.get_extent(sc_tmp) center = self.cmd.get_position(sc_tmp) radius = 1.25*cpv.length(cpv.sub(extent[0],extent[1])) self.cmd.alter_state(self.cmd.get_state(), sc_tmp, "(x,y,z)=rsp(pos,rds)", space= { 'rsp' : cpv.random_displacement, 'pos' : center, 'rds' : radius }) self.cmd.delete(sc_tmp)
def planeFromPoints(point1, point2, point3, facetSize): v1 = cpv.normalize(cpv.sub(point2, point1)) v2 = cpv.normalize(cpv.sub(point3, point1)) normal = cpv.cross_product(v1, v2) v2 = cpv.cross_product(normal, v1) x = cpv.scale(v1, facetSize) y = cpv.scale(v2, facetSize) center = point2 corner1 = cpv.add(cpv.add(center, x), y) corner2 = cpv.sub(cpv.add(center, x), y) corner3 = cpv.sub(cpv.sub(center, x), y) corner4 = cpv.add(cpv.sub(center, x), y) return plane(corner1, corner2, corner3, corner4, normal)
def get_cgo(self, dot_mode=0, dot_radius=0.03): """Generate a CGO list for a dot.""" cgolist = [] # COLOR cgolist.extend(_cgo_color(self.color)) if dot_mode == 0: # spheres logger.debug("Adding dot to cgolist...") cgolist.extend(_cgo_sphere(self.coords, dot_radius)) logger.debug("Finished adding dot to cgolist.") if dot_mode == 1: # quads logger.debug("Adding quad to cgolist...") normal = cpv.normalize(cpv.sub(self.coords, self.atom['coords'])) cgolist.extend(_cgo_quad(self.coords, normal, dot_radius * 1.5)) logger.debug("Finished adding quad to cgolist.") return cgolist
def loop_orientation(selection, state=STATE, visualize=1, quiet=1): ''' DESCRIPTION Get the center and approximate direction of a peptide. Works for any secondary structure. Averages direction of N(i)->C(i) pseudo bonds. USAGE loop_orientation selection [, visualize ] SEE ALSO helix_orientation ''' state, visualize, quiet = int(state), int(visualize), int(quiet) coords = dict() cmd.iterate_state(state, '(%s) and name N+C' % (selection), 'coords.setdefault(chain + resi, {})[name] = x,y,z', space=locals()) vec = cpv.get_null() center = cpv.get_null() count = 0 for x in coords.itervalues(): if 'C' in x and 'N' in x: vec = cpv.add(vec, cpv.sub(x['C'], x['N'])) for coord in x.itervalues(): center = cpv.add(center, coord) count += 1 if count == 0: print 'warning: count == 0' raise CmdException vec = cpv.normalize(vec) center = cpv.scale(center, 1./count) _common_orientation(selection, center, vec, visualize, 2.0*len(coords), quiet) return center, vec
def helix_orientation_hbond(selection, visualize=1, cutoff=3.5, quiet=0): ''' DESCRIPTION Get the center and direction of a helix as vectors. Will only work for alpha helices and gives slightly different results than helix_orientation. Averages direction of O(i)->N(i+4) hydrogen bonds. USAGE helix_orientation selection [, visualize [, cutoff]] ARGUMENTS cutoff = float: maximal hydrogen bond distance {default: 3.5} SEE ALSO helix_orientation ''' visualize, quiet, cutoff = int(visualize), int(quiet), float(cutoff) stored.x = dict() cmd.iterate_state(STATE, '(%s) and name N+O' % (selection), 'stored.x.setdefault(resv, dict())[name] = x,y,z') vec_list = [] for resi in stored.x: resi_other = resi + 4 if 'O' in stored.x[resi] and resi_other in stored.x: if 'N' in stored.x[resi_other]: vec = cpv.sub(stored.x[resi_other]['N'], stored.x[resi]['O']) if cpv.length(vec) < cutoff: vec_list.append(vec) if len(vec_list) == 0: print 'warning: count == 0' raise CmdException vec = _vec_sum(vec_list) vec = cpv.normalize(vec) return _common_orientation(selection, vec, visualize, quiet)
def cgo_grid( pos1=[0,0,0], pos2=[1,0,0], pos3=[0,0,1], length_x=30, length_z='', npoints_x='', npoints_z='', nwaves_x=2, nwaves_z='', offset_x=0, offset_z='', gain_x=1, gain_z='', thickness=2.0, color='', nstates=60, startframe=1, endframe=1, mode=0, view=0, name='', quiet=1): ''' DESCRIPTION Generates an animated flowing mesh object using the points provided or the current view. The shape is affected substantially by the arguments! USEAGE cgo_grid [ pos1 [, pos2 [, pos3 [, length_x [, length_z [, npoints_x [, npoints_z [, nwaves_x [, nwaves_z [, offset_x [, offset_z [, gain_x [, gain_z [, thickness [, color [, nstates [, startframe [, endframe [, mode [, view [, name [, quiet ]]]]]]]]]]]]]]]]]]]]]] EXAMPLE cgo_grid view=1 ARGUMENTS pos1 = single atom selection (='pk1') or list of 3 floats {default: [0,0,0]} pos2 = single atom selection (='pk2') or list of 3 floats {default: [1,0,0]} pos3 = single atom selection (='pk3') or list of 3 floats {default: [0,0,1]} --> the plane is defined by pos1 (origin) and vectors to pos2 and pos3, respectively length_x = <float>: length of membrane {default: 30} length_z = <float>: length of membrane {default: ''} # same as length_x npoints_x = <int>: number of points(lines) along x-direction {default: ''} #will be set to give a ~1 unit grid npoints_z = <int>: number of points(lines) along z-direction {default: ''} #will be set to give a ~1 unit grid {minimum: 1 # automatic} nwaves_x = <float>: number of complete sin waves along object x-axis {default: 2} nwaves_z = <float>: number of complete sin waves along object z-axis {default: ''} # same as nwaves_x define separately to adjust number of waves in each direction offset_x = <float> phase delay (in degrees) of sin wave in x-axis can be set to affect shape and starting amplitude {default: 0} offset_z = <float> phase delay (in degrees) of sin wave in z-axis can be set to affect shape and starting amplitude {default: ''} # same as offset_x offset_x and offset_z can be used together to phase otherwise identical objects gain_x = <float>: multiplication factor for y-amplitude for x-direction {default: 1} gain_z = <float>: multiplication factor for y-amplitude for z-direction {default: ''} #=gain_x thickness = <float>: line thickness {default: 2} color = color name <string> (e.g. 'skyblue') OR rgb-value list of 3 floats (e.g. [1.0,1.0,1.0]) OR {default: ''} // opposite of background input illegal values for random coloring nstates = <int>: number of states; {default: 60} this setting will define how many states the object will have (per wave) and how fluent and fast the animation will be. Higher values will promote 'fluent' transitions, but decrease flow speed. Note: Frame animation cycles thought the states one at a time and needs to be set accordingly. Can also be used to phase otherwise identical objects. Set to 1 for static object {automatic minimum} startframe: specify starting frame <int> or set (='') to use current frame set to 'append' to extend movie from the last frame {default: 1} endframe: specify end frame <int> or set (='') to use last frame if 'append' is used for startframe, endframe becomes the number of frames to be appended instead {default: 1} Note: if start- and endframe are the same, movie animation will be skipped, the object will be loaded and can be used afterwards mode: defines positioning {default: 0}: 0: pos1 is center 1: pos1 is corner view {default: 0}: '0': off/ uses provided points to create CGO '1': overrides atom selections and uses current orienatation for positioning - pos1 = origin/center - pos2 = origin +1 in camera y - pos3 = origin +1 in camera z name: <string> name of cgo object {default: ''} / automatic quiet: <boolean> toggles output ''' ########## BEGIN OF FUNCTION CODE ########## def get_coord(v): if not isinstance(v, str): try: return v[:3] except: return False if v.startswith('['): return cmd.safe_list_eval(v)[:3] try: if cmd.count_atoms(v)==1: # atom coordinates return cmd.get_atom_coords(v) else: # more than one atom --> use "center" # alt check! if cmd.count_atoms('(alt *) and not (alt "")')!=0: print("cgo_grid: warning! alternative coordinates found for origin, using center!") view_temp=cmd.get_view() cmd.zoom(v) v=cmd.get_position() cmd.set_view(view_temp) return v except: return False def eval_color(v): try: if not v: v=eval(cmd.get('bg_rgb')) v=list(map(sum, list(zip(v,[-1,-1,-1])))) v=list(map(abs, v)) if v[0]==v[1]==v[2]==0.5: # grey v=[0,0,0] return v if isinstance(v, list): return v[0:3] if not isinstance(v, str): return v[0:3] if v.startswith('['): return cmd.safe_list_eval(v)[0:3] return list(cmd.get_color_tuple(v)) except: return [random.random(),random.random(),random.random()] cmd.extend("eval_color", eval_color) color=eval_color(color) try: mode=int(mode) except: raise Exception("Input error in Mode") if mode<0 or mode>1: raise Exception("Mode out of range!") try: nstates=int(nstates) if nstates<1: nstates=1 print("NB! nstates set to 1 (automatic minimum)") length_x=float(length_x) if length_z=='': length_z=length_x else: length_z=float(length_z) if npoints_x=='': npoints_x=int(length_x)+1 else: npoints_x=int(npoints_x) if npoints_x<1: npoints_x=1 print("NB! npoints_x set to 1 (automatic minimum)") if npoints_z =='': npoints_z=int(length_z)+1 else: npoints_z=int(npoints_z) if npoints_z<1: npoints_z=1 print("NB! npoints_x set to 1 (automatic minimum)") nwaves_x=abs(float(nwaves_x)) if nwaves_z=='': nwaves_z=nwaves_x else: nwaves_z=abs(float(nwaves_z)) offset_x=float(offset_x)*math.pi/180 if offset_z=='': offset_z=offset_x else: offset_z=float(offset_z)*math.pi/180 thickness=float(thickness) gain_x=float(gain_x) if gain_z=='': gain_z=gain_x else: gain_z=float(gain_z) if not name: name = cmd.get_unused_name('membrane') else: name = str(name) if int(quiet): quiet=True else: quiet=False if int(view): view=True else: view=False except: raise Exception("Input error in parameters!") #prevent auto zooming on object temp_auto_zoom=cmd.get('auto_zoom') cmd.set('auto_zoom', '0') if int(view): xyz1=cmd.get_position() tempname = cmd.get_unused_name('temp') ori_ax=[[0,0,0],[10,0,0],[0,0,10]] for a in range (0,len(ori_ax)): cmd.pseudoatom(tempname, resi=''+str(a+1)+'', pos=xyz1) cmd.translate(ori_ax[a], selection=''+tempname+' and resi '+str(a+1)+'', camera='1') ori_ax[a]=cmd.get_atom_coords(''+tempname+' and resi '+str(a+1)+'') cmd.delete(tempname) xyz1=ori_ax[0] xyz2=ori_ax[1] xyz3=ori_ax[2] else: xyz1 = get_coord(pos1) xyz2 = get_coord(pos2) xyz3 = get_coord(pos3) if (not startframe): startframe=cmd.get('frame') if (not endframe): endframe=cmd.count_frames() if endframe==0: endframe=1 if (startframe=='append'): startframe=cmd.count_frames()+1 try: endframe=int(endframe) cmd.madd('1 x'+str(endframe)) endframe=cmd.count_frames() except ValueError: raise Exception("Input error: Value for 'endframe' is not integer!") try: startframe=int(startframe) endframe=int(endframe) endframe/startframe startframe/endframe except ValueError: raise Exception("Input error: Failed to convert to integer!") except ZeroDivisionError: raise Exception("Error: unexpected zero value!") except: raise Exception("Unexpected error!") if (nstates==1): if not quiet: print("Creating one state object!") if startframe > endframe: startframe, endframe = endframe, startframe if not quiet: print("Inverted start and end frames!") ########## BEGIN OF FUNCTIONAL SCRIPT ########## #normalize and get orthogonal vector # define vectors from points xyz2 = cpv.sub(xyz2, xyz1) xyz3 = cpv.sub(xyz3, xyz1) #NB! cpv.get_system2 outputs normalized vectors [x,y,z] xyz4 = cpv.get_system2(xyz2,xyz3) xyz2 = xyz4[0] xyz3 = xyz4[1] for x in range(0,3): for z in range(0,3): if x==z: continue if xyz4[x]==xyz4[z]: raise Exception("Illegal vector settings!") xyz4 = cpv.negate(xyz4[2]) #overwrites original # transform origin to corner if mode==0: if npoints_x>1: xyz1 = cpv.sub(xyz1, cpv.scale(xyz2,length_x/2)) if npoints_z>1: xyz1 = cpv.sub(xyz1, cpv.scale(xyz3,length_z/2)) #defines array lines nlines=max([npoints_x, npoints_z]) # in case only one line max # create an empty array for xyz entries # this may contain more values than are actually drawn later, # but they are needed to draw lines in each direction grid_xyz = [] for x in range(0,nlines): grid_xyz.append([0.0,0.0,0.0]*nlines) # grid distance and steps # prevent zero divisions (lines=1) and enable calculations if lines=0 if (not (npoints_x-1<2)): gap_length_x = length_x/(npoints_x-1) step_line_x = 2*math.pi/(npoints_x-1) else: gap_length_x=length_x step_line_x=2*math.pi if (not (npoints_z-1<2)): gap_length_z = length_z/(npoints_z-1) step_line_z = 2*math.pi/(npoints_z-1) else: gap_length_z=length_z step_line_z=2*math.pi # calculate steps if nstates==1: step_state=0 else: step_state = 2*math.pi/(nstates-1) ########## BEGIN STATE ITERATION ########## # create a n-state object in PyMol for a in range(0,nstates): # Reset object obj = [] #assign color obj.extend( [ COLOR, color[0], color[1], color[2] ] ) #set width obj.extend( [ LINEWIDTH, thickness ] ) # Calculate xyz-coordinates for each line for x in range(0,nlines): for z in range(0,nlines): # update grid position in x-direction xyztemp=cpv.add(xyz1,cpv.scale(xyz2,gap_length_x*x)) # update grid position in z-direction xyztemp=cpv.add(xyztemp,cpv.scale(xyz3,gap_length_z*z)) # calculate amplitude for y-direction and update grid position y_amp=(\ gain_x*math.sin(offset_x+nwaves_x*((a*step_state)+(x*step_line_x)))/2+\ gain_z*math.sin(offset_z+nwaves_z*((a*step_state)+(z*step_line_z)))/2\ ) xyztemp=cpv.add(xyztemp,cpv.scale(xyz4,y_amp)) grid_xyz[x][z]=xyztemp #Now the coordinates for this state are defined! #Now the coordinates are read separately: # allow to run the loops as often as required #if npoints_x==0:npoints_x=npoints_z #lines along z in x direction for z in range(0,npoints_z): obj.extend( [ BEGIN, LINE_STRIP ] ) for x in range(0,npoints_x): obj.extend( [ VERTEX, grid_xyz[x][z][0], grid_xyz[x][z][1], grid_xyz[x][z][2] ] ) obj.append( END ) #lines along x in z direction for x in range(0,npoints_x): obj.extend( [ BEGIN, LINE_STRIP ] ) for z in range(0,npoints_z): obj.extend( [ VERTEX, grid_xyz[x][z][0], grid_xyz[x][z][1], grid_xyz[x][z][2] ] ) obj.append( END ) # Load state into PyMOL object: cmd.load_cgo(obj,name,a+1) # All states of object loaded! #reset auto zooming to previous value cmd.set('auto_zoom', temp_auto_zoom) # animate object using frames instead of states if (not endframe==startframe): framecount=0 countvar=1 for frame in range(startframe, endframe + 1): #increase count framecount=framecount+countvar # set state in frame cmd.mappend(frame, "/cmd.set('state', %s, %s)" % (repr(framecount), repr(name))) # Looping if framecount==nstates: if ((int(nwaves_x)!=nwaves_x) or (int(nwaves_z)!=nwaves_z)): #if not complete sinus wave #--> reverse wave in ongoing animation countvar=-1 else: #wave is complete --> repeat framecount=0 # count up from first state if framecount==1: countvar=1 if not quiet: print("object loaded and animated with frames!") else: if not quiet: print("object loaded!") #OUTPUT if not quiet: print("Grid variables for:",name) print("corner:", xyz1) print("vector 1:", xyz2) print("vector 2:", xyz3) print("length_x:",length_x) print("length_z:",length_z) print("npoints_x:", npoints_x) print("npoints_z:", npoints_z) print("nwaves_x:", nwaves_x) print("nwaves_z:", nwaves_z) print("offset_x:",offset_x) print("offset_z:",offset_z) print("gain_x:",gain_x) print("gain_z:",gain_z) print("thickness:",thickness) print("states", nstates) if (not endframe==startframe): print("frames: start:",startframe,"end:",endframe) return grid_xyz
def planeFromPoints(p1, p2, p3, vm1=None, vm2=None, center=True, settings={}): v1 = cpv.sub(p1, p2) v2 = cpv.sub(p3, p2) normal = cpv.cross_product(v1, v2) if 'translate' in settings: vtran = cpv.scale(cpv.normalize(normal), settings['translate']) p1_t = cpv.sub(p1, vtran) p2_t = cpv.sub(p2, vtran) p3_t = cpv.sub(p3, vtran) print("New coordinates are:") print_info("New", p1_t, p2_t, p3_t) print("New coordinates are for normalized plane:") v1_t = cpv.normalize(cpv.sub(p1_t, p2_t)) v2_t = cpv.normalize(cpv.sub(p3_t, p2_t)) normal_t = cpv.normalize(cpv.cross_product(v1_t, v2_t)) v2_t = cpv.normalize(cpv.cross_product(normal_t, v1_t)) p1_t2 = cpv.add(v1_t, p2_t) p3_t2 = cpv.add(v2_t, p2_t) print_info("Newnormal", p1_t2, p2_t, p3_t2) if vm1 != None: v1 = cpv.scale(cpv.normalize(v1), vm1) if vm2 != None: v2 = cpv.scale(cpv.normalize(v2), vm2) centrum = p2 if center: corner1 = cpv.add(cpv.add(centrum, v1), v2) corner2 = cpv.sub(cpv.add(centrum, v1), v2) corner3 = cpv.sub(cpv.sub(centrum, v1), v2) corner4 = cpv.add(cpv.sub(centrum, v1), v2) else: corner1 = cpv.add(cpv.add(centrum, v1), v2) corner2 = cpv.add(centrum, v1) corner3 = centrum corner4 = cpv.add(centrum, v2) return plane(corner1, corner2, corner3, corner4, normal, settings)
def append_tri(self): if self.l_vert and not self.l_norm: d0 = cpv.sub(self.l_vert[0], self.l_vert[1]) d1 = cpv.sub(self.l_vert[0], self.l_vert[2]) n0 = cpv.cross_product(d0, d1) n0 = cpv.normalize_failsafe(n0) n1 = [-n0[0], -n0[1], -n0[2]] ns = cpv.scale(n0, 0.002) if not self.tri_flag: self.obj.append(BEGIN) self.obj.append(TRIANGLES) self.tri_flag = 1 self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[0]) self.obj.append(NORMAL) self.obj.extend(n0) self.obj.append(VERTEX) self.obj.extend(cpv.add(self.l_vert[0], ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[1]) self.obj.append(NORMAL) self.obj.extend(n0) self.obj.append(VERTEX) self.obj.extend(cpv.add(self.l_vert[1], ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[2]) self.obj.append(NORMAL) self.obj.extend(n0) self.obj.append(VERTEX) self.obj.extend(cpv.add(self.l_vert[2], ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[0]) self.obj.append(NORMAL) self.obj.extend(n1) self.obj.append(VERTEX) self.obj.extend(cpv.sub(self.l_vert[0], ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[1]) self.obj.append(NORMAL) self.obj.extend(n1) self.obj.append(VERTEX) self.obj.extend(cpv.sub(self.l_vert[1], ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[2]) self.obj.append(NORMAL) self.obj.extend(n1) self.obj.append(VERTEX) self.obj.extend(cpv.sub(self.l_vert[2], ns)) elif self.l_vert and self.t_colr and self.l_norm: if not self.tri_flag: self.obj.append(BEGIN) self.obj.append(TRIANGLES) self.tri_flag = 1 self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[0]) self.obj.append(NORMAL) self.obj.extend(self.l_norm[0]) self.obj.append(VERTEX) self.obj.extend(self.l_vert[0]) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[1]) self.obj.append(NORMAL) self.obj.extend(self.l_norm[1]) self.obj.append(VERTEX) self.obj.extend(self.l_vert[1]) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[2]) self.obj.append(NORMAL) self.obj.extend(self.l_norm[2]) self.obj.append(VERTEX) self.obj.extend(self.l_vert[2]) self.l_vert = None self.t_colr = None self.l_norm = None
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_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 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 cgo_grid(pos1=[0, 0, 0], pos2=[1, 0, 0], pos3=[0, 0, 1], length_x=30, length_z='', npoints_x='', npoints_z='', nwaves_x=2, nwaves_z='', offset_x=0, offset_z='', gain_x=1, gain_z='', thickness=2.0, color='', nstates=60, startframe=1, endframe=1, mode=0, view=0, name='', quiet=1): ''' DESCRIPTION Generates an animated flowing mesh object using the points provided or the current view. The shape is affected substantially by the arguments! USEAGE cgo_grid [ pos1 [, pos2 [, pos3 [, length_x [, length_z [, npoints_x [, npoints_z [, nwaves_x [, nwaves_z [, offset_x [, offset_z [, gain_x [, gain_z [, thickness [, color [, nstates [, startframe [, endframe [, mode [, view [, name [, quiet ]]]]]]]]]]]]]]]]]]]]]] EXAMPLE cgo_grid view=1 ARGUMENTS pos1 = single atom selection (='pk1') or list of 3 floats {default: [0,0,0]} pos2 = single atom selection (='pk2') or list of 3 floats {default: [1,0,0]} pos3 = single atom selection (='pk3') or list of 3 floats {default: [0,0,1]} --> the plane is defined by pos1 (origin) and vectors to pos2 and pos3, respectively length_x = <float>: length of membrane {default: 30} length_z = <float>: length of membrane {default: ''} # same as length_x npoints_x = <int>: number of points(lines) along x-direction {default: ''} #will be set to give a ~1 unit grid npoints_z = <int>: number of points(lines) along z-direction {default: ''} #will be set to give a ~1 unit grid {minimum: 1 # automatic} nwaves_x = <float>: number of complete sin waves along object x-axis {default: 2} nwaves_z = <float>: number of complete sin waves along object z-axis {default: ''} # same as nwaves_x define separately to adjust number of waves in each direction offset_x = <float> phase delay (in degrees) of sin wave in x-axis can be set to affect shape and starting amplitude {default: 0} offset_z = <float> phase delay (in degrees) of sin wave in z-axis can be set to affect shape and starting amplitude {default: ''} # same as offset_x offset_x and offset_z can be used together to phase otherwise identical objects gain_x = <float>: multiplication factor for y-amplitude for x-direction {default: 1} gain_z = <float>: multiplication factor for y-amplitude for z-direction {default: ''} #=gain_x thickness = <float>: line thickness {default: 2} color = color name <string> (e.g. 'skyblue') OR rgb-value list of 3 floats (e.g. [1.0,1.0,1.0]) OR {default: ''} // opposite of background input illegal values for random coloring nstates = <int>: number of states; {default: 60} this setting will define how many states the object will have (per wave) and how fluent and fast the animation will be. Higher values will promote 'fluent' transitions, but decrease flow speed. Note: Frame animation cycles thought the states one at a time and needs to be set accordingly. Can also be used to phase otherwise identical objects. Set to 1 for static object {automatic minimum} startframe: specify starting frame <int> or set (='') to use current frame set to 'append' to extend movie from the last frame {default: 1} endframe: specify end frame <int> or set (='') to use last frame if 'append' is used for startframe, endframe becomes the number of frames to be appended instead {default: 1} Note: if start- and endframe are the same, movie animation will be skipped, the object will be loaded and can be used afterwards mode: defines positioning {default: 0}: 0: pos1 is center 1: pos1 is corner view {default: 0}: '0': off/ uses provided points to create CGO '1': overrides atom selections and uses current orienatation for positioning - pos1 = origin/center - pos2 = origin +1 in camera y - pos3 = origin +1 in camera z name: <string> name of cgo object {default: ''} / automatic quiet: <boolean> toggles output ''' ########## BEGIN OF FUNCTION CODE ########## def get_coord(v): if not isinstance(v, str): try: return v[:3] except: return False if v.startswith('['): return cmd.safe_list_eval(v)[:3] try: if cmd.count_atoms(v) == 1: # atom coordinates return cmd.get_atom_coords(v) else: # more than one atom --> use "center" # alt check! if cmd.count_atoms('(alt *) and not (alt "")') != 0: print "cgo_grid: warning! alternative coordinates found for origin, using center!" view_temp = cmd.get_view() cmd.zoom(v) v = cmd.get_position() cmd.set_view(view_temp) return v except: return False def eval_color(v): try: if not v: v = eval(cmd.get('bg_rgb')) v = map(sum, zip(v, [-1, -1, -1])) v = map(abs, v) if v[0] == v[1] == v[2] == 0.5: # grey v = [0, 0, 0] return v if isinstance(v, list): return v[0:3] if not isinstance(v, str): return v[0:3] if v.startswith('['): return cmd.safe_list_eval(v)[0:3] return list(cmd.get_color_tuple(v)) except: return [random.random(), random.random(), random.random()] cmd.extend("eval_color", eval_color) color = eval_color(color) try: mode = int(mode) except: raise Exception("Input error in Mode") if mode < 0 or mode > 1: raise Exception("Mode out of range!") try: nstates = int(nstates) if nstates < 1: nstates = 1 print "NB! nstates set to 1 (automatic minimum)" length_x = float(length_x) if length_z == '': length_z = length_x else: length_z = float(length_z) if npoints_x == '': npoints_x = int(length_x) + 1 else: npoints_x = int(npoints_x) if npoints_x < 1: npoints_x = 1 print "NB! npoints_x set to 1 (automatic minimum)" if npoints_z == '': npoints_z = int(length_z) + 1 else: npoints_z = int(npoints_z) if npoints_z < 1: npoints_z = 1 print "NB! npoints_x set to 1 (automatic minimum)" nwaves_x = abs(float(nwaves_x)) if nwaves_z == '': nwaves_z = nwaves_x else: nwaves_z = abs(float(nwaves_z)) offset_x = float(offset_x) * math.pi / 180 if offset_z == '': offset_z = offset_x else: offset_z = float(offset_z) * math.pi / 180 thickness = float(thickness) gain_x = float(gain_x) if gain_z == '': gain_z = gain_x else: gain_z = float(gain_z) if not name: name = cmd.get_unused_name('membrane') else: name = str(name) if int(quiet): quiet = True else: quiet = False if int(view): view = True else: view = False except: raise Exception("Input error in parameters!") #prevent auto zooming on object temp_auto_zoom = cmd.get('auto_zoom') cmd.set('auto_zoom', '0') if int(view): xyz1 = cmd.get_position() tempname = cmd.get_unused_name('temp') ori_ax = [[0, 0, 0], [10, 0, 0], [0, 0, 10]] for a in range(0, len(ori_ax)): cmd.pseudoatom(tempname, resi='' + str(a + 1) + '', pos=xyz1) cmd.translate(ori_ax[a], selection='' + tempname + ' and resi ' + str(a + 1) + '', camera='1') ori_ax[a] = cmd.get_atom_coords('' + tempname + ' and resi ' + str(a + 1) + '') cmd.delete(tempname) xyz1 = ori_ax[0] xyz2 = ori_ax[1] xyz3 = ori_ax[2] else: xyz1 = get_coord(pos1) xyz2 = get_coord(pos2) xyz3 = get_coord(pos3) if (not startframe): startframe = cmd.get('frame') if (not endframe): endframe = cmd.count_frames() if endframe == 0: endframe = 1 if (startframe == 'append'): startframe = cmd.count_frames() + 1 try: endframe = int(endframe) cmd.madd('1 x' + str(endframe)) endframe = cmd.count_frames() except ValueError: raise Exception( "Input error: Value for 'endframe' is not integer!") try: startframe = int(startframe) endframe = int(endframe) endframe / startframe startframe / endframe except ValueError: raise Exception("Input error: Failed to convert to integer!") except ZeroDivisionError: raise Exception("Error: unexpected zero value!") except: raise Exception("Unexpected error!") if (nstates == 1): if not quiet: print "Creating one state object!" if startframe > endframe: startframe, endframe = endframe, startframe if not quiet: print "Inverted start and end frames!" ########## BEGIN OF FUNCTIONAL SCRIPT ########## #normalize and get orthogonal vector # define vectors from points xyz2 = cpv.sub(xyz2, xyz1) xyz3 = cpv.sub(xyz3, xyz1) #NB! cpv.get_system2 outputs normalized vectors [x,y,z] xyz4 = cpv.get_system2(xyz2, xyz3) xyz2 = xyz4[0] xyz3 = xyz4[1] for x in range(0, 3): for z in range(0, 3): if x == z: continue if xyz4[x] == xyz4[z]: raise Exception("Illegal vector settings!") xyz4 = cpv.negate(xyz4[2]) #overwrites original # transform origin to corner if mode == 0: if npoints_x > 1: xyz1 = cpv.sub(xyz1, cpv.scale(xyz2, length_x / 2)) if npoints_z > 1: xyz1 = cpv.sub(xyz1, cpv.scale(xyz3, length_z / 2)) #defines array lines nlines = max([npoints_x, npoints_z]) # in case only one line max # create an empty array for xyz entries # this may contain more values than are actually drawn later, # but they are needed to draw lines in each direction grid_xyz = [] for x in range(0, nlines): grid_xyz.append([0.0, 0.0, 0.0] * nlines) # grid distance and steps # prevent zero divisions (lines=1) and enable calculations if lines=0 if (not (npoints_x - 1 < 2)): gap_length_x = length_x / (npoints_x - 1) step_line_x = 2 * math.pi / (npoints_x - 1) else: gap_length_x = length_x step_line_x = 2 * math.pi if (not (npoints_z - 1 < 2)): gap_length_z = length_z / (npoints_z - 1) step_line_z = 2 * math.pi / (npoints_z - 1) else: gap_length_z = length_z step_line_z = 2 * math.pi # calculate steps if nstates == 1: step_state = 0 else: step_state = 2 * math.pi / (nstates - 1) ########## BEGIN STATE ITERATION ########## # create a n-state object in PyMol for a in range(0, nstates): # Reset object obj = [] #assign color obj.extend([COLOR, color[0], color[1], color[2]]) #set width obj.extend([LINEWIDTH, thickness]) # Calculate xyz-coordinates for each line for x in range(0, nlines): for z in range(0, nlines): # update grid position in x-direction xyztemp = cpv.add(xyz1, cpv.scale(xyz2, gap_length_x * x)) # update grid position in z-direction xyztemp = cpv.add(xyztemp, cpv.scale(xyz3, gap_length_z * z)) # calculate amplitude for y-direction and update grid position y_amp=(\ gain_x*math.sin(offset_x+nwaves_x*((a*step_state)+(x*step_line_x)))/2+\ gain_z*math.sin(offset_z+nwaves_z*((a*step_state)+(z*step_line_z)))/2\ ) xyztemp = cpv.add(xyztemp, cpv.scale(xyz4, y_amp)) grid_xyz[x][z] = xyztemp #Now the coordinates for this state are defined! #Now the coordinates are read separately: # allow to run the loops as often as required #if npoints_x==0:npoints_x=npoints_z #lines along z in x direction for z in range(0, npoints_z): obj.extend([BEGIN, LINE_STRIP]) for x in range(0, npoints_x): obj.extend([ VERTEX, grid_xyz[x][z][0], grid_xyz[x][z][1], grid_xyz[x][z][2] ]) obj.append(END) #lines along x in z direction for x in range(0, npoints_x): obj.extend([BEGIN, LINE_STRIP]) for z in range(0, npoints_z): obj.extend([ VERTEX, grid_xyz[x][z][0], grid_xyz[x][z][1], grid_xyz[x][z][2] ]) obj.append(END) # Load state into PyMOL object: cmd.load_cgo(obj, name, a + 1) # All states of object loaded! #reset auto zooming to previous value cmd.set('auto_zoom', temp_auto_zoom) # animate object using frames instead of states if (not endframe == startframe): framecount = 0 countvar = 1 for frame in range(startframe, endframe + 1): #increase count framecount = framecount + countvar # set state in frame cmd.mappend( frame, "/cmd.set('state', %s, %s)" % (repr(framecount), repr(name))) # Looping if framecount == nstates: if ((int(nwaves_x) != nwaves_x) or (int(nwaves_z) != nwaves_z)): #if not complete sinus wave #--> reverse wave in ongoing animation countvar = -1 else: #wave is complete --> repeat framecount = 0 # count up from first state if framecount == 1: countvar = 1 if not quiet: print "object loaded and animated with frames!" else: if not quiet: print "object loaded!" #OUTPUT if not quiet: print "Grid variables for:", name print "corner:", xyz1 print "vector 1:", xyz2 print "vector 2:", xyz3 print "length_x:", length_x print "length_z:", length_z print "npoints_x:", npoints_x print "npoints_z:", npoints_z print "nwaves_x:", nwaves_x print "nwaves_z:", nwaves_z print "offset_x:", offset_x print "offset_z:", offset_z print "gain_x:", gain_x print "gain_z:", gain_z print "thickness:", thickness print "states", nstates if (not endframe == startframe): print "frames: start:", startframe, "end:", endframe return grid_xyz
def append_tri(self): if self.l_vert and not self.l_norm: d0 = cpv.sub(self.l_vert[0],self.l_vert[1]) d1 = cpv.sub(self.l_vert[0],self.l_vert[2]) n0 = cpv.cross_product(d0,d1) n0 = cpv.normalize_failsafe(n0) n1 = [-n0[0],-n0[1],-n0[2]] ns = cpv.scale(n0,0.002) if not self.tri_flag: self.obj.append(BEGIN) self.obj.append(TRIANGLES) self.tri_flag = 1 self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[0]) self.obj.append(NORMAL) self.obj.extend(n0) self.obj.append(VERTEX) self.obj.extend(cpv.add(self.l_vert[0],ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[1]) self.obj.append(NORMAL) self.obj.extend(n0) self.obj.append(VERTEX) self.obj.extend(cpv.add(self.l_vert[1],ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[2]) self.obj.append(NORMAL) self.obj.extend(n0) self.obj.append(VERTEX) self.obj.extend(cpv.add(self.l_vert[2],ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[0]) self.obj.append(NORMAL) self.obj.extend(n1) self.obj.append(VERTEX) self.obj.extend(cpv.sub(self.l_vert[0],ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[1]) self.obj.append(NORMAL) self.obj.extend(n1) self.obj.append(VERTEX) self.obj.extend(cpv.sub(self.l_vert[1],ns)) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[2]) self.obj.append(NORMAL) self.obj.extend(n1) self.obj.append(VERTEX) self.obj.extend(cpv.sub(self.l_vert[2],ns)) elif self.l_vert and self.t_colr and self.l_norm: if not self.tri_flag: self.obj.append(BEGIN) self.obj.append(TRIANGLES) self.tri_flag = 1 self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[0]) self.obj.append(NORMAL) self.obj.extend(self.l_norm[0]) self.obj.append(VERTEX) self.obj.extend(self.l_vert[0]) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[1]) self.obj.append(NORMAL) self.obj.extend(self.l_norm[1]) self.obj.append(VERTEX) self.obj.extend(self.l_vert[1]) self.obj.append(COLOR) # assuming unicolor self.obj.extend(self.t_colr[2]) self.obj.append(NORMAL) self.obj.extend(self.l_norm[2]) self.obj.append(VERTEX) self.obj.extend(self.l_vert[2]) self.l_vert=None self.t_colr=None self.l_norm=None
def update_box(self): if self.points_name in self.cmd.get_names(): model = self.cmd.get_model(self.points_name) self.coord = ( model.atom[0].coord, model.atom[1].coord, model.atom[2].coord, model.atom[3].coord, ) p = self.coord[0] d10 = sub(self.coord[1], p) d20 = sub(self.coord[2], p) d30 = sub(self.coord[3], p) x10_20 = cross_product(d10, d20) if self.mode != 'quad': if dot_product(d30, x10_20) < 0.0: p = model.atom[1].coord d10 = sub(self.coord[0], p) d20 = sub(self.coord[2], p) d30 = sub(self.coord[3], p) n10_20 = normalize(x10_20) n10 = normalize(d10) d100 = d10 d010 = remove_component(d20, n10) if self.mode != 'quad': d001 = project(d30, n10_20) else: d001 = n10_20 n100 = normalize(d100) n010 = normalize(d010) n001 = normalize(d001) f100 = reverse(n100) f010 = reverse(n010) f001 = reverse(n001) if self.mode == 'quad': p000 = p p100 = add(p, remove_component(d10, n001)) p010 = add(p, remove_component(d20, n001)) p001 = add(p, remove_component(d30, n001)) else: p000 = p p100 = add(p, d100) p010 = add(p, d010) p001 = add(p, d001) p110 = add(p100, d010) p011 = add(p010, d001) p101 = add(p100, d001) p111 = add(p110, d001) obj = [] if self.mode == 'box': # standard box obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(f001) obj.append(VERTEX) obj.extend(p000) obj.append(VERTEX) obj.extend(p010) obj.append(VERTEX) obj.extend(p100) obj.append(VERTEX) obj.extend(p110) obj.append(END) obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(n001) obj.append(VERTEX) obj.extend(p001) obj.append(VERTEX) obj.extend(p101) obj.append(VERTEX) obj.extend(p011) obj.append(VERTEX) obj.extend(p111) obj.append(END) obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(f010) obj.append(VERTEX) obj.extend(p000) obj.append(VERTEX) obj.extend(p100) obj.append(VERTEX) obj.extend(p001) obj.append(VERTEX) obj.extend(p101) obj.append(END) obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(n010) obj.append(VERTEX) obj.extend(p010) obj.append(VERTEX) obj.extend(p011) obj.append(VERTEX) obj.extend(p110) obj.append(VERTEX) obj.extend(p111) obj.append(END) obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(f100) obj.append(VERTEX) obj.extend(p000) obj.append(VERTEX) obj.extend(p001) obj.append(VERTEX) obj.extend(p010) obj.append(VERTEX) obj.extend(p011) obj.append(END) obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(n100) obj.append(VERTEX) obj.extend(p100) obj.append(VERTEX) obj.extend(p110) obj.append(VERTEX) obj.extend(p101) obj.append(VERTEX) obj.extend(p111) obj.append(END) model.atom[0].coord = p000 model.atom[1].coord = p100 model.atom[2].coord = add(p010, scale(d100, 0.5)) model.atom[3].coord = add(add(p001, scale(d010, 0.5)), d100) elif self.mode == 'walls': obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(n001) obj.append(VERTEX) obj.extend(p000) obj.append(VERTEX) obj.extend(p100) obj.append(VERTEX) obj.extend(p010) obj.append(VERTEX) obj.extend(p110) obj.append(END) obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(n010) obj.append(VERTEX) obj.extend(p000) obj.append(VERTEX) obj.extend(p001) obj.append(VERTEX) obj.extend(p100) obj.append(VERTEX) obj.extend(p101) obj.append(END) obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(n100) obj.append(VERTEX) obj.extend(p000) obj.append(VERTEX) obj.extend(p010) obj.append(VERTEX) obj.extend(p001) obj.append(VERTEX) obj.extend(p011) obj.append(END) model.atom[0].coord = p000 model.atom[1].coord = p100 model.atom[2].coord = p010 model.atom[3].coord = p001 elif self.mode == 'plane': obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(n001) obj.append(VERTEX) obj.extend(p000) obj.append(VERTEX) obj.extend(p100) obj.append(VERTEX) obj.extend(p010) obj.append(VERTEX) obj.extend(p110) obj.append(END) model.atom[0].coord = p000 model.atom[1].coord = p100 model.atom[2].coord = p010 model.atom[3].coord = add(add(p001, scale(d010, 0.5)), scale(d100, 0.5)) elif self.mode == 'quad': obj.extend([BEGIN, TRIANGLE_STRIP]) obj.append(NORMAL) obj.extend(n001) obj.append(VERTEX) obj.extend(p000) obj.append(VERTEX) obj.extend(p100) obj.append(VERTEX) obj.extend(p010) obj.append(VERTEX) obj.extend(p001) obj.append(END) model.atom[0].coord = p000 model.atom[1].coord = p100 model.atom[2].coord = p010 model.atom[3].coord = p001 self.cmd.load_model(model, '_tmp', zoom=0) self.cmd.update(self.points_name, "_tmp") self.cmd.delete("_tmp") # then we load it into PyMOL self.cmd.delete(self.cgo_name) self.cmd.load_cgo(obj, self.cgo_name, zoom=0) self.cmd.order(self.cgo_name + " " + self.points_name, sort=1, location='bottom') self.cmd.set("nonbonded_size", math.sqrt(dot_product(d10, d10)) / 10, self.points_name)
def calculateNewPoint(p1, p2, distance): v1 = cpv.normalize(cpv.sub(p1, p2)) return cpv.add(p1, cpv.scale(v1, distance))
def cgo_arrow(atom1='pk1', atom2='pk2', radius=0.5, gap=0.0, hlength=-1, hradius=-1, color='black black', name=''): ''' #I modify the color the line just before 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 ''' from chempy import cpv radius, gap = float(radius), float(gap) hlength, hradius = float(hlength), float(hradius) 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.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 visualize_orientation(direction, center=[0.0] * 3, scale=1.0, symmetric=False, color='green', color2='red', *, _self=cmd): ''' DESCRIPTION Draw an arrow. Helper function for "helix_orientation" etc. ''' from pymol import cgo color_list = _self.get_color_tuple(color) color2_list = _self.get_color_tuple(color2) if symmetric: scale *= 0.5 end = cpv.add(center, cpv.scale(direction, scale)) radius = 0.3 obj = [cgo.SAUSAGE] obj.extend(center) obj.extend(end) obj.extend([ radius, 0.8, 0.8, 0.8, ]) obj.extend(color_list) if symmetric: start = cpv.sub(center, cpv.scale(direction, scale)) obj.append(cgo.SAUSAGE) obj.extend(center) obj.extend(start) obj.extend([ radius, 0.8, 0.8, 0.8, ]) obj.extend(color2_list) coneend = cpv.add( end, cpv.scale(direction, 4.0 * radius / cpv.length(direction))) obj.append(cgo.CONE) obj.extend(end) obj.extend(coneend) obj.extend([ radius * 1.75, 0.0, ]) obj.extend(color_list * 2) obj.extend([ 1.0, 1.0, # Caps ]) _self.load_cgo(obj, _self.get_unused_name('oriVec'), zoom=0)
def drawmol(self,model): print 'drawmol' self.sphere_list= glGenLists(1) glNewList(self.sphere_list, GL_COMPILE) print 'making sphere list of ', len(model.atom),' atoms' for a in model.atom: try: z = a.get_number() except Exception: z = 0 r,g,b = colours[z] glColor3f(r,g,b) glPushMatrix() x = a.coord[0] y = a.coord[1] zz = a.coord[2] glTranslatef (x, y, zz) fac = rcov[z] / 2.0 glScale(fac,fac,fac) glutSolidSphere(0.4, 16, 16) glPopMatrix() glEndList() self.line_list= glGenLists(1) glNewList(self.line_list, GL_COMPILE) glLineWidth(2.0) glBegin(GL_LINES) line_count = 0 for a in model.atom: try: c = a.conn except AttributeError: c = [] for t in c: if t.get_index() > a.get_index(): line_count = line_count + 1 vec = cpv.sub(t.coord, a.coord) mid = cpv.add(a.coord,cpv.scale(vec,0.5)) try: z = a.get_number() except Exception: z = 0 r,g,b = colours[z] glColor3f(r, g, b) glVertex3f(a.coord[0],a.coord[1],a.coord[2]) glVertex3f(mid[0],mid[1],mid[2]) try: z = t.get_number() except Exception: z = 0 r,g,b = colours[z] glColor3f(r, g, b) glVertex3f(mid[0],mid[1],mid[2]) glVertex3f(t.coord[0],t.coord[1],t.coord[2]) glEnd() glEndList() print 'made line list of ', line_count, ' lines'
def cgo_arrow(atom1='pk1', atom2='pk2', radius=0.5, gap=0.0, hlength=-1, hradius=-1, color='blue red', name=''): ''' 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 ''' from chempy import cpv radius, gap = float(radius), float(gap) hlength, hradius = float(hlength), float(hradius) 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.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 set_view(view, center, trans, volume, persp): ''' view is their 4x4 center is the centor of rotation in tranformed coordinates ''' view = list(view) # print view[0:4] # print view[4:8] # print view[8:12] # print view[12:16] # print "\nmaestro_center: %8.3f %8.3f %8.3f"%tuple(center) # print "maestro_transl: %8.3f %8.3f %8.3f"%tuple(trans) mat = [ view[0:3], view[4:7], view[8:11] ] tmp = cpv.sub(center,view[12:15]) pymol_center = cpv.transform(mat,tmp) # print "volumeX: %8.3f %8.3f"%(tuple(volume[0:2])) # print "volumeY: %8.3f %8.3f"%(tuple(volume[2:4])) # print "volumeZ: %8.3f %8.3f"%(tuple(volume[4:6])) # print "pymol_center: %8.3f %8.3f %8.3f"%tuple(pymol_center) # print persp if persp<0.0: pymol_ortho = 1.0 else: pymol_ortho = 0.0 if pymol_ortho==0.0: fov = 1 + 100*(persp - 1.0)/3.0 cmd.set('field_of_view',fov) fov = (math.pi * float(cmd.get("field_of_view")) / 180.0) # unclear why we have to multiple by 1.17 to get the correct look camera_dist = 1.17 * (abs(volume[2] - volume[3])/2.0)/math.atan(fov/2.0) vol_center = [ (volume[0]+volume[1])/2.0, (volume[2]+volume[3])/2.0, (volume[4]+volume[5])/2.0 ] pymol_objective = [ trans[0] + center[0] - vol_center[0], trans[1] + center[1] - vol_center[1], -camera_dist ] # print "pymol_objective: %8.3f %8.3f %8.3f"%tuple(pymol_objective) pymol_front = center[2] + trans[2] - volume[4] - pymol_objective[2] pymol_back = center[2] + trans[2] - volume[5] - pymol_objective[2] pymol_view = cmd.get_view() cur_view = ( view[0:3] + view[4:7] + view[8:11] + pymol_objective + pymol_center + [ pymol_front, pymol_back, pymol_ortho ] ) # print cur_view cmd.set_view(tuple(cur_view))
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 update_box(self): if self.points_name in self.cmd.get_names(): model = self.cmd.get_model(self.points_name) self.coord = ( model.atom[0].coord, model.atom[1].coord, model.atom[2].coord, model.atom[3].coord, ) p = self.coord[0] d10 = sub(self.coord[1], p) d20 = sub(self.coord[2], p) d30 = sub(self.coord[3], p) x10_20 = cross_product(d10,d20) if self.mode != 'quad': if dot_product(d30,x10_20)<0.0: p = model.atom[1].coord d10 = sub(self.coord[0], p) d20 = sub(self.coord[2], p) d30 = sub(self.coord[3], p) n10_20 = normalize(x10_20) n10 = normalize(d10) d100 = d10 d010 = remove_component(d20, n10) if self.mode != 'quad': d001 = project(d30, n10_20) else: d001 = n10_20 n100 = normalize(d100) n010 = normalize(d010) n001 = normalize(d001) f100 = reverse(n100) f010 = reverse(n010) f001 = reverse(n001) if self.mode == 'quad': p000 = p p100 = add(p, remove_component(d10,n001)) p010 = add(p, remove_component(d20,n001)) p001 = add(p, remove_component(d30,n001)) else: p000 = p p100 = add(p,d100) p010 = add(p,d010) p001 = add(p,d001) p110 = add(p100, d010) p011 = add(p010, d001) p101 = add(p100, d001) p111 = add(p110, d001) obj = [] if self.mode == 'box': # standard box obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(f001) obj.append(VERTEX); obj.extend(p000) obj.append(VERTEX); obj.extend(p010) obj.append(VERTEX); obj.extend(p100) obj.append(VERTEX); obj.extend(p110) obj.append(END) obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(n001) obj.append(VERTEX); obj.extend(p001) obj.append(VERTEX); obj.extend(p101) obj.append(VERTEX); obj.extend(p011) obj.append(VERTEX); obj.extend(p111) obj.append(END) obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(f010) obj.append(VERTEX); obj.extend(p000) obj.append(VERTEX); obj.extend(p100) obj.append(VERTEX); obj.extend(p001) obj.append(VERTEX); obj.extend(p101) obj.append(END) obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(n010) obj.append(VERTEX); obj.extend(p010) obj.append(VERTEX); obj.extend(p011) obj.append(VERTEX); obj.extend(p110) obj.append(VERTEX); obj.extend(p111) obj.append(END) obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(f100) obj.append(VERTEX); obj.extend(p000) obj.append(VERTEX); obj.extend(p001) obj.append(VERTEX); obj.extend(p010) obj.append(VERTEX); obj.extend(p011) obj.append(END) obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(n100) obj.append(VERTEX); obj.extend(p100) obj.append(VERTEX); obj.extend(p110) obj.append(VERTEX); obj.extend(p101) obj.append(VERTEX); obj.extend(p111) obj.append(END) model.atom[0].coord = p000 model.atom[1].coord = p100 model.atom[2].coord = add(p010, scale(d100,0.5)) model.atom[3].coord = add(add(p001, scale(d010,0.5)),d100) elif self.mode=='walls': obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(n001) obj.append(VERTEX); obj.extend(p000) obj.append(VERTEX); obj.extend(p100) obj.append(VERTEX); obj.extend(p010) obj.append(VERTEX); obj.extend(p110) obj.append(END) obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(n010) obj.append(VERTEX); obj.extend(p000) obj.append(VERTEX); obj.extend(p001) obj.append(VERTEX); obj.extend(p100) obj.append(VERTEX); obj.extend(p101) obj.append(END) obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(n100) obj.append(VERTEX); obj.extend(p000) obj.append(VERTEX); obj.extend(p010) obj.append(VERTEX); obj.extend(p001) obj.append(VERTEX); obj.extend(p011) obj.append(END) model.atom[0].coord = p000 model.atom[1].coord = p100 model.atom[2].coord = p010 model.atom[3].coord = p001 elif self.mode=='plane': obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(n001) obj.append(VERTEX); obj.extend(p000) obj.append(VERTEX); obj.extend(p100) obj.append(VERTEX); obj.extend(p010) obj.append(VERTEX); obj.extend(p110) obj.append(END) model.atom[0].coord = p000 model.atom[1].coord = p100 model.atom[2].coord = p010 model.atom[3].coord = add(add(p001, scale(d010,0.5)),scale(d100,0.5)) elif self.mode=='quad': obj.extend([ BEGIN, TRIANGLE_STRIP ]) obj.append(NORMAL); obj.extend(n001) obj.append(VERTEX); obj.extend(p000) obj.append(VERTEX); obj.extend(p100) obj.append(VERTEX); obj.extend(p010) obj.append(VERTEX); obj.extend(p001) obj.append(END) model.atom[0].coord = p000 model.atom[1].coord = p100 model.atom[2].coord = p010 model.atom[3].coord = p001 self.cmd.load_model(model, '_tmp', zoom=0) self.cmd.update(self.points_name,"_tmp") self.cmd.delete("_tmp") # then we load it into PyMOL self.cmd.delete(self.cgo_name) self.cmd.load_cgo(obj,self.cgo_name,zoom=0) self.cmd.order(self.cgo_name+" "+self.points_name,sort=1,location='bottom') self.cmd.set("nonbonded_size",math.sqrt(dot_product(d10,d10))/10,self.points_name)
def cgo_arrow(origin, endpoint, color='blue', radius=0.10, gap=0.0, hlength=-1, hradius=-1, type='electric', name='', scaling = 7): ''' :param origin: List representing origin point of vector to be drawn :type origin: List of floats :param endpoint: List representing endpoint of vector to be drawn :type endpoint: List of floats :param color: Color of arrow :type color: String, optional - default blue :param radius: Radius of cylinder portion of arrow :type radius: Float, optional - default .1 :param gap: Specifies a gap between the head and body of the arrow, if desired :type gap: Float, optional - default 0 :param hlength: Length of the head of the arrow :type hlength: Float, optional - default -1 :param hradius: Radius of the head of the arrow :type hradius: Float, optional - default -1 :param type: Type of vector being drawn, electric or magnetic :type type: String, optional - default electric :param name: Name to be shown in PyMol for the cgo object :type name: String, optional - default blank :param scaling: Scaling factor that is passed to scale_endpoint function :type scaling: Int, optional - default 7 :return: None ''' from chempy import cpv #converting parameters to floats radius, gap = float(radius), float(gap) hlength, hradius = float(hlength), float(hradius) if type == 'electric': color = 'red' name = 'electric'+name if type == 'magnetic': color = 'blue' name = 'magnetic'+name try: color1, color2 = color.split() except: color1 = color2 = color color1 = list(cmd.get_color_tuple(color1)) color2 = list(cmd.get_color_tuple(color2)) if origin == 'sele': xyz1 = cmd.get_coords('sele', 1) xyz1 = xyz1.flatten() xyz1 = xyz1.tolist() length=np.linalg.norm(np.array(endpoint)) xyz2 = scale_endpoint(endpoint,scaling) xyz2 = shift_vectors(xyz2, xyz1) else: xyz1 = origin length=np.linalg.norm(np.array(endpoint)-np.array(xyz1)) xyz2 = scale_endpoint(endpoint,scaling) 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) ##Location where cylinder switches to cone xyz3 = cpv.add(cpv.scale(normal, hlength), xyz2) obj = [cgo.CYLINDER] + xyz1 + xyz3 + [radius] + color1 + color1 + \ [cgo.CONE] + xyz3 + xyz2 + [hradius, 0.0] + color1 + color2 + \ [1.0, 0.0] print(obj) ##Place pseudoatom with label at midpoint of vector v0=np.array(xyz1) v1=np.array(xyz2) loc=(v0+v1)/2 if not name: name = cmd.get_unused_name('arrow') cmd.load_cgo(obj, f"vec_{name}") ##For some reason pos fails, but it just happens to put it where I want cmd.pseudoatom(f"lab_{name}",name="lab_"+name,label=f"{length:.2f}")#,pos=loc cmd.group(name,members=f"lab_{name} vec_{name}")