# Lightweight ET Viewer using PyMOL # Script/plugin by Rhonald Lua (lua@bcm.edu) # Some parts of GUI code based on apbs_tools.py by Michael Lerner. # # THE AUTHOR(S) DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN # NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF # USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR # OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. # ---------------------------------------------------------------------- #Possible locations of the PyMOL plugins directory: #On Windows, this is usually: # C:\Program Files\DeLano Scientific\PyMOL\modules\pmg_tk\startup #On Macintosh, with the X11/Hybrid version, the location is probably: # PyMOLX11Hybrid.app/pymol/modules/pmg_tk/startup #On a linux machine, it might be under: # /var/lib/python-support/python2.4/pmg_tk/startup/ from pymol import cmd #This launches pymol from Tkinter import * import os,fnmatch,time,math,colorsys,string,urllib import Tkinter,Pmw,tkColorChooser #from tkSimpleDialog import * from threading import Thread, Event #Square of cutoff distance defining adjacency or contact #between residues CONTACT_DISTANCE2=16.0 #Enable or disable multithreading on certain operations _ET_THREADING=0 ####################################################### # Functions useful for calculating clustering z-score # ####################################################### def _et_calcDist(self,atoms1,atoms2): """return smallest distance (squared) between two groups of atoms""" #(not distant by more than ~100 A) #mind2=CONTACT_DISTANCE2+100 c1=atoms1[0] #atoms must not be empty c2=atoms2[0] mind2=(c1[0]-c2[0])*(c1[0]-c2[0])+\ (c1[1]-c2[1])*(c1[1]-c2[1])+\ (c1[2]-c2[2])*(c1[2]-c2[2]) for c1 in atoms1: for c2 in atoms2: d2=(c1[0]-c2[0])*(c1[0]-c2[0])+\ (c1[1]-c2[1])*(c1[1]-c2[1])+\ (c1[2]-c2[2])*(c1[2]-c2[2]) if d2_S)/sigma_S The steps are: 1. Calculate Selection Clustering Weight (SCW) 'w' 2. Calculate mean SCW (_S) in the ensemble of random selections of len(reslist) residues 3. Calculate mean square SCW (_S) and standard deviation (sigma_S) Reference: Mihalek, Res, Yao, Lichtarge (2003) reslist - a list of int's of protein residue numbers, e.g. ET residues L - length of protein A - the adjacency matrix implemented as a dictionary. The first key is related to the second key by resi_S and _S. #Use expressions (3),(4),(5),(6) in Reference. M=len(reslist) #L=self.ranksObj1.getSize() pi1=M*(M-1.0)/(L*(L-1.0)) pi2=pi1*(M-2.0)/(L-2.0) pi3=pi2*(M-3.0)/(L-3.0) w_ave=0 w2_ave=0 if bias==1: for resi, neighborsj in A.items(): for resj in neighborsj: w_ave+=(resj-resi) for resk, neighborsl in A.items(): for resl in neighborsl: if (resi==resk and resj==resl) or \ (resi==resl and resj==resk): w2_ave+=pi1*(resj-resi)*(resl-resk) elif (resi==resk) or (resj==resl) or \ (resi==resl) or (resj==resk): w2_ave+=pi2*(resj-resi)*(resl-resk) else: w2_ave+=pi3*(resj-resi)*(resl-resk) elif bias==0: for resi, neighborsj in A.items(): w_ave+=len(neighborsj) for resj in neighborsj: #w_ave+=1 for resk, neighborsl in A.items(): for resl in neighborsl: if (resi==resk and resj==resl) or \ (resi==resl and resj==resk): w2_ave+=pi1 elif (resi==resk) or (resj==resl) or \ (resi==resl) or (resj==resk): w2_ave+=pi2 else: w2_ave+=pi3 w_ave=w_ave*pi1 #print "w_ave", w_ave sigma=math.sqrt(w2_ave-w_ave*w_ave) #print "sigma", sigma if sigma==0: #Response to Bioinformatics reviewer 08/24/10 return 'NA' return (w-w_ave)/sigma def _et_computeInterface(self,structurename1,structurename2,dist2): """Get the interface residues between structurename1 and structurename2""" try: model1=cmd.get_model(structurename1) except Exception: print "Structure \'%s\' does not exist!" % structurename1 return None, None, None, None try: model2=cmd.get_model(structurename2) except Exception: print "Structure \'%s\' does not exist!" % structurename2 return None, None, None, None ResAtoms1={} #List of atom coordinates indexed by residue number #atom.resi is a string, leave it as string for i in range(len(model1.atom)): atom=model1.atom[i] try: ResAtoms1[int(atom.resi)].append(atom.coord) except KeyError: ResAtoms1[int(atom.resi)]=[atom.coord] ResAtoms2={} #List of atom coordinates indexed by residue number for i in range(len(model2.atom)): atom=model2.atom[i] try: ResAtoms2[int(atom.resi)].append(atom.coord) except KeyError: ResAtoms2[int(atom.resi)]=[atom.coord] A1={} A2={} for res1 in ResAtoms1.keys(): for res2 in ResAtoms2.keys(): if(self.calcDist(ResAtoms1[res1], ResAtoms2[res2])_S)/sigma_S The steps are: 1. Calculate the number of couples ('w') between residues in reslist1 and reslist2 2. Calculate mean number of couples (_S) in the ensemble of random selections of len(reslist) residues on each protein partner 3. Calculate mean square number of couples (_S) and standard deviation (sigma_S) reslist1 and reslist2 - lists of int's of protein residue numbers, e.g. ET residues L1 and L2 - lengths of protein partners A - the adjacency matrix of interface residues implemented as a dictionary""" w=0 for resi in reslist1: for resj in reslist2: try: if resj in A[resi]: #A is a dictionary of lists of neighbors w+=1 except KeyError: pass #Calculate _S and _S. M1=len(reslist1) M2=len(reslist2) c1=M1*1.0/L1 c2=M2*1.0/L2 SiSk=c1*(M1-1.0)/(L1-1.0) SjSl=c2*(M2-1.0)/(L2-1.0) w_ave=0 w2_ave=0 for resi, neighborsj in A.items(): w_ave+=len(neighborsj) #total number of interface couples when the loop ends for resj in neighborsj: for resk, neighborsl in A.items(): for resl in neighborsl: if resi==resk: SiSjSkSl=c1 else: SiSjSkSl=SiSk if resj==resl: SiSjSkSl*=c2 else: SiSjSkSl*=SjSl w2_ave+=SiSjSkSl w_ave=w_ave*c1*c2 #print "w_ave", w_ave sigma=math.sqrt(w2_ave-w_ave*w_ave) #print "sigma", sigma return w, w_ave, sigma ################################################################# ##try: ## PYMOL_PATH=os.environ['PYMOL_PATH'] ##except KeyError: ## PYMOL_PATH='.' def __init__(self): self.menuBar.addmenuitem('Plugin', 'command', 'Launch PyETV', label='PyETV...', command = lambda s=self: ETTools(s)) class FileDialogButtonClassFactory: def get(fn,filter='*'): """This returns a FileDialogButton class that will call the specified function with the resulting file. """ class FileDialogButton(Tkinter.Button): # This is just an ordinary button with special colors. def __init__(self, master=None, cnf={}, **kw): '''when we get a file, we call fn(filename)''' self.fn = fn self.__toggle = 0 apply(Tkinter.Button.__init__, (self, master, cnf), kw) self.configure(command=self.set) def set(self): fd = PmwFileDialog(self.master,filter=filter) fd.title('Please choose a file') n=fd.askfilename() if n is not None: self.fn(n) return FileDialogButton get = staticmethod(get) # # The classes PmwFileDialog and PmwExistingFileDialog and the _errorpop function # are taken from the Pmw contrib directory. The attribution given in that file # is: ################################################################################ # Filename dialogs using Pmw # # (C) Rob W.W. Hooft, Nonius BV, 1998 # # Modifications: # # J. Willem M. Nissink, Cambridge Crystallographic Data Centre, 8/2002 # Added optional information pane at top of dialog; if option # 'info' is specified, the text given will be shown (in blue). # Modified example to show both file and directory-type dialog # # No Guarantees. Distribute Freely. # Please send bug-fixes/patches/features to # ################################################################################ #import os,fnmatch,time #import Tkinter,Pmw #Pmw.setversion("0.8.5") ##def _errorpop(master,text): ## d=Pmw.MessageDialog(master, ## title="Error", ## message_text=text, ## buttons=("OK",)) ## d.component('message').pack(ipadx=15,ipady=15) ## d.activate() ## d.destroy() class PmwFileDialog(Pmw.Dialog): """File Dialog using Pmw""" def __init__(self, parent = None, **kw): # Define the megawidget options. optiondefs = ( ('filter', '*', self.newfilter), ('directory', os.getcwd(), self.newdir), ('filename', '', self.newfilename), ('historylen',10, None), ('command', None, None), ('info', None, None), ) self.defineoptions(kw, optiondefs) # Initialise base class (after defining options). Pmw.Dialog.__init__(self, parent) self.withdraw() # Create the components. interior = self.interior() if self['info'] is not None: rowoffset=1 dn = self.infotxt() dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3) else: rowoffset=0 dn = self.mkdn() dn.grid(row=0+rowoffset,column=0,columnspan=2,padx=3,pady=3) del dn # Create the directory list component. dnb = self.mkdnb() dnb.grid(row=1+rowoffset,column=0,sticky='news',padx=3,pady=3) del dnb # Create the filename list component. fnb = self.mkfnb() fnb.grid(row=1+rowoffset,column=1,sticky='news',padx=3,pady=3) del fnb # Create the filter entry ft = self.mkft() ft.grid(row=2+rowoffset,column=0,columnspan=2,padx=3,pady=3) del ft # Create the filename entry fn = self.mkfn() fn.grid(row=3+rowoffset,column=0,columnspan=2,padx=3,pady=3) fn.bind('',self.okbutton) del fn # Buttonbox already exists bb=self.component('buttonbox') bb.add('OK',command=self.okbutton) bb.add('Cancel',command=self.cancelbutton) del bb Pmw.alignlabels([self.component('filename'), self.component('filter'), self.component('dirname')]) def infotxt(self): """ Make information block component at the top """ return self.createcomponent( 'infobox', (), None, Tkinter.Label, (self.interior(),), width=51, relief='groove', foreground='darkblue', justify='left', text=self['info'] ) def mkdn(self): """Make directory name component""" return self.createcomponent( 'dirname', (), None, Pmw.ComboBox, (self.interior(),), entryfield_value=self['directory'], entryfield_entry_width=40, entryfield_validate=self.dirvalidate, selectioncommand=self.setdir, labelpos='w', label_text='Directory:') def mkdnb(self): """Make directory name box""" return self.createcomponent( 'dirnamebox', (), None, Pmw.ScrolledListBox, (self.interior(),), label_text='directories', labelpos='n', hscrollmode='dynamic', #'none' originally dblclickcommand=self.selectdir) def mkft(self): """Make filter""" return self.createcomponent( 'filter', (), None, Pmw.ComboBox, (self.interior(),), entryfield_value=self['filter'], entryfield_entry_width=40, selectioncommand=self.setfilter, labelpos='w', label_text='Filter:') def mkfnb(self): """Make filename list box""" return self.createcomponent( 'filenamebox', (), None, Pmw.ScrolledListBox, (self.interior(),), label_text='files', labelpos='n', hscrollmode='dynamic', #'none' originally. 'dynamic' is supposed to be the default selectioncommand=self.singleselectfile, dblclickcommand=self.selectfile) def mkfn(self): """Make file name entry""" return self.createcomponent( 'filename', (), None, Pmw.ComboBox, (self.interior(),), entryfield_value=self['filename'], entryfield_entry_width=40, entryfield_validate=self.filevalidate, selectioncommand=self.setfilename, labelpos='w', label_text='Filename:') def dirvalidate(self,string): if os.path.isdir(string): return Pmw.OK else: return Pmw.PARTIAL def filevalidate(self,string): if string=='': return Pmw.PARTIAL elif os.path.isfile(string): return Pmw.OK elif os.path.exists(string): return Pmw.PARTIAL else: return Pmw.OK def okbutton(self): """OK action: user thinks he has input valid data and wants to proceed. This is also called by in the filename entry""" fn=self.component('filename').get() self.setfilename(fn) if self.validate(fn): self.canceled=0 self.deactivate() def cancelbutton(self): """Cancel the operation""" self.canceled=1 self.deactivate() def tidy(self,w,v): """Insert text v into the entry and at the top of the list of the combobox w, remove duplicates""" if not v: return entry=w.component('entry') entry.delete(0,'end') entry.insert(0,v) list=w.component('scrolledlist') list.insert(0,v) index=1 while indexself['historylen']: list.delete(index) else: index=index+1 w.checkentry() def setfilename(self,value): if not value: return value=os.path.join(self['directory'],value) dir,fil=os.path.split(value) self.configure(directory=dir,filename=value) c=self['command'] if callable(c): c() def newfilename(self): """Make sure a newly set filename makes it into the combobox list""" self.tidy(self.component('filename'),self['filename']) def setfilter(self,value): self.configure(filter=value) def newfilter(self): """Make sure a newly set filter makes it into the combobox list""" self.tidy(self.component('filter'),self['filter']) self.fillit() def setdir(self,value): self.configure(directory=value) def newdir(self): """Make sure a newly set dirname makes it into the combobox list""" self.tidy(self.component('dirname'),self['directory']) self.fillit() def singleselectfile(self): """Single click in file listbox. Move file to "filename" combobox""" cs=self.component('filenamebox').curselection() if cs!=(): value=self.component('filenamebox').get(cs) self.setfilename(value) def selectfile(self): """Take the selected file from the filename, normalize it, and OK""" self.singleselectfile() value=self.component('filename').get() self.setfilename(value) if value: self.okbutton() def selectdir(self): """Take selected directory from the dirnamebox into the dirname""" cs=self.component('dirnamebox').curselection() if cs!=(): value=self.component('dirnamebox').get(cs) dir=self['directory'] if not dir: dir=os.getcwd() if value: if value=='..': dir=os.path.split(dir)[0] else: dir=os.path.join(dir,value) self.configure(directory=dir) self.fillit() def askfilename(self,directory=None,filter=None): """The actual client function. Activates the dialog, and returns only after a valid filename has been entered (return value is that filename) or when canceled (return value is None)""" if directory!=None: self.configure(directory=directory) if filter!=None: self.configure(filter=filter) self.fillit() self.canceled=1 # Needed for when user kills dialog window self.activate() if self.canceled: return None else: return self.component('filename').get() lastdir="" lastfilter=None lasttime=0 def fillit(self): """Get the directory list and show it in the two listboxes""" # Do not run unnecesarily if self.lastdir==self['directory'] and self.lastfilter==self['filter'] and self.lasttime>os.stat(self.lastdir)[8]: return self.lastdir=self['directory'] self.lastfilter=self['filter'] self.lasttime=time.time() dir=self['directory'] if not dir: dir=os.getcwd() dirs=['..'] files=[] try: fl=os.listdir(dir) fl.sort() except os.error,arg: if arg[0] in (2,20): return raise for f in fl: if os.path.isdir(os.path.join(dir,f)): dirs.append(f) else: filter=self['filter'] if not filter: filter='*' if fnmatch.fnmatch(f,filter): files.append(f) self.component('filenamebox').setlist(files) self.component('dirnamebox').setlist(dirs) def validate(self,filename): """Validation function. Should return 1 if the filename is valid, 0 if invalid. May pop up dialogs to tell user why. Especially suited to subclasses: i.e. only return 1 if the file does/doesn't exist""" return 1 ##class PmwExistingFileDialog(PmwFileDialog): ## def filevalidate(self,string): ## if os.path.isfile(string): ## return Pmw.OK ## else: ## return Pmw.PARTIAL ## def validate(self,filename): ## if os.path.isfile(filename): ## return 1 ## elif os.path.exists(filename): ## _errorpop(self.interior(),"This is not a plain file") ## return 0 ## else: ## _errorpop(self.interior(),"Please select an existing file") ## return 0 ################################# ET ###################################### #Class representing a list of ET ranks (rho), computed coverages, #and residue numbers. class ETRanks: def __init__(self): self.ranksloaded=False def readRanks(self,rankspath): """Read residue rankings from an ET .ranks file, or a .simple file with residue numbers in the first column and ranks on the second column.""" self.resnums=[] self.ranks=[] self.coverages=[] self.ranksloaded=False self.rankspath=rankspath if rankspath[-7:]=='.simple': FILE=open(rankspath,'r') types=[] #.simple file has no list of amino acid types try: for line in FILE: if line.find('#')==0: #comment continue cols=line.split() if len(cols)<2: continue resnum=cols[0].strip() rho=cols[1].strip() if resnum=='-': pass #gap else: self.resnums.append(resnum) self.ranks.append(float(rho)) self.coverages.append(0) finally: FILE.close() else: FILE=open(rankspath,'r') types=[] try: for line in FILE: if line.find('%')==0: continue if len(line.rstrip())>81: resnum=line[10:20].strip() if resnum=='-': pass #gap else: rho=line[72:82].strip() self.resnums.append(resnum) types.append(line[29]) #One-letter amino acid code self.ranks.append(float(rho)) self.coverages.append(0) #print resnum,rho finally: FILE.close() if len(self.resnums)>0: self.sequence=string.join(types,'') self.computeCoverage() self.ranksloaded=True #PyMOL already has "spectrum" that can indicate b-factors def getBfactors(self,model): self.resnums=[] self.ranks=[] self.coverages=[] self.ranksloaded=False self.rankspath="B-factors" resnumBdict={} for i in range(len(model.atom)): atomobj=model.atom[i] #if atomobj.hetatm==1: # continue try: resnumBdict[atomobj.resi].append(atomobj.b) except KeyError: resnumBdict[atomobj.resi]=[atomobj.b] self.resnums.append(atomobj.resi) for i in range(len(self.resnums)): r=self.resnums[i] bsum=0 for b in resnumBdict[r]: bsum+=b self.ranks.append(bsum*1.0/len(resnumBdict[r])) self.coverages.append(0) if len(self.resnums)>0: #self.sequence=string.join(types,'') self.computeCoverage() self.ranksloaded=True def computeCoverage(self): numres=self.getSize() for i in range(numres): self.coverages[i]=0 #12/21/11 for j in range(numres): if self.ranks[i]>=self.ranks[j]: self.coverages[i]+=1 self.coverages[i]=self.coverages[i]*100.0/numres def getSize(self): return len(self.resnums) def ranksLoaded(self): return self.ranksloaded def getResnumCoverageRankTuple(self,i): return self.resnums[i], self.coverages[i], self.ranks[i] def getResnum(self,i): return self.resnums[i] class ETControlGroup: #Reuse some functions useful for calculating clustering z-score #(Assignments made outside of a method such as __init__ make 'self' the first parameter) calcDist=_et_calcDist computeAdjacency=_et_computeAdjacency calcZScore=_et_calcZScore computeInterface=_et_computeInterface def __init__(self, page, groupname='Trace', defaultstructurename='(pdb)', defaultrankspath='.ranks', defaultslidercoverage=30, defaultetoption=0, defaultqualitymeasure=0, defaultchain='', defaultpartnerstructurename='', etcolor='red', noetcolor='salmon', et_loader_on=True, interface_on=True, et_colorramp=None, et_messagebox=None): self.etcolor=etcolor self.noetcolor=noetcolor self.et_colorramp=et_colorramp self.et_messagebox=et_messagebox #group = Pmw.Group(page,tag_text=groupname) #Changing to scrollable frame as a response to Bioinformatics reviewer 08/24/10 group=Pmw.ScrolledFrame(page, labelpos='nw', label_text=groupname) self.groupname=groupname self.group=group #self.groupscrolled=group group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) self.balloon=Pmw.Balloon(group.interior()) self.structureframe=Tkinter.Frame(group.interior()) #Field for entering name of structure or model self.structure = Pmw.EntryField(self.structureframe, labelpos='w', label_text='structure to use: ', value=defaultstructurename, ) self.chain = Pmw.EntryField(self.structureframe, labelpos='w', label_text='chain: ', value=defaultchain, ) self.structure.grid(column=0,row=0) self.chain.grid(column=1,row=0) def quickFileValidation(s): if s == '': return Pmw.PARTIAL elif os.path.isfile(s): return Pmw.OK elif os.path.exists(s): return Pmw.PARTIAL else: return Pmw.PARTIAL if et_loader_on: #Put ET Loader capability directly into ETControlGroup (03/08/10) self.loadergroup = Pmw.Group(group.interior(),tag_text='(optional) Load structure and precomputed trace') self.pdbnamebox = Pmw.EntryField(self.loadergroup.interior(), labelpos='w', label_text='Enter a 4-digit pdb code + chain id (e.g. 2phyA): ', value='2phyA', ) #Button for assigning ranks to structure self.load_buttonbox = Pmw.ButtonBox(self.loadergroup.interior(), padx=0) self.load_buttonbox.add('Load trace',command=self.loadETVX) self.load_buttonbox.add('View ET Server Page',command=self.viewETServerPage) self.pdbnamebox.pack(fill='x',padx=4,pady=1) # vertical self.load_buttonbox.pack(fill='x',padx=4,pady=1) # vertical self.checksequence_var=IntVar() self.checksequence_var.set(0) self.checksequence_checkbutton = Checkbutton(group.interior(), text = "check sequence", variable = self.checksequence_var) self.usebfactor_var=IntVar() self.usebfactor_var.set(0) self.usebfactor_checkbutton = Checkbutton(group.interior(), text = "Use b-factor as ranks", variable = self.usebfactor_var) #Button for assigning ranks to structure self.map_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.map_buttonbox.add('Map ranks to structure',command=self.mapRanks) #Field for entering ranks file self.ranksfile = Pmw.EntryField(group.interior(), labelpos='w', label_pyclass = FileDialogButtonClassFactory.get(self.setRanksFileLocation,'*.ranks'), validate = {'validator':quickFileValidation,}, value = defaultrankspath, #entry_width=50, #This value is set for the sole purpose of making the width of the plugin dialog box large enough label_text = 'ET ranks file path:') #Tkinter Slider Tkinterfor changing ET residue coverage. #TODO: Use a Pmw implementation? self.slider = Scale(group.interior(), #from_=self.min, to=self.max, from_=0, to=100, showvalue=1, length=200, orient=HORIZONTAL, resolution=0.01, tickinterval=0, #repeatinterval=500, #Dunno what repeatinterval is for... repeatdelay=500 ) self.slider.set(defaultslidercoverage) #self.slider.grid() self.slider.bind("", self.slider_button_release) #self.slider.bind("", self.mousebutton_click) self.slider.bind("", self.mousebutton_click) #For Windows self.slider.bind("", self.mousewheel_roll) #For Linux (for Mac?) self.slider.bind("", self.mousewheel_roll) self.slider.bind("", self.mousewheel_roll) #self.slider.bind("", self.slider_button_release) ## Triggered when the mouse enters a widget ## ## Triggered when a left click is done in a widget ##, <1> ## Triggered when the mouse is dragged over ## ## the widget with the left mouse button being ## held down. ## Triggered when a widget is double-clicked ## ## with the left mouse button ## Triggered when the key producing the letter ##, , , A ## A (caps) is pressed. #Field for displaying ET coverage self.frame1=Tkinter.Frame(group.interior()) self.percentcoverage = Pmw.EntryField(self.frame1, #group.interior(), labelpos='w', label_text='Percent coverage: ', value='', ) self.rankvalue = Pmw.EntryField(self.frame1, #group.interior(), labelpos='w', label_text='Rank: ', value='', ) self.percentcoverage.grid(column=0,row=0) self.rankvalue.grid(column=1,row=0) self.frame2=Tkinter.Frame(group.interior()) self.et_options_tuple = ('Colors only('+self.etcolor+')', 'as Spheres', 'as Spheres (C-alpha only)', 'Prismatic (Gobstopper)', 'as Sticks', 'Map -1 to +1 to blue-white-red') self.show_et_options = Pmw.OptionMenu(self.frame2, #group.interior(), labelpos = 'w', label_text = 'Show ET residues', items = self.et_options_tuple, initialitem = self.et_options_tuple[defaultetoption], command=self.slider_button_release ) ## self.show_et_var=IntVar() ## self.show_et_var.set(0) ## self.show_et_checkbutton = Checkbutton(group.interior(), ## text = "Show ET residues (as spheres)", ## variable = self.show_et_var) self.select_et_var=IntVar() self.select_et_var.set(0) self.select_et_checkbutton = Checkbutton(self.frame2, #group.interior(), text = "Select ET residues", variable = self.select_et_var) self.show_et_options.grid(column=0,row=0) self.select_et_checkbutton.grid(column=1,row=0) #self.ETcolor_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) #06/10/11 Experimenting with tkColorChooser #self.ETcolor_buttonbox.add('Choose ET color',command=self.chooseETcolor) self.qualitymeasure_options_tuple = ('3D nobias', '3D bias (j-i)') self.show_qualitymeasure_options = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'quality measure: ', items = self.qualitymeasure_options_tuple, initialitem = self.qualitymeasure_options_tuple[defaultqualitymeasure], ) self.zscore_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.zscore_buttonbox.add('Compute z-scores',command=self.showZScores) self.zscore_buttonbox.add('Average neighbor ranks',command=self.averageNeighborRanks) self.zscore_et = Pmw.EntryField(group.interior(), labelpos='w', label_text='z-score ET residues: ', value='', ) self.zscore_notet = Pmw.EntryField(group.interior(), labelpos='w', label_text='z-score non-ET residues: ', value='', ) if interface_on: #Put Interface/binding site search capability into ETControlGroup (05/18/10) self.interfacegroup = Pmw.Group(group.interior(),tag_text='Find interface with the next structure/molecule') self.partnerstructureframe=Tkinter.Frame(self.interfacegroup.interior()) #Field for entering name of structure or model self.partnerstructure = Pmw.EntryField(self.partnerstructureframe, labelpos='w', label_text='structure: ', value=defaultpartnerstructurename, ) self.partnerchain = Pmw.EntryField(self.partnerstructureframe, labelpos='w', label_text='chain: ', value='', ) self.partnerstructure.grid(column=0,row=0) self.partnerchain.grid(column=1,row=0) self.distance = Pmw.EntryField(self.interfacegroup.interior(), labelpos='w', label_text='distance to use for interface: ', validate={'validator':'real','min':1,'max':20}, value=4, ) self.mark_buttonbox = Pmw.ButtonBox(self.interfacegroup.interior(), padx=0) self.mark_buttonbox.add('Mark interface',command=self.markInterface) self.interface_options_tuple = (#'Colors only('+self.interfacecolor1+')', 'as Spheres', 'as Sticks', 'as Selection', 'None') self.show_interface_options = Pmw.OptionMenu(self.interfacegroup.interior(), labelpos = 'w', label_text = 'Show interface residues', items = self.interface_options_tuple, initialitem = self.interface_options_tuple[0], command=self.updateInterface #Need two arguments for this method ) self.partnerstructureframe.pack(fill='x',padx=4,pady=1) self.distance.pack(fill='x',padx=4,pady=1) self.mark_buttonbox.pack(fill='x',padx=4,pady=1) self.show_interface_options.pack(fill='x',padx=4,pady=1) if et_loader_on: self.loadergroup.pack(fill='x',padx=4,pady=1) for entry in (self.structureframe, self.ranksfile, self.checksequence_checkbutton, self.usebfactor_checkbutton, self.map_buttonbox, self.slider, self.frame1, self.frame2, #self.percentcoverage, #self.rankvalue, #self.show_et_checkbutton, #self.show_et_options, #self.select_et_checkbutton, #self.ETcolor_buttonbox, self.zscore_buttonbox, self.show_qualitymeasure_options, self.zscore_et, self.zscore_notet): entry.pack(fill='x',padx=4,pady=1) # vertical if interface_on: self.interfacegroup.pack(fill='x',padx=4,pady=1) #Tool tips (help) for user-interface components and boxes self.balloon.bind(self.structure,"Enter a name from the list of objects in the PyMOL Viewer") self.balloon.bind(self.ranksfile,"Click to open a box for navigating and choosing a file") self.balloon.bind(self.checksequence_checkbutton, "Check this box to verify if the sequence in the structure and ranks file match after mapping ranks to structure") self.balloon.bind(self.usebfactor_checkbutton, "Check this box to use the B factor or the temperature factor, averaged over the residue's atoms, as ET ranks") self.balloon.bind(self.map_buttonbox,"Click to map rank data onto the structure. Done automatically when doing 'Load trace'") self.balloon.bind(self.slider,"Drag slider to vary ET residue selection and coverage of the structure") self.balloon.bind(self.percentcoverage,"Maximum percent-rank (or percentile-rank) in the ET residue selection") self.balloon.bind(self.rankvalue,"Maximum raw ET rank score in the ET residue selection") self.balloon.bind(self.show_et_options,"Select display style to distinguish ET residue selection from the rest of the structure") self.balloon.bind(self.select_et_checkbutton,"Check box to create a PyMOL selection of the ET residues") self.balloon.bind(self.zscore_buttonbox,"Compute the clustering z-score of the ET residue selection") self.balloon.bind(self.show_qualitymeasure_options,"Select from several measures of clustering quality") if et_loader_on: self.balloon.bind(self.loadergroup, "Use this to download a PDB chain and precomputed ET rank data") self.balloon.bind(self.load_buttonbox.button(0), "Click to start download") self.balloon.bind(self.load_buttonbox.button(1), "Click to view the ET server entry for this structure if it exists") if interface_on: self.balloon.bind(self.partnerstructure, "A structure with this name must exist from the list of objects in the PyMOL Viewer!") self.balloon.bind(self.distance, "Maximum inter-residue atom-atom distance (Angstroms)") self.balloon.bind(self.mark_buttonbox, "Click to start interface calculation and display") self.balloon.bind(self.show_interface_options, "Select display style to distinguish interface residues from the rest of the structure") self.ranksObj=ETRanks() self.ranksStructureOK=False self.adjacencyOK=False self.interfaceComputed=False self.et_loader_on=et_loader_on self.zscore_button_bg=self.zscore_buttonbox.button(0).cget('background') self.zscore_button_state=self.zscore_buttonbox.button(0).cget('state') #The defaults for zscore_buttonbox could instead be used self.mark_button_bg=self.mark_buttonbox.button(0).cget('background') self.mark_button_state=self.mark_buttonbox.button(0).cget('state') def setRanksObj(self, ranksObj_external): """Ranks file has been read without calling mapRanks. Use the externally-created ranksObj""" structurename=self.structure.getvalue().strip() chainindicator=self.chain.getvalue().strip() self.structurename=structurename self.chainindicator=chainindicator self.ranksStructureOK=True self.ranksObj=ranksObj_external #self.setRanksFileLocation(self.ranksObj.rankspath) #self.slider_button_release(None) #06/10/11 Experimenting with tkColorChooser def chooseETcolor(self): if self.ranksStructureOK: print tkColorChooser.askcolor(title = "Pick a color for ET residues", parent=self.group.interior()) def mapRanks(self): structurename=self.structure.getvalue().strip() supper=structurename.upper() for n in cmd.get_names('all'): if supper==n.upper(): break else: print 'structure name must be in PyMOL viewer list:' print cmd.get_names('all') return chainindicator=self.chain.getvalue().strip() self.ranksStructureOK=False self.adjacencyOK=False if len(structurename)<1: print 'Provide structure name!' return try: model=cmd.get_model(structurename) except Exception: print "Structure \'%s\' does not exist!" % structurename return #TODO if self.usebfactor_var.get()==1: print "Using %s B-factors as ranks" % structurename self.ranksObj.getBfactors(model) else: rankspath=self.ranksfile.getvalue().strip() if len(rankspath)<1: print 'Provide path to ranks file!' return self.ranksObj.readRanks(rankspath) if self.ranksObj.ranksLoaded(): print "Ranks file \'%s\' loaded" % rankspath else: print "Error loading ranks file \'%s\'!" % rankspath return if self.checksequence_var.get()==1: self.checkSequence(model,structurename,chainindicator,rankspath) self.structurename=structurename self.chainindicator=chainindicator self.ranksStructureOK=True self.recomputeInterface=True #For CouplingGroup self.slider_button_release(None) #This check uses the residue numbers, not the amino acid types def checkSequence(self,model,structurename,chainindicator,rankspath): three2one={ "ALA":'A', "ARG":'R', "ASN":'N', "ASP":'D', "CYS":'C', "GLN":'Q', "GLU":'E', "GLY":'G', "HIS":'H', "ILE":'I', "LEU":'L', "LYS":'K', "MET":'M', "PHE":'F', "PRO":'P', "SER":'S', "THR":'T', "TRP":'W', "TYR":'Y', "VAL":'V', "A":"A", "G":"G", "T":"T", "U":"U", "C":"C",} print 'Comparing residue numbers of structure \'%s\' and ranks \'%s\'...' % (structurename+chainindicator, rankspath) #Check that the residue numbers in the model #and in the ranks file are identical resnumDict={} if len(chainindicator)>0: #chainup=chainindicator.upper() #Case of chain indicator is relevant for i in range(len(model.atom)): atomobj=model.atom[i] if chainindicator==atomobj.chain: try: aa1=three2one[atomobj.resn] #Consider only residues with standard amino acids resnumDict[atomobj.resi]=1 except KeyError: pass else: for i in range(len(model.atom)): resnumDict[model.atom[i].resi]=1 print 'Sequence lengths:' print 'structure: ', len(resnumDict) print 'ranks: ', self.ranksObj.getSize() if len(resnumDict)<1: print 'Structure \'%s\' has no residues!' % (structurename+chainindicator) if len(resnumDict)!=self.ranksObj.getSize(): print "Sequence lengths of \'%s\' and \'%s\' are not the same!" % (structurename+chainindicator, rankspath) missing=0 for i in range(self.ranksObj.getSize()): try: r=resnumDict[self.ranksObj.getResnum(i)] except KeyError: missing+=1 if missing>0: print "%d residue numbers in \'%s\' missing in \'%s\'!" % (missing, rankspath, structurename+chainindicator) print '...Done.' def mousewheel_roll(self, event): slideval=self.slider.get() #See http://www.daniweb.com/code/snippet217059.html if event.num==4 or event.delta==-120: self.slider.set(slideval+1) self.slider_button_release(None) if event.num==5 or event.delta==120: self.slider.set(slideval-1) self.slider_button_release(None) #print event.num, event.delta, slideval def mousebutton_click(self, event): #slideval=self.slider.get() if event.num==1 or event.num==2: self.slider_button_release(None) #print event.num, event.delta, slideval def slider_button_release(self, event): if self.ranksStructureOK: self.et_messagebox.show() maxcov=0 maxrank=0 slideval=self.slider.get() #The following does not work. The colors _et_prism_colorXX are defined only in PyMOL, #not Pmw/Tkinter #self.slider.configure(background=('_et_prism_color%d' % (slideval-0.000001))) if len(self.chainindicator)>0: structurename='%s and chain %s' % (self.structurename,self.chainindicator) else: structurename=self.structurename if self.show_et_options.getvalue()==self.et_options_tuple[2]: cmd.hide('spheres',structurename) #Need to hide spheres in case non-CA atoms are displayed for i in range(self.ranksObj.getSize()): (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov: if cov>maxcov: maxcov=cov maxrank=rank cmd.color(self.etcolor,'%s and resi %s' % (structurename,resnum)) cmd.show('spheres','%s and resi %s and name CA' % (structurename,resnum)) else: #TODO: Color only the spheres? cmd.color(self.noetcolor,'%s and resi %s' % (structurename,resnum)) cmd.hide('spheres','%s and resi %s' % (structurename,resnum)) #if self.show_et_var.get()==1: elif self.show_et_options.getvalue()==self.et_options_tuple[1]: #Rong's suggestion #cmd.hide('spheres',structurename) #cmd.show('cartoon',structurename) #cmd.color(self.noetcolor,structurename) for i in range(self.ranksObj.getSize()): (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov: if cov>maxcov: maxcov=cov maxrank=rank cmd.color(self.etcolor,'%s and resi %s' % (structurename,resnum)) cmd.show('spheres','%s and resi %s' % (structurename,resnum)) else: #TODO: Color only the spheres? cmd.color(self.noetcolor,'%s and resi %s' % (structurename,resnum)) cmd.hide('spheres','%s and resi %s' % (structurename,resnum)) elif self.show_et_options.getvalue()==self.et_options_tuple[3]: #Do Prismatic for i in range(self.ranksObj.getSize()): (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov: if cov>maxcov: maxcov=cov maxrank=rank cmd.color('_et_prism_color%d'%(int(cov-0.000001)),'%s and resi %s' % (structurename,resnum)) else: cmd.color('white','%s and resi %s' % (structurename,resnum)) if self.et_colorramp: #print 'show prismatic ramp' self.et_colorramp.show() elif self.show_et_options.getvalue()==self.et_options_tuple[4]: for i in range(self.ranksObj.getSize()): (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov: if cov>maxcov: maxcov=cov maxrank=rank cmd.color(self.etcolor,'%s and resi %s' % (structurename,resnum)) cmd.show('sticks','%s and resi %s' % (structurename,resnum)) else: cmd.color(self.noetcolor,'%s and resi %s' % (structurename,resnum)) cmd.hide('sticks','%s and resi %s' % (structurename,resnum)) elif self.show_et_options.getvalue()==self.et_options_tuple[5]: #Special mapping for difference ET coverage differentials suggested by Angela for i in range(self.ranksObj.getSize()): (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) if cov>maxcov: maxcov=cov maxrank=rank if rank>0.99999: rank=0.99999 if rank<-0.99999: rank=-0.99999 if rank>0.2: cmd.color('_et_red_color%s'%int(10*(rank-0.2)/0.8),'%s and resi %s' % (structurename,resnum)) elif rank<-0.2: cmd.color('_et_blue_color%s'%int(10*(-rank-0.2)/0.8),'%s and resi %s' % (structurename,resnum)) else: cmd.color('white','%s and resi %s' % (structurename,resnum)) else: #It turns out that calling cmd.color or cmd.select with a list of residues, e.g. 'resi 1+2+...', can crash pymol #if the list is too big (>300) for i in range(self.ranksObj.getSize()): (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov: if cov>maxcov: maxcov=cov maxrank=rank cmd.color(self.etcolor,'%s and resi %s' % (structurename,resnum)) else: cmd.color(self.noetcolor,'%s and resi %s' % (structurename,resnum)) #See if this is faster #if len(etlist)>0: # cmd.color(self.etcolor,'%s and resi %s' % (structurename,string.join(etlist,'+'))) #if len(notetlist)>0: # cmd.color(self.noetcolor,'%s and resi %s' % (structurename,string.join(noetlist,'+'))) self.percentcoverage.setvalue(maxcov) self.rankvalue.setvalue(maxrank) #Make a selection of the ET residues if self.select_et_var.get()==1: resnumlist=[] for i in range(self.ranksObj.getSize()): (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov: resnumlist.append(resnum) else: #You might want to make a selection for non-ET residues also pass if len(resnumlist)>0: cmd.select('et_%s_PyETV' % (self.structurename+self.chainindicator),'%s and resi %s' % (structurename,string.join(resnumlist,'+'))) else: cmd.select('et_%s_PyETV' % (self.structurename+self.chainindicator),'none') self.et_messagebox.withdraw() def setRanksFileLocation(self,value): self.ranksfile.setvalue(value) def getETselection(self): """Get selection of ET residues at the current slider (percentile) setting""" et1=[] if self.ranksStructureOK: slideval=self.slider.get() for i in range(self.ranksObj.getSize()): (resnum1,cov1,rank1)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov1: et1.append(int(resnum1)) else: pass #notet.append(int(resnum1)) return et1 #list of ints of residue numbers #Threading as a response to reviewers 08/24/10 if _ET_THREADING: def showZScores(self): if self.ranksStructureOK: self.zscore_buttonbox.button(0).configure(state=DISABLED) if self.et_loader_on: self.load_buttonbox.button(0).configure(state=DISABLED, background='red') self.map_buttonbox.button(0).configure(state=DISABLED, background='red') self.zscoreBusyDoneEvent=Event() self.zscoreDoneEvent=Event() tm=Thread(target=self.zscoreBusyMessage) tm.start() tz=Thread(target=self.showZScores_run) tz.start() else: def showZScores(self): if self.ranksStructureOK: try: self.et_messagebox.show() slideval=self.slider.get() #Get the slider value (ET threshold) early if self.show_qualitymeasure_options.getvalue()==self.qualitymeasure_options_tuple[0]: bias=0 elif self.show_qualitymeasure_options.getvalue()==self.qualitymeasure_options_tuple[1]: bias=1 if not self.adjacencyOK: if len(self.chainindicator)>0: structurename='%s and chain %s' % (self.structurename,self.chainindicator) else: structurename=self.structurename print "Computing adjacency matrix A(i,j)..." self._A,ResAtoms,self._Ar=self.computeAdjacency(structurename) if self._A==None: self.zscore_et.setvalue('') self.zscore_notet.setvalue('') self.et_messagebox.withdraw() return else: self.adjacencyOK=True print "... done" #Get lists of ET residues et1=[] notet=[] #slideval=self.slider.get() for i in range(self.ranksObj.getSize()): (resnum1,cov1,rank1)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov1: et1.append(int(resnum1)) else: notet.append(int(resnum1)) print "ET residue selection lists:" print et1 print "Computing z-scores..." if len(et1)>0: z1=self.calcZScore(et1,self.ranksObj.getSize(),self._A,bias) else: z1='NA' if len(notet)>0: z0=self.calcZScore(notet,self.ranksObj.getSize(),self._A,bias) else: z0='NA' print "...done" self.zscore_et.setvalue(z1) self.zscore_notet.setvalue(z0) #if len(notet)>0: # print 'Non-ET residue z-score: ', self.calcZScore(notet,self.ranksObj.getSize(),self._A) except Exception, detail: print 'An exception occurred in showZScores!' print detail self.et_messagebox.withdraw() ####################### 12/21/11 def averageNeighborRanks(self): if self.ranksStructureOK: try: self.et_messagebox.show() if not self.adjacencyOK: if len(self.chainindicator)>0: structurename='%s and chain %s' % (self.structurename,self.chainindicator) else: structurename=self.structurename print "Computing adjacency matrix A(i,j)..." self._A,ResAtoms,self._Ar=self.computeAdjacency(structurename) if self._A==None: self.et_messagebox.withdraw() return else: self.adjacencyOK=True print "... done" self.calcAverageNeighborRanks() print "...done" except Exception, detail: print 'An exception occurred in averageNeighborRanks!' print detail self.et_messagebox.withdraw() def calcAverageNeighborRanks(self): #Build dictionary (resnum,i) resindex={} tmpranks=[0]*self.ranksObj.getSize() for i in range(self.ranksObj.getSize()): (resnum1,cov1,rank1)=self.ranksObj.getResnumCoverageRankTuple(i) resindex[int(resnum1)]=i tmpranks[i]=rank1 for i in range(self.ranksObj.getSize()): ranki=tmpranks[i] resi=int(self.ranksObj.getResnum(i)) try: neighborsj=self._A[resi] for resj in neighborsj: j=resindex[resj] rankj=tmpranks[j] ranki+=rankj except KeyError: neighborsj=[] try: neighborsj2=self._Ar[resi] for resj in neighborsj2: j=resindex[resj] rankj=tmpranks[j] ranki+=rankj except KeyError: neighborsj2=[] nall=len(neighborsj)+len(neighborsj2) if nall>0: self.ranksObj.ranks[i]=ranki/(nall+1.0) #Update coverage self.ranksObj.computeCoverage() #Update display self.slider_button_release(None) print "ET ranks have been modified!" ####################### def zscoreBusyMessage(self): tog=True #Loop until showZScores_run finishes with calculation while not self.zscoreDoneEvent.isSet(): if tog: self.zscore_buttonbox.button(0).configure(background='green') #self.zscore_et.setvalue('PROCESSING...') #self.zscore_notet.setvalue('PROCESSING...') else: self.zscore_buttonbox.button(0).configure(background=self.zscore_button_bg) #self.zscore_et.setvalue('') #self.zscore_notet.setvalue('') tog=not tog time.sleep(0.5) self.zscore_buttonbox.button(0).configure(background=self.zscore_button_bg) #Notify showZScores_run that pulsing message has ended self.zscoreBusyDoneEvent.set() def showZScores_run(self): try: if 1: #if self.ranksStructureOK: slideval=self.slider.get() #Get the slider value (ET threshold) early if self.show_qualitymeasure_options.getvalue()==self.qualitymeasure_options_tuple[0]: bias=0 elif self.show_qualitymeasure_options.getvalue()==self.qualitymeasure_options_tuple[1]: bias=1 if not self.adjacencyOK: if len(self.chainindicator)>0: structurename='%s and chain %s' % (self.structurename,self.chainindicator) else: structurename=self.structurename print "Computing adjacency matrix A(i,j)..." self._A,ResAtoms,self._Ar=self.computeAdjacency(structurename) if self._A==None: self.zscoreDoneEvent.set() self.zscoreBusyDoneEvent.wait(5) self.zscore_et.setvalue('') self.zscore_notet.setvalue('') self.zscore_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) if self.et_loader_on: self.load_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.map_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) return else: self.adjacencyOK=True print "... done" #Get lists of ET residues et1=[] notet=[] #slideval=self.slider.get() for i in range(self.ranksObj.getSize()): (resnum1,cov1,rank1)=self.ranksObj.getResnumCoverageRankTuple(i) if slideval>=cov1: et1.append(int(resnum1)) else: notet.append(int(resnum1)) print "ET residue selection lists:" print et1 print "Computing z-scores..." if len(et1)>0: z1=self.calcZScore(et1,self.ranksObj.getSize(),self._A,bias) else: z1='NA' if len(notet)>0: z0=self.calcZScore(notet,self.ranksObj.getSize(),self._A,bias) else: z0='NA' print "...done" self.zscoreDoneEvent.set() #Make sure zscoreBusyMessage ends so z-scores #on text/entry fields don't get overwritten self.zscoreBusyDoneEvent.wait(5) self.zscore_et.setvalue(z1) self.zscore_notet.setvalue(z0) #if len(notet)>0: # print 'Non-ET residue z-score: ', self.calcZScore(notet,self.ranksObj.getSize(),self._A) except Exception, detail: print 'An exception occurred in showZScores_run!' print detail self.zscoreDoneEvent.set() #Place inside a "finally" clause? self.zscore_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) if self.et_loader_on: self.load_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.map_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) def loadETVX(self): self.et_messagebox.show() etvxurl='http://mammoth.bcm.tmc.edu/ETserver2/pdbeasytrace/' #self.etvxurlbox.getvalue().strip() pdb_chain=self.pdbnamebox.getvalue().strip()[:5] print 'Retrieving '+pdb_chain+'.etvx from '+etvxurl try: tmpetvxpath = urllib.urlretrieve(etvxurl+pdb_chain+'.etvx')[0] except Exception: print 'Error in retrieving trace data! Please check your internet connection.' self.et_messagebox.withdraw() return print tmpetvxpath if os.path.getsize(tmpetvxpath)==0: print etvxurl+pdb_chain+'.etvx not found' self.et_messagebox.withdraw() return print 'Extracting query pdb structure' pdbfilename=self.extractPDB(tmpetvxpath,pdb_chain) if pdbfilename==None: print 'Missing structure.', etvxurl+pdb_chain+'.etvx likely non-existent' self.et_messagebox.withdraw() return print pdbfilename print 'Extracting ranks file' ranksfilename=self.extractRanks(tmpetvxpath,pdb_chain) print ranksfilename cmd.load(pdbfilename,object=pdb_chain) self.setRanksFileLocation(ranksfilename) self.structure.setvalue(pdb_chain) self.chain.setvalue('') #Let PyETV (or ET Tools) know about this trace... #cmd._et_tools_structurename=pdb_chain #cmd._et_tools_rankspath1=ranksfilename self.mapRanks() self.et_messagebox.withdraw() def extractPDB(self,etvxpath,pdb_chain): #Get the ATOM records FILE=open(etvxpath,'r') data='' try: for line in FILE: if line[:4]=='ATOM': data+=line #TODO: Stop when pdb section is exhausted? finally: FILE.close() if len(data)==0: return None #Write ATOM lines to file pdbfilename=os.path.dirname(etvxpath)+os.sep+'query_'+pdb_chain+'.pdb' FILE_PDB=open(pdbfilename,'w') FILE_PDB.write(data) FILE_PDB.close() return pdbfilename def extractRanks(self,etvxpath,pdb_chain): #Get the ranks section FILE=open(etvxpath,'r') data='' ready=False try: for line in FILE: if line[:5]=='~tree': break if ready: data+=line if line[:9]=='~ET_ranks': ready=True finally: FILE.close() #Write ranks section to file ranksfilename=os.path.dirname(etvxpath)+os.sep+pdb_chain+'.ranks' FILE_RANKS=open(ranksfilename,'w') FILE_RANKS.write(data) FILE_RANKS.close() return ranksfilename def viewETServerPage(self): tv=Thread(target=self.viewETServerPage_run) tv.start() def viewETServerPage_run(self): pdb=self.pdbnamebox.getvalue().strip()[:4] import webbrowser webbrowser.open('http://mammoth.bcm.tmc.edu/cgi-bin/report_maker_ls/traceServerResults.pl?identifier=%s' % pdb) if _ET_THREADING: def markInterface(self): if self.ranksStructureOK: self.mark_buttonbox.button(0).configure(state=DISABLED) self.markBusyDoneEvent=Event() self.markDoneEvent=Event() tm=Thread(target=self.markBusyMessage) tm.start() ti=Thread(target=self.markInterface_run) ti.start() else: def markInterface(self): if self.ranksStructureOK: try: chainindicator1=self.chain.getvalue().strip() structname=self.structure.getvalue().strip() supper=structname.upper() for n in cmd.get_names('all'): if supper==n.upper(): break else: print 'structure name must be in PyMOL viewer list:' print cmd.get_names('all') return if len(chainindicator1)>0: structurename1=structname+' and chain %s' % chainindicator1 else: structurename1=structname chainindicator2=self.partnerchain.getvalue().strip() pstructname=self.partnerstructure.getvalue().strip() psupper=pstructname.upper() for n in cmd.get_names('all'): if psupper==n.upper(): break else: print 'partner structure name must be in PyMOL viewer list:' print cmd.get_names('all') return if len(chainindicator2)>0: structurename2=pstructname+' and chain %s' % chainindicator2 else: structurename2=pstructname dist=float(self.distance.getvalue().strip()) self.et_messagebox.show() #In self.interface1, each residue indexes into an array of neighboring residues in the other structure (self.interface1, self.interface2, self.ResAtoms1, self.ResAtoms2)=self.computeInterface(structurename1,structurename2,dist*dist) if (self.interface1 is None) or (self.interface2 is None): print 'Interfaces not computed' self.interfaceComputed=False self.et_messagebox.withdraw() return self.interfaceComputed=True print "%d interface residues in %s" % (len(self.interface1),structurename1) print "%d interface residues in %s" % (len(self.interface2),structurename2) print "Adjacency lists:" print structurename1, self.interface1 print structurename2, self.interface2 self.updateInterface(None) except Exception, detail: print 'An exception occurred in markInterface!' print detail self.et_messagebox.withdraw() def markBusyMessage(self): tog=True #Loop until markInterface_run finishes with calculation while not self.markDoneEvent.isSet(): if tog: self.mark_buttonbox.button(0).configure(background='green') else: self.mark_buttonbox.button(0).configure(background=self.mark_button_bg) tog=not tog time.sleep(0.5) self.mark_buttonbox.button(0).configure(background=self.mark_button_bg) #Notify markInterface_run that pulsing message has ended self.markBusyDoneEvent.set() def markInterface_run(self): #Response to reviewer 08/24/10 try: chainindicator1=self.chain.getvalue().strip() structname=self.structure.getvalue().strip() supper=structname.upper() for n in cmd.get_names('all'): if supper==n.upper(): break else: print 'structure name must be in PyMOL viewer list:' print cmd.get_names('all') self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return if len(chainindicator1)>0: structurename1=structname+' and chain %s' % chainindicator1 else: structurename1=structname chainindicator2=self.partnerchain.getvalue().strip() pstructname=self.partnerstructure.getvalue().strip() psupper=pstructname.upper() for n in cmd.get_names('all'): if psupper==n.upper(): break else: print 'partner structure name must be in PyMOL viewer list:' print cmd.get_names('all') self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return if len(chainindicator2)>0: structurename2=pstructname+' and chain %s' % chainindicator2 else: structurename2=pstructname dist=float(self.distance.getvalue().strip()) #These are redundant. 08/29/10 ## if len(self.structure.getvalue().strip())<1: ## print 'Provide structure 1 name!' ## self.mark_buttonbox.button(0).configure(state=self.mark_button_state, ## background=self.mark_button_bg) ## return ## if len(self.partnerstructure.getvalue().strip())<1: ## print 'Provide structure 2 name!' ## self.mark_buttonbox.button(0).configure(state=self.mark_button_state, ## background=self.mark_button_bg) ## return #In self.interface1, each residue indexes into an array of neighboring residues in the other structure (self.interface1, self.interface2, self.ResAtoms1, self.ResAtoms2)=self.computeInterface(structurename1,structurename2,dist*dist) if (self.interface1 is None) or (self.interface2 is None): print 'Interfaces not computed' self.interfaceComputed=False self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return self.interfaceComputed=True print "%d interface residues in %s" % (len(self.interface1),structurename1) print "%d interface residues in %s" % (len(self.interface2),structurename2) print "Adjacency lists:" print structurename1, self.interface1 print structurename2, self.interface2 self.updateInterface(None) except Exception, detail: print 'An exception occurred in markInterface_run!' print detail #self.markDoneEvent.set() self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) def updateInterface(self,event): #TODO: Make this method more aware of changes in the viewer if self.interfaceComputed==False: return s1=self.structure.getvalue().strip() s2=self.partnerstructure.getvalue().strip() c1=self.chain.getvalue().strip() c2=self.partnerchain.getvalue().strip() if len(c1)>0: structurename1=s1+' and chain %s' % c1 else: structurename1=s1 if len(c2)>0: structurename2=s2+' and chain %s' % c2 else: structurename2=s2 ## if self.show_interface_options1.getvalue()==self.interface_options_tuple[0]: ## for res in self.interface1.keys(): ## cmd.color(self.interfacecolor1,'%s and resi %s' % (structurename1,res)) if self.show_interface_options.getvalue()==self.interface_options_tuple[0]: for res in self.interface1.keys(): cmd.show('spheres','%s and resi %s' % (structurename1,res)) elif self.show_interface_options.getvalue()==self.interface_options_tuple[1]: for res in self.interface1.keys(): cmd.show('sticks','%s and resi %s' % (structurename1,res)) elif self.show_interface_options.getvalue()==self.interface_options_tuple[2]: #Make a selection of the ET residues if len(self.interface1)>0: cmd.select('%s_%s_PyETV' % (s1+c1,s2+c2), '%s and resi %s' % (structurename1,string.join(map(str,self.interface1),'+'))) else: cmd.select('%s_%s_PyETV' % (s1+c1,s2+c2),'none') ##################################################################### #Assembly #1. Get multimer structure from PISA #2. Get ranks files of every unique chain from mammoth pdbeasytrace #3. Map ranks files to the correct chains in the multimer class ETAssemblyControlGroup: def __init__(self, page, groupname='Load Biological Unit', defaultslidercoverage=30, defaultetoption=0, defaultqualitymeasure=0, et_colorramp=None, et_messagebox=None ): group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) self.et_colorramp=et_colorramp self.et_messagebox=et_messagebox self.slavelist=[] if 1: self.pdbnamebox = Pmw.EntryField(group.interior(), labelpos='w', label_text='Enter a 4-digit pdb code (e.g. 3gcb): ', value='1got', ) #Button for assigning ranks to structure self.load_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.load_buttonbox.add('Load Assembly',command=self.load) self.load_buttonbox.add('View PISA Page',command=self.viewPage) self.pdbnamebox.pack(fill='x',padx=4,pady=1) # vertical self.load_buttonbox.pack(fill='x',padx=4,pady=1) # vertical #Tkinter Slider Tkinterfor changing ET residue coverage. #TODO: Use a Pmw implementation? self.slider = Scale(group.interior(), #from_=self.min, to=self.max, from_=0, to=100, showvalue=1, length=200, orient=HORIZONTAL, resolution=0.01, tickinterval=0, #repeatinterval=500, #Dunno what repeatinterval is for... repeatdelay=500 ) self.slider.set(defaultslidercoverage) #self.slider.grid() #These additional mouse operations might be too costly for large assemblies self.slider.bind("", self.slider_button_release) ## #self.slider.bind("", self.mousebutton_click) ## self.slider.bind("", self.mousebutton_click) ## #For Windows ## self.slider.bind("", self.mousewheel_roll) ## #For Linux (for Mac?) ## self.slider.bind("", self.mousewheel_roll) ## self.slider.bind("", self.mousewheel_roll) #self.slider.bind("", self.slider_button_release) ## Triggered when the mouse enters a widget ## ## Triggered when a left click is done in a widget ##, <1> ## Triggered when the mouse is dragged over ## ## the widget with the left mouse button being ## held down. ## Triggered when a widget is double-clicked ## ## with the left mouse button ## Triggered when the key producing the letter ##, , , A ## A (caps) is pressed. self.frame2=Tkinter.Frame(group.interior()) #This list must be the same as in ETControlGroup self.et_options_tuple = ('Colors only', 'as Spheres', 'as Spheres (C-alpha only)', 'Prismatic (Gobstopper)', 'as Sticks') self.show_et_options = Pmw.OptionMenu(self.frame2, #group.interior(), labelpos = 'w', label_text = 'Show ET residues', items = self.et_options_tuple, initialitem = self.et_options_tuple[defaultetoption], command=self.change_options ) self.show_et_options.grid(column=0,row=0) self.notebook = Pmw.NoteBook(group.interior()) self.balloon=Pmw.Balloon(group.interior()) self.balloon.bind(self.slider,"Use this slider to vary the selection of ET residues for all chains in the assembly.") self.balloon.bind(self.load_buttonbox.button(0),"Click to start downloading an assembly and rank data and creating widgets below") self.balloon.bind(self.load_buttonbox.button(1),"Click to view the PISA entry") self.balloon.bind(self.show_et_options,"Select display style to distinguish ET residue selections from the rest of the structure") self.balloon.bind(self.pdbnamebox,"Enter a single PDB code (e.g. 1got) or a PDB code with PISA assembly numbers (1got:1,1)") for entry in (self.pdbnamebox, self.load_buttonbox, self.slider, self.frame2): entry.pack(fill='x',padx=4,pady=1) # vertical self.notebook.pack(fill='x',expand=1,padx=4,pady=1) self.three2one={ "ALA":'A', "ARG":'R', "ASN":'N', "ASP":'D', "CYS":'C', "GLN":'Q', "GLU":'E', "GLY":'G', "HIS":'H', "ILE":'I', "LEU":'L', "LYS":'K', "MET":'M', "PHE":'F', "PRO":'P', "SER":'S', "THR":'T', "TRP":'W', "TYR":'Y', "VAL":'V'} self.load_button_bg=self.load_buttonbox.button(0).cget('background') self.load_button_state=self.load_buttonbox.button(0).cget('state') if _ET_THREADING: #Threading as a response to reviewers 08/24/10 def load(self): self.load_buttonbox.button(0).configure(state=DISABLED) #Got errors when the next two loops were placed in load_run and ran #on a new thread for slave in self.slavelist: del slave for name in self.notebook.pagenames(): self.notebook.delete(name) #Clear the previous tabs self.loadBusyDoneEvent=Event() self.loadDoneEvent=Event() tm=Thread(target=self.loadBusyMessage) tm.start() tl=Thread(target=self.load_run) tl.start() else: #Not threaded def load(self): try: self.et_messagebox.show() for slave in self.slavelist: del slave for name in self.notebook.pagenames(): self.notebook.delete(name) #Clear the previous tabs params=self.pdbnamebox.getvalue().strip() if len(params)<4: print 'Enter valid pdb code!' self.et_messagebox.withdraw() return elif len(params)==4: params=params+':1,1' else: #User might specify different assembly set, e.g. '3cgb:2,1' pass PISA_url='http://www.ebi.ac.uk/msd-srv/pisa/cgi-bin/multimer.pdb?'+params #import urllib try: pdbpath = urllib.urlretrieve(PISA_url)[0] except Exception: print 'Error in retrieving PISA structure data! Please check your internet connection.' raise Exception() structurename=params[:4] cmd.load(pdbpath,structurename) #Check if structure/pdb is empty try: model=cmd.get_model(structurename) except Exception: print "Structure \'%s\' does not exist!" % structurename self.et_messagebox.withdraw() return if len(model.atom)==0: print "Structure \'%s\' has no PISA quaternary structure!" % structurename self.et_messagebox.withdraw() return self.getRanks(params[:4]) self.matchChaintoRanks(structurename) #Create ET control groups mapping a trace to each chain self.slavelist=[] for c, ranksObj in self.chain_ranks_dict.items(): page=self.notebook.add(c) slave=ETControlGroup(page, groupname=structurename+c, defaultstructurename=structurename, defaultchain=c, defaultrankspath=ranksObj.rankspath, #defaultetoption=self.show_et_options.index(Pmw.SELECT), defaultslidercoverage=self.slider.get(), #etcolor=etcolor_, #noetcolor=noetcolor_, defaultpartnerstructurename=structurename, et_loader_on=False, et_colorramp=self.et_colorramp, et_messagebox=self.et_messagebox) slave.setRanksObj(ranksObj) self.slavelist.append(slave) #Add Zcoupling and Interface computation to Assembly tabs (05/20/11) if len(self.chain_ranks_dict)>1: page=self.notebook.add('Zcoupling') self.couplingCalculatorAssembly=CouplingGroup2(page, groupname='Compute ET coupling z-score', tracelist=self.slavelist, et_messagebox=self.et_messagebox ) self.InterfaceGroupAssembly=InterfaceControlGroup2(page, groupname='Mark interface between structures 1 and 2', tracelist=self.slavelist, defaultinterfaceoption1=1, defaultinterfaceoption2=1, et_messagebox=self.et_messagebox ) self.notebook.pack(fill='both',expand=1,padx=10,pady=10) #self.notebook.setnaturalsize() self.change_options(None) except Exception, detail: print 'An exception occurred in load!' print detail self.et_messagebox.withdraw() def loadBusyMessage(self): tog=True #Loop until load_run finishes with calculation while not self.loadDoneEvent.isSet(): if tog: self.load_buttonbox.button(0).configure(background='green') else: self.load_buttonbox.button(0).configure(background=self.load_button_bg) tog=not tog time.sleep(0.5) #Notify load_run that pulsing message has ended self.loadBusyDoneEvent.set() def load_run(self): """Download multimer pdb from PISA""" ## for slave in self.slavelist: ## #slave.groupscrolled.configure(hscrollmode='none') ## del slave.groupscrolled try: params=self.pdbnamebox.getvalue().strip() if len(params)<4: print 'Enter valid pdb code!' self.loadDoneEvent.set() self.loadBusyDoneEvent.wait(5) self.load_buttonbox.button(0).configure(state=self.load_button_state, background=self.load_button_bg) return elif len(params)==4: params=params+':1,1' else: #User might specify different assembly set, e.g. '3cgb:2,1' pass PISA_url='http://www.ebi.ac.uk/msd-srv/pisa/cgi-bin/multimer.pdb?'+params #import urllib pdbpath = urllib.urlretrieve(PISA_url)[0] structurename=params[:4] cmd.load(pdbpath,structurename) #Check if structure/pdb is empty try: model=cmd.get_model(structurename) except Exception: print "Structure \'%s\' does not exist!" % structurename self.loadDoneEvent.set() self.loadBusyDoneEvent.wait(5) self.load_buttonbox.button(0).configure(state=self.load_button_state, background=self.load_button_bg) return if len(model.atom)==0: print "Structure \'%s\' has no PISA quaternary structure!" % structurename self.loadDoneEvent.set() self.loadBusyDoneEvent.wait(5) self.load_buttonbox.button(0).configure(state=self.load_button_state, background=self.load_button_bg) return self.getRanks(params[:4]) self.matchChaintoRanks(structurename) #Create ET control groups mapping a trace to each chain self.slavelist=[] for c, ranksObj in self.chain_ranks_dict.items(): page=self.notebook.add(c) slave=ETControlGroup(page, groupname=structurename+c, defaultstructurename=structurename, defaultchain=c, defaultrankspath=ranksObj.rankspath, #defaultetoption=self.show_et_options.index(Pmw.SELECT), defaultslidercoverage=self.slider.get(), #etcolor=etcolor_, #noetcolor=noetcolor_, defaultpartnerstructurename=structurename, et_loader_on=False, et_colorramp=self.et_colorramp, et_messagebox=self.et_messagebox) slave.setRanksObj(ranksObj) self.slavelist.append(slave) self.notebook.pack(fill='both',expand=1,padx=10,pady=10) #self.notebook.setnaturalsize() self.change_options(None) except Exception, detail: print 'An exception occurred in load_run!' print detail #self.loadDoneEvent.set() self.loadDoneEvent.set() self.loadBusyDoneEvent.wait(5) self.load_buttonbox.button(0).configure(state=self.load_button_state, background=self.load_button_bg) def viewPage(self): tv=Thread(target=self.viewPage_run) tv.start() def viewPage_run(self): import webbrowser #http://www.ebi.ac.uk/msd-srv/prot_int/pistart.html #http://www.ebi.ac.uk/msd-srv/prot_int/cgi-bin/piserver #http://www.ebi.ac.uk/msd-srv/pisa/cgi-bin/piserver?qa=1stm params=self.pdbnamebox.getvalue().strip()[:4] PISA_url='http://www.ebi.ac.uk/msd-srv/pisa/cgi-bin/piserver?qa='+params webbrowser.open(PISA_url) #This call blocks in debian linux def matchChaintoRanks(self,structurename): """Get the amino acid sequences in the structure sorted by chain""" try: model=cmd.get_model(structurename) except Exception: print "Structure \'%s\' does not exist!" % structurename return chain_sequence_dict={} for i in range(len(model.atom)): atomobj=model.atom[i] if atomobj.name=='CA': #Caution: Sometimes the CA atom may not be present in a pdb residue try: aa1=self.three2one[atomobj.resn] #Assume the amino acids are standard except KeyError: pass #Not a standard amino acid else: try: chain_sequence_dict[atomobj.chain].append(aa1) except KeyError: chain_sequence_dict[atomobj.chain]=[aa1] self.chain_ranks_dict={} for c, s in chain_sequence_dict.items(): seq=string.join(s,'') for ranksObj in self.ranksObjlist: if seq.find(ranksObj.sequence)!=-1: #Find a 'soft' match. Sequence in trace must be a substring of the PDB chain sequence. self.chain_ranks_dict[c]=ranksObj break print "Structure \'%s\' has %d protein chains:" % (structurename,len(chain_sequence_dict)), chain_sequence_dict.keys() print "Found traces for %d chains" % (len(self.chain_ranks_dict)) def getRanks(self,pdbcode): """Gather all ranks files for this pdbcode from mammoth""" self.ranksObjlist=[] #TODO: This strategy looks like a hack. Get the list of unique chains from the pml file, which contains: #load http://mammoth.bcm.tmc.edu/ETserver2/pdbeasytrace/1ewyA.etvx, 1ewyA #load http://mammoth.bcm.tmc.edu/ETserver2/pdbeasytrace/1ewyC.etvx, 1ewyC #zoom #cmd._et_tools_structurenamelist=['1ewyA', '1ewyC'] #cmd._et_tools_etvxurllist=['http://mammoth.bcm.tmc.edu/ETserver2/pdbeasytrace/1ewyA.etvx', 'http://mammoth.bcm.tmc.edu/ETserver2/pdbeasytrace/1ewyC.etvx'] #cmd._et_tools_selectpage='1ewyA' pml_url="http://mammoth.bcm.tmc.edu/ETserver2/pdbeasytrace/pmlFiles/%s.pml" % pdbcode try: pmlpath=urllib.urlretrieve(pml_url)[0] except Exception: print 'Error retrieving trace (pml) data! Please check your internet connection.' raise Exception() FILE=open(pmlpath,'r') for line in FILE: cols=line.split() if len(cols)==3: if cols[0]=='load': etvxurl=cols[1].strip(' ,') chain=etvxurl[-1] try: etvxpath = urllib.urlretrieve(etvxurl)[0] except Exception: print 'Error retrieving trace data! Please check your internet connection.' raise Exception() ranksfilename=self.extractRanks(etvxpath,cols[2].strip()) ranksObj=ETRanks() ranksObj.readRanks(ranksfilename) self.ranksObjlist.append(ranksObj) FILE.close() def extractRanks(self,etvxpath,pdb_chain): #Get the ranks section FILE=open(etvxpath,'r') data='' ready=False try: for line in FILE: if line[:5]=='~tree': break if ready: data+=line if line[:9]=='~ET_ranks': ready=True finally: FILE.close() #Write ranks section to file ranksfilename=os.path.dirname(etvxpath)+os.sep+pdb_chain+'.ranks' FILE_RANKS=open(ranksfilename,'w') FILE_RANKS.write(data) FILE_RANKS.close() return ranksfilename def mousewheel_roll(self, event): slideval=self.slider.get() #See http://www.daniweb.com/code/snippet217059.html if event.num==4 or event.delta==-120: self.slider.set(slideval+1) self.slider_button_release(None) if event.num==5 or event.delta==120: self.slider.set(slideval-1) self.slider_button_release(None) #print event.num, event.delta, slideval def mousebutton_click(self, event): #slideval=self.slider.get() if event.num==1 or event.num==2: self.slider_button_release(None) #print event.num, event.delta, slideval def slider_button_release(self, event): slideval=self.slider.get() for slave in self.slavelist: slave.slider.set(slideval) slave.slider_button_release(None) def change_options(self, event): for slave in self.slavelist: slave.show_et_options.setvalue(self.show_et_options.getvalue()) slave.slider_button_release(None) ##################################################################### #Complex/multiple chains class ETMasterControlGroup: def __init__(self, page, groupname='ALL', slavelist=[], defaultslidercoverage=30, defaultetoption=0, defaultqualitymeasure=0): group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) self.slavelist=slavelist #Tkinter Slider Tkinterfor changing ET residue coverage. #TODO: Use a Pmw implementation? self.slider = Scale(group.interior(), #from_=self.min, to=self.max, from_=0, to=100, showvalue=1, length=200, orient=HORIZONTAL, resolution=0.01, tickinterval=0, #repeatinterval=500, #Dunno what repeatinterval is for... repeatdelay=500 ) self.slider.set(defaultslidercoverage) #self.slider.grid() self.slider.bind("", self.slider_button_release) #These mouse operations might be too costly for large assemblies ## #self.slider.bind("", self.mousebutton_click) ## self.slider.bind("", self.mousebutton_click) ## #For Windows ## self.slider.bind("", self.mousewheel_roll) ## #For Linux (for Mac?) ## self.slider.bind("", self.mousewheel_roll) ## self.slider.bind("", self.mousewheel_roll) #self.slider.bind("", self.slider_button_release) ## Triggered when the mouse enters a widget ## ## Triggered when a left click is done in a widget ##, <1> ## Triggered when the mouse is dragged over ## ## the widget with the left mouse button being ## held down. ## Triggered when a widget is double-clicked ## ## with the left mouse button ## Triggered when the key producing the letter ##, , , A ## A (caps) is pressed. self.frame2=Tkinter.Frame(group.interior()) #This list must be the same as in ETControlGroup self.et_options_tuple = ('Colors only', 'as Spheres', 'as Spheres (C-alpha only)', 'Prismatic (Gobstopper)', 'as Sticks') self.show_et_options = Pmw.OptionMenu(self.frame2, #group.interior(), labelpos = 'w', label_text = 'Show ET residues', items = self.et_options_tuple, initialitem = self.et_options_tuple[defaultetoption], command=self.change_options ) self.show_et_options.grid(column=0,row=0) self.notebook = Pmw.NoteBook(group.interior()) self.balloon=Pmw.Balloon(group.interior()) self.balloon.bind(self.slider,"Use this slider to vary the selection of ET residues for all chains in the complex.") self.balloon.bind(self.show_et_options,"Select display style to distinguish ET residue selections from the rest of the structure") for entry in (self.slider, self.frame2): entry.pack(fill='x',padx=4,pady=1) # vertical self.notebook.pack(fill='x',expand=1,padx=4,pady=1) def mousewheel_roll(self, event): slideval=self.slider.get() #See http://www.daniweb.com/code/snippet217059.html if event.num==4 or event.delta==-120: self.slider.set(slideval+1) self.slider_button_release(None) if event.num==5 or event.delta==120: self.slider.set(slideval-1) self.slider_button_release(None) #print event.num, event.delta, slideval def mousebutton_click(self, event): #slideval=self.slider.get() if event.num==1 or event.num==2: self.slider_button_release(None) #print event.num, event.delta, slideval def slider_button_release(self, event): slideval=self.slider.get() for slave in self.slavelist: slave.slider.set(slideval) slave.slider_button_release(None) def change_options(self, event): for slave in self.slavelist: slave.show_et_options.setvalue(self.show_et_options.getvalue()) slave.slider_button_release(None) ##################################################################### #Group for computing the ET coupling z-score #This control interacts with two ETControlGroup pages (ET1 and ET2) class CouplingGroup: #Reuse some functions useful for calculating coupling z-score calcDist=_et_calcDist computeInterface=_et_computeInterface computeCoupling=_et_computeCoupling def __init__(self, page, trace1, trace2, groupname='Coupling z-score', et_messagebox=None): group = Pmw.Group(page,tag_text=groupname) self.et_messagebox=et_messagebox self.trace1=trace1 self.trace2=trace2 group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) self.zscore_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.zscore_buttonbox.add('Update interface',command=self.computeInterface_cb) self.zscore_buttonbox.add('Compute coupling z-score',command=self.showZScores) self.scw = Pmw.EntryField(group.interior(), labelpos='w', label_text='Number of ET couples, c: ', value='', ) self.scw_ave = Pmw.EntryField(group.interior(), labelpos='w', label_text=' average: ', value='', ) self.scw_stdev = Pmw.EntryField(group.interior(), labelpos='w', label_text='c stdev: ', value='', ) self.zscore = Pmw.EntryField(group.interior(), labelpos='w', label_text='z-score: ', value='', ) for entry in (self.zscore_buttonbox, self.zscore, self.scw, self.scw_ave, self.scw_stdev): entry.pack(fill='x',padx=4,pady=1) # vertical self.balloon=Pmw.Balloon(group.interior()) self.balloon.bind(self.zscore_buttonbox.button(0), "Recompute the interface between structures in ET1 and ET2") self.balloon.bind(self.zscore_buttonbox.button(1), "Click to start computing the ET coupling z-score using ET residue selections in ET1 and ET2") self.balloon.bind(self.zscore,"(c-)/stdev") self.interfaceOK=False #Deprecated self.zscore_buttonbox.button(0).configure(state=DISABLED) #Disable Update interface for now self.zscore_button_bg=self.zscore_buttonbox.button(1).cget('background') self.zscore_button_state=self.zscore_buttonbox.button(1).cget('state') def computeInterface_cb(self): #self.interfaceOK=False if self.trace1.ranksStructureOK and self.trace2.ranksStructureOK: if len(self.trace1.chainindicator)>0: structurename1='%s and chain %s' % (self.trace1.structurename, self.trace1.chainindicator) else: structurename1=self.trace1.structurename if len(self.trace2.chainindicator)>0: structurename2='%s and chain %s' % (self.trace2.structurename, self.trace2.chainindicator) else: structurename2=self.trace2.structurename print "Computing adjacency matrix for protein-protein interface A(i,j)..." self._A1,self._A2,ResAtoms1,ResAtoms2=self.computeInterface(structurename1, structurename2, CONTACT_DISTANCE2) if self._A1==None: return else: #self.interfaceOK=True print "%d interface residues in %s" % (len(self._A1),structurename1) print "%d interface residues in %s" % (len(self._A2),structurename2) print "Adjacency lists:" print structurename1, self._A1 print structurename2, self._A2 print "... done" else: print "Must provide structures and map trace results first!" if _ET_THREADING: #Threading as a response to reviewers 08/24/10 def showZScores(self): if self.trace1.ranksStructureOK and self.trace2.ranksStructureOK: self.zscore.setvalue('') self.scw.setvalue('') self.scw_ave.setvalue('') self.scw_stdev.setvalue('') self.zscore_buttonbox.button(1).configure(state=DISABLED) #TODO: These may get enabled by another thread, like #the z-score computations in ET1 or ET2 self.trace1.map_buttonbox.button(0).configure(state=DISABLED, background='red') self.trace1.load_buttonbox.button(0).configure(state=DISABLED, background='red') self.trace2.map_buttonbox.button(0).configure(state=DISABLED, background='red') self.trace2.load_buttonbox.button(0).configure(state=DISABLED, background='red') self.zscoreBusyDoneEvent=Event() self.zscoreDoneEvent=Event() tm=Thread(target=self.zscoreBusyMessage) tm.start() tz=Thread(target=self.showZScores_run) tz.start() else: self.zscore.setvalue('') self.scw.setvalue('') self.scw_ave.setvalue('') self.scw_stdev.setvalue('') print "Must provide structures and map trace results in ET1 and ET2!" else: def showZScores(self): if self.trace1.ranksStructureOK and self.trace2.ranksStructureOK: self.zscore.setvalue('') self.scw.setvalue('') self.scw_ave.setvalue('') self.scw_stdev.setvalue('') try: self.et_messagebox.show() #if not self.interfaceOK: if self.trace1.recomputeInterface==False and \ self.trace2.recomputeInterface==False: #Interface between ET1 and ET2 structures was previously computed #after a "Map ranks to structure" on ET1 and ET2 pass else: self.trace1.recomputeInterface=False self.trace2.recomputeInterface=False self.computeInterface_cb() print "Computing coupling z-scores using structures \'%s\' and \'%s\'..." % (self.trace1.structurename+self.trace1.chainindicator, self.trace2.structurename+self.trace2.chainindicator) #et1 and et2 are list of ints of residue numbers et1=self.trace1.getETselection() et2=self.trace2.getETselection() print "ET selections", et1, et2 if 1: #if len(et1)>0 and len(et2)>0: L1=self.trace1.ranksObj.getSize() L2=self.trace2.ranksObj.getSize() w,w_ave,w_stdev=self.computeCoupling(et1,et2,L1,L2,self._A1) self.scw.setvalue(w) self.scw_ave.setvalue(w_ave) self.scw_stdev.setvalue(w_stdev) if w_stdev>0: self.zscore.setvalue((w-w_ave)/w_stdev) else: self.zscore.setvalue('NA') print "...done" except Exception, detail: print 'An exception occurred in showZScores!' print detail self.et_messagebox.withdraw() else: self.zscore.setvalue('') self.scw.setvalue('') self.scw_ave.setvalue('') self.scw_stdev.setvalue('') print "Must provide structures and map trace results in ET1 and ET2!" def zscoreBusyMessage(self): tog=True #Loop until showZScores_run finishes with calculation while not self.zscoreDoneEvent.isSet(): if tog: self.zscore_buttonbox.button(1).configure(background='green') #self.zscore.setvalue('PROCESSING...') else: self.zscore_buttonbox.button(1).configure(background=self.zscore_button_bg) #self.zscore.setvalue('') tog=not tog time.sleep(0.5) #Notify showZScores_run that pulsing message has ended self.zscoreBusyDoneEvent.set() def showZScores_run(self): #if self.trace1.ranksStructureOK and self.trace2.ranksStructureOK: try: #if not self.interfaceOK: if self.trace1.recomputeInterface==False and \ self.trace2.recomputeInterface==False: #Interface between ET1 and ET2 structures was previously computed #after a "Map ranks to structure" on ET1 and ET2 pass else: self.trace1.recomputeInterface=False self.trace2.recomputeInterface=False self.computeInterface_cb() ## print "Computing adjacency matrix for protein-protein interface A(i,j)..." ## self._A1,self._A2,ResAtoms1,ResAtoms2=self.computeInterface(self.trace1.structurename, ## self.trace2.structurename, ## CONTACT_DISTANCE2) #(4 A)^2 ## if self._A1==None: ## return ## else: ## self.interfaceOK=True ## print "%d interface residues in %s" % (len(self._A1),self.trace1.structurename) ## print "%d interface residues in %s" % (len(self._A2),self.trace2.structurename) ## print "Adjacency lists:" ## print self.trace1.structurename, self._A1 ## print self.trace2.structurename, self._A2 ## print "... done" print "Computing coupling z-scores using structures \'%s\' and \'%s\'..." % (self.trace1.structurename+self.trace1.chainindicator, self.trace2.structurename+self.trace2.chainindicator) #et1 and et2 are list of ints of residue numbers et1=self.trace1.getETselection() et2=self.trace2.getETselection() print "ET selections", et1, et2 if 1: #if len(et1)>0 and len(et2)>0: L1=self.trace1.ranksObj.getSize() L2=self.trace2.ranksObj.getSize() w,w_ave,w_stdev=self.computeCoupling(et1,et2,L1,L2,self._A1) self.scw.setvalue(w) self.scw_ave.setvalue(w_ave) self.scw_stdev.setvalue(w_stdev) if w_stdev>0: self.zscore.setvalue((w-w_ave)/w_stdev) else: self.zscore.setvalue('NA') print "...done" except Exception, detail: print 'An exception occurred in showZScores_run!' print detail #self.markDoneEvent.set() self.zscoreDoneEvent.set() self.zscoreBusyDoneEvent.wait(5) ## self.zscore.setvalue('') ## self.scw.setvalue('') ## self.scw_ave.setvalue('') ## self.scw_stdev.setvalue('') self.zscore_buttonbox.button(1).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.trace1.map_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.trace1.load_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.trace2.map_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.trace2.load_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) # Modify CouplingGroup to have selectable list of traces class CouplingGroup2: #Reuse some functions useful for calculating coupling z-score calcDist=_et_calcDist computeInterface=_et_computeInterface computeCoupling=_et_computeCoupling def __init__(self, page, tracelist=[], groupname='Coupling z-score', et_messagebox=None): group = Pmw.Group(page,tag_text=groupname) self.et_messagebox=et_messagebox self.tracelist=tracelist group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) self.zscore_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.zscore_buttonbox.add('Update interface',command=self.computeInterface_cb) self.zscore_buttonbox.add('Compute coupling z-score',command=self.showZScores) self.scw = Pmw.EntryField(group.interior(), labelpos='w', label_text='Number of ET couples, c: ', value='', ) self.scw_ave = Pmw.EntryField(group.interior(), labelpos='w', label_text=' average: ', value='', ) self.scw_stdev = Pmw.EntryField(group.interior(), labelpos='w', label_text='c stdev: ', value='', ) self.zscore = Pmw.EntryField(group.interior(), labelpos='w', label_text='z-score: ', value='', ) self.tracesframe=Tkinter.Frame(group.interior()) self.traces_tuple = tuple([t.groupname for t in self.tracelist]) self.show_traces_options1 = Pmw.OptionMenu(self.tracesframe, #group.interior(), labelpos = 'w', label_text = 'Select 1st trace', items = self.traces_tuple, initialitem = self.traces_tuple[0], #command=self.slider_button_release ) self.show_traces_options2 = Pmw.OptionMenu(self.tracesframe, #group.interior(), labelpos = 'w', label_text = 'Select 2nd trace', items = self.traces_tuple, initialitem = self.traces_tuple[1], #command=self.slider_button_release ) self.show_traces_options1.grid(column=0,row=0) self.show_traces_options2.grid(column=1,row=0) for entry in (self.tracesframe, self.zscore_buttonbox, self.zscore, self.scw, self.scw_ave, self.scw_stdev): entry.pack(fill='x',padx=4,pady=1) # vertical self.balloon=Pmw.Balloon(group.interior()) self.balloon.bind(self.zscore_buttonbox.button(0), "Recompute the interface between structures") self.balloon.bind(self.zscore_buttonbox.button(1), "Click to start computing the ET coupling z-score using ET residue selections in 1st and 2nd trace") self.balloon.bind(self.zscore,"(c-)/stdev") self.interfaceOK=False #Deprecated self.zscore_buttonbox.button(0).configure(state=DISABLED) #Disable Update interface for now self.zscore_button_bg=self.zscore_buttonbox.button(1).cget('background') self.zscore_button_state=self.zscore_buttonbox.button(1).cget('state') def computeInterface_cb(self): #self.interfaceOK=False self.trace1=self.tracelist[self.show_traces_options1.index(Pmw.SELECT)] self.trace2=self.tracelist[self.show_traces_options2.index(Pmw.SELECT)] if self.trace1==self.trace2: print "Cannot compute the coupling z-score for identical structures!" return if self.trace1.ranksStructureOK and self.trace2.ranksStructureOK: if len(self.trace1.chainindicator)>0: structurename1='%s and chain %s' % (self.trace1.structurename, self.trace1.chainindicator) else: structurename1=self.trace1.structurename if len(self.trace2.chainindicator)>0: structurename2='%s and chain %s' % (self.trace2.structurename, self.trace2.chainindicator) else: structurename2=self.trace2.structurename print "Computing adjacency matrix for protein-protein interface A(i,j)..." self._A1,self._A2,ResAtoms1,ResAtoms2=self.computeInterface(structurename1, structurename2, CONTACT_DISTANCE2) if self._A1==None: return else: #self.interfaceOK=True print "%d interface residues in %s" % (len(self._A1),structurename1) print "%d interface residues in %s" % (len(self._A2),structurename2) print "Adjacency lists:" print structurename1, self._A1 print structurename2, self._A2 print "... done" else: print "Must provide structures and map trace results first!" def showZScores(self): self.trace1=self.tracelist[self.show_traces_options1.index(Pmw.SELECT)] self.trace2=self.tracelist[self.show_traces_options2.index(Pmw.SELECT)] if self.trace1==self.trace2: print "Cannot compute the coupling z-score for identical structures!" return if self.trace1.ranksStructureOK and self.trace2.ranksStructureOK: self.zscore.setvalue('') self.scw.setvalue('') self.scw_ave.setvalue('') self.scw_stdev.setvalue('') try: self.et_messagebox.show() #if not self.interfaceOK: ## if self.trace1.recomputeInterface==False and \ ## self.trace2.recomputeInterface==False: ## #Interface between ET1 and ET2 structures was previously computed ## #after a "Map ranks to structure" on ET1 and ET2 ## pass ## else: ## self.trace1.recomputeInterface=False ## self.trace2.recomputeInterface=False if 1: self.computeInterface_cb() print "Computing coupling z-scores using structures \'%s\' and \'%s\'..." % (self.trace1.structurename+self.trace1.chainindicator, self.trace2.structurename+self.trace2.chainindicator) #et1 and et2 are list of ints of residue numbers et1=self.trace1.getETselection() et2=self.trace2.getETselection() print "ET selections", et1, et2 if 1: #if len(et1)>0 and len(et2)>0: L1=self.trace1.ranksObj.getSize() L2=self.trace2.ranksObj.getSize() w,w_ave,w_stdev=self.computeCoupling(et1,et2,L1,L2,self._A1) self.scw.setvalue(w) self.scw_ave.setvalue(w_ave) self.scw_stdev.setvalue(w_stdev) if w_stdev>0: self.zscore.setvalue((w-w_ave)/w_stdev) else: self.zscore.setvalue('NA') print "...done" except Exception, detail: print 'An exception occurred in showZScores!' print detail self.et_messagebox.withdraw() else: self.zscore.setvalue('') self.scw.setvalue('') self.scw_ave.setvalue('') self.scw_stdev.setvalue('') print "Must provide structures and map trace results in 1st and 2nd trace!" def showZScores_run(self): #if self.trace1.ranksStructureOK and self.trace2.ranksStructureOK: try: #if not self.interfaceOK: if self.trace1.recomputeInterface==False and \ self.trace2.recomputeInterface==False: #Interface between ET1 and ET2 structures was previously computed #after a "Map ranks to structure" on ET1 and ET2 pass else: self.trace1.recomputeInterface=False self.trace2.recomputeInterface=False self.computeInterface_cb() ## print "Computing adjacency matrix for protein-protein interface A(i,j)..." ## self._A1,self._A2,ResAtoms1,ResAtoms2=self.computeInterface(self.trace1.structurename, ## self.trace2.structurename, ## CONTACT_DISTANCE2) #(4 A)^2 ## if self._A1==None: ## return ## else: ## self.interfaceOK=True ## print "%d interface residues in %s" % (len(self._A1),self.trace1.structurename) ## print "%d interface residues in %s" % (len(self._A2),self.trace2.structurename) ## print "Adjacency lists:" ## print self.trace1.structurename, self._A1 ## print self.trace2.structurename, self._A2 ## print "... done" print "Computing coupling z-scores using structures \'%s\' and \'%s\'..." % (self.trace1.structurename+self.trace1.chainindicator, self.trace2.structurename+self.trace2.chainindicator) #et1 and et2 are list of ints of residue numbers et1=self.trace1.getETselection() et2=self.trace2.getETselection() print "ET selections", et1, et2 if 1: #if len(et1)>0 and len(et2)>0: L1=self.trace1.ranksObj.getSize() L2=self.trace2.ranksObj.getSize() w,w_ave,w_stdev=self.computeCoupling(et1,et2,L1,L2,self._A1) self.scw.setvalue(w) self.scw_ave.setvalue(w_ave) self.scw_stdev.setvalue(w_stdev) if w_stdev>0: self.zscore.setvalue((w-w_ave)/w_stdev) else: self.zscore.setvalue('NA') print "...done" except Exception, detail: print 'An exception occurred in showZScores_run!' print detail #self.markDoneEvent.set() self.zscoreDoneEvent.set() self.zscoreBusyDoneEvent.wait(5) ## self.zscore.setvalue('') ## self.scw.setvalue('') ## self.scw_ave.setvalue('') ## self.scw_stdev.setvalue('') self.zscore_buttonbox.button(1).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.trace1.map_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.trace1.load_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.trace2.map_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) self.trace2.load_buttonbox.button(0).configure(state=self.zscore_button_state, background=self.zscore_button_bg) ########################################################################### #Group for computing the z-score of the #Selection Clustering Weight (SCW) (Mihalek,Res,Yao,Lichtarge,JMB,2003) class SCWGroup: #Reuse some functions useful for calculating clustering z-score calcDist=_et_calcDist computeAdjacency=_et_computeAdjacency #calcZScore=_et_calcZScore def __init__(self, page, groupname='Selection Clustering Weight (SCW)', defaultstructurename='(pdb)', defaultselectionname='(sele)', defaultqualitymeasure=0): group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) #Field for entering name of structure or model self.structure = Pmw.EntryField(group.interior(), labelpos='w', label_text='structure to use: ', value=defaultstructurename, ) self.selection = Pmw.EntryField(group.interior(), labelpos='w', label_text='residue selection to use: ', value=defaultselectionname, ) self.qualitymeasure_options_tuple = ('3D nobias', '3D bias (j-i)') self.show_qualitymeasure_options = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'quality measure: ', items = self.qualitymeasure_options_tuple, initialitem = self.qualitymeasure_options_tuple[defaultqualitymeasure], ) self.zscore_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.zscore_buttonbox.add('Compute adjacency',command=self.computeAdjacency_cb) self.zscore_buttonbox.add('Compute z-score',command=self.showZScores) self.scw = Pmw.EntryField(group.interior(), labelpos='w', label_text='SCW: ', value='', ) self.scw_ave = Pmw.EntryField(group.interior(), labelpos='w', label_text=' average: ', value='', ) self.scw_stdev = Pmw.EntryField(group.interior(), labelpos='w', label_text='SCW stdev: ', value='', ) self.zscore = Pmw.EntryField(group.interior(), labelpos='w', label_text='z-score: ', value='', ) for entry in (self.structure, self.selection, self.show_qualitymeasure_options, self.zscore_buttonbox, self.zscore, self.scw, self.scw_ave, self.scw_stdev): entry.pack(fill='x',padx=4,pady=1) # vertical self.adjacencyOK=False def computeAdjacency_cb(self): self.adjacencyOK=False self.structurename=self.structure.getvalue().strip() print "Computing adjacency matrix A(i,j)..." self._A,ResAtoms,self._Ar=self.computeAdjacency(self.structurename) if self._A==None: return else: self.adjacencyOK=True self.numres=len(ResAtoms) print "... done" def showZScores(self): if 1: structurename=self.structure.getvalue().strip() if self.show_qualitymeasure_options.getvalue()==self.qualitymeasure_options_tuple[0]: bias=0 elif self.show_qualitymeasure_options.getvalue()==self.qualitymeasure_options_tuple[1]: bias=1 if not self.adjacencyOK or structurename!=self.structurename: self.structurename=structurename self.adjacencyOK=False print "Computing adjacency matrix A(i,j)..." self._A,ResAtoms,self._Ar=self.computeAdjacency(structurename) if self._A==None: return else: self.adjacencyOK=True self.numres=len(ResAtoms) print "... done" #Get the list of selected residues selectionname=self.selection.getvalue().strip() try: selemodel=cmd.get_model(selectionname) except Exception: print "Selection \'%s\' does not exist!" % selectionname return SeleResAtoms={} #List of atom coordinates indexed by residue number #atom.resi is a string, convert it to int for i in range(len(selemodel.atom)): atom=selemodel.atom[i] try: SeleResAtoms[int(atom.resi)].append(atom.coord) except KeyError: SeleResAtoms[int(atom.resi)]=[atom.coord] print "Computing z-scores using structure \'%s\' and selection \'%s\'..." % (structurename, selectionname) print "Residue list = ", SeleResAtoms.keys() zscore,w,w_ave,w_stdev=self.calcZScore(SeleResAtoms.keys(),self.numres,bias) self.scw.setvalue(w) self.scw_ave.setvalue(w_ave) self.scw_stdev.setvalue(w_stdev) self.zscore.setvalue(zscore) print "...done" #Calculate z-score (z_S) for residue selection reslist=[1,2,...] #z_S = (w-_S)/sigma_S #The steps are: #1. Calculate Selection Clustering Weight (SCW) 'w' #2. Calculate mean SCW (_S) in the ensemble of random # selections of len(reslist) residues #3. Calculate mean square SCW (_S) and standard deviation (sigma_S) #Reference: Mihalek, Res, Yao, Lichtarge (2003) def calcZScore(self,reslist,L,bias=1): A=self._A #Calculate w w=0 if bias==1: for resi in reslist: for resj in reslist: if resi_S and _S. #Use expressions (3),(4),(5),(6) in Reference. M=len(reslist) #L=self.numres pi1=M*(M-1.0)/(L*(L-1.0)) pi2=pi1*(M-2.0)/(L-2.0) pi3=pi2*(M-3.0)/(L-3.0) w_ave=0 w2_ave=0 if bias==1: for resi, neighborsj in A.items(): for resj in neighborsj: w_ave+=(resj-resi) for resk, neighborsl in A.items(): for resl in neighborsl: if (resi==resk and resj==resl) or \ (resi==resl and resj==resk): w2_ave+=pi1*(resj-resi)*(resl-resk) elif (resi==resk) or (resj==resl) or \ (resi==resl) or (resj==resk): w2_ave+=pi2*(resj-resi)*(resl-resk) else: w2_ave+=pi3*(resj-resi)*(resl-resk) elif bias==0: for resi, neighborsj in A.items(): w_ave+=len(neighborsj) for resj in neighborsj: #w_ave+=1 for resk, neighborsl in A.items(): for resl in neighborsl: if (resi==resk and resj==resl) or \ (resi==resl and resj==resk): w2_ave+=pi1 elif (resi==resk) or (resj==resl) or \ (resi==resl) or (resj==resk): w2_ave+=pi2 else: w2_ave+=pi3 w_ave=w_ave*pi1 #print "w_ave", w_ave sigma=math.sqrt(w2_ave-w_ave*w_ave) #print "sigma", sigma return (w-w_ave)/sigma, w, w_ave, sigma class InterfaceControlGroup: computeInterface=_et_computeInterface calcDist=_et_calcDist def __init__(self, page, groupname='Protein-protein interface', defaultstructurename1='(pdb)', defaultstructurename2='(pdb)', defaultchain1='', defaultchain2='', defaultdistance=4, interfacecolor1='red', interfacecolor2='red', defaultinterfaceoption1=0, defaultinterfaceoption2=0, et_messagebox=None): self.interfacecolor1=interfacecolor1 self.interfacecolor2=interfacecolor2 self.et_messagebox=et_messagebox group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) self.structureframe1=Tkinter.Frame(group.interior()) #Field for entering name of structure or model self.structure1 = Pmw.EntryField(self.structureframe1, labelpos='w', label_text='structure 1: ', value=defaultstructurename1, ) self.chain1 = Pmw.EntryField(self.structureframe1, labelpos='w', label_text='chain: ', value=defaultchain1, ) self.structure1.grid(column=0,row=0) self.chain1.grid(column=1,row=0) self.structureframe2=Tkinter.Frame(group.interior()) self.structure2 = Pmw.EntryField(self.structureframe2, labelpos='w', label_text='structure 2: ', value=defaultstructurename2, ) self.chain2 = Pmw.EntryField(self.structureframe2, labelpos='w', label_text='chain: ', value=defaultchain2, ) self.structure2.grid(column=0,row=0) self.chain2.grid(column=1,row=0) self.distance = Pmw.EntryField(group.interior(), labelpos='w', label_text='distance to use for interface: ', validate={'validator':'real','min':1,'max':20}, value=defaultdistance, ) self.mark_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.mark_buttonbox.add('Mark interface',command=self.markInterface) self.interface_options_tuple1 = ('Colors only('+self.interfacecolor1+')', 'as Spheres', 'as Sticks', 'as Selection', 'None') self.interface_options_tuple2 = ('Colors only('+self.interfacecolor2+')', 'as Spheres', 'as Sticks', 'as Selection', 'None') self.show_interface_options1 = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'Show interface residues (structure 1)', items = self.interface_options_tuple1, initialitem = self.interface_options_tuple1[defaultinterfaceoption1], command=self.updateInterface #Need two arguments for this method ) self.show_interface_options2 = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'Show interface residues (structure 2)', items = self.interface_options_tuple2, initialitem = self.interface_options_tuple2[defaultinterfaceoption2], command=self.updateInterface ) for entry in (self.structureframe1, self.structureframe2, self.distance, self.mark_buttonbox, self.show_interface_options1, self.show_interface_options2, ): entry.pack(fill='x',padx=4,pady=1) # vertical self.balloon=Pmw.Balloon(group.interior()) self.balloon.bind(self.structure1, "Enter a name from the list of objects in the PyMOL Viewer") self.balloon.bind(self.structure2, "Enter a name from the list of objects in the PyMOL Viewer") self.balloon.bind(self.distance, "Maximum inter-residue atom-atom distance (Angstroms)") self.balloon.bind(self.mark_buttonbox, "Click to start interface calculation and display") self.balloon.bind(self.show_interface_options1, "Select display style to distinguish interface residues from the rest of structure 1") self.balloon.bind(self.show_interface_options2, "Select display style to distinguish interface residues from the rest of structure 2") self.interfaceComputed=False self.mark_button_bg=self.mark_buttonbox.button(0).cget('background') self.mark_button_state=self.mark_buttonbox.button(0).cget('state') if _ET_THREADING: #Threading as a response to reviewers 08/24/10 def markInterface(self): self.interfaceComputed=False supper1=self.structure1.getvalue().strip().upper() supper2=self.structure2.getvalue().strip().upper() for n in cmd.get_names('all'): if supper1==n.upper(): break else: print 'structure 1 name must be in PyMOL viewer list:' print cmd.get_names('all') return for n in cmd.get_names('all'): if supper2==n.upper(): break else: print 'structure 2 name must be in PyMOL viewer list:' print cmd.get_names('all') return if 1: self.mark_buttonbox.button(0).configure(state=DISABLED) self.markBusyDoneEvent=Event() self.markDoneEvent=Event() tm=Thread(target=self.markBusyMessage) tm.start() tz=Thread(target=self.markInterface_run) tz.start() else: def markInterface(self): try: self.interfaceComputed=False supper1=self.structure1.getvalue().strip().upper() supper2=self.structure2.getvalue().strip().upper() for n in cmd.get_names('all'): if supper1==n.upper(): break else: print 'structure 1 name must be in PyMOL viewer list:' print cmd.get_names('all') return for n in cmd.get_names('all'): if supper2==n.upper(): break else: print 'structure 2 name must be in PyMOL viewer list:' print cmd.get_names('all') return chainindicator1=self.chain1.getvalue().strip() self.s1=self.structure1.getvalue().strip() #Save these self.c1=chainindicator1 if len(chainindicator1)>0: structurename1=self.s1+' and chain %s' % chainindicator1 else: structurename1=self.s1 chainindicator2=self.chain2.getvalue().strip() self.s2=self.structure2.getvalue().strip() self.c2=chainindicator2 if len(chainindicator2)>0: structurename2=self.s2+' and chain %s' % chainindicator2 else: structurename2=self.s2 dist=float(self.distance.getvalue().strip()) if len(self.structure1.getvalue().strip())<1: print 'Provide structure 1 name!' return if len(self.structure2.getvalue().strip())<1: print 'Provide structure 2 name!' return self.et_messagebox.show() #In self.interface1, each residue indexes into an array of neighboring residues in the other structure (self.interface1, self.interface2, self.ResAtoms1, self.ResAtoms2)=self.computeInterface(structurename1,structurename2,dist*dist) if (self.interface1 is None) or (self.interface2 is None): self.interfaceComputed=False self.et_messagebox.withdraw() return self.interfaceComputed=True print "%d interface residues in %s" % (len(self.interface1),structurename1) print "%d interface residues in %s" % (len(self.interface2),structurename2) print "Adjacency lists:" print structurename1, self.interface1 print structurename2, self.interface2 self.updateInterface(None) except Exception, detail: print 'An exception occurred in markInterface!' print detail self.et_messagebox.withdraw() def markBusyMessage(self): tog=True #Loop until markInterface_run finishes with calculation while not self.markDoneEvent.isSet(): if tog: self.mark_buttonbox.button(0).configure(background='green') else: self.mark_buttonbox.button(0).configure(background=self.mark_button_bg) tog=not tog time.sleep(0.5) #Notify markInterface_run that pulsing message has ended self.markBusyDoneEvent.set() def markInterface_run(self): try: chainindicator1=self.chain1.getvalue().strip() self.s1=self.structure1.getvalue().strip() #Save these self.c1=chainindicator1 if len(chainindicator1)>0: structurename1=self.s1+' and chain %s' % chainindicator1 else: structurename1=self.s1 chainindicator2=self.chain2.getvalue().strip() self.s2=self.structure2.getvalue().strip() self.c2=chainindicator2 if len(chainindicator2)>0: structurename2=self.s2+' and chain %s' % chainindicator2 else: structurename2=self.s2 dist=float(self.distance.getvalue().strip()) if len(self.structure1.getvalue().strip())<1: print 'Provide structure 1 name!' self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return if len(self.structure2.getvalue().strip())<1: print 'Provide structure 2 name!' self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return #In self.interface1, each residue indexes into an array of neighboring residues in the other structure (self.interface1, self.interface2, self.ResAtoms1, self.ResAtoms2)=self.computeInterface(structurename1,structurename2,dist*dist) if (self.interface1 is None) or (self.interface2 is None): self.interfaceComputed=False self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return self.interfaceComputed=True print "%d interface residues in %s" % (len(self.interface1),structurename1) print "%d interface residues in %s" % (len(self.interface2),structurename2) print "Adjacency lists:" print structurename1, self.interface1 print structurename2, self.interface2 self.updateInterface(None) except Exception, detail: print 'An exception occurred in markInterface_run!' print detail #self.markDoneEvent.set() self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) def updateInterface(self,event): #TODO: Make this method more aware of changes in the viewer if self.interfaceComputed==False: return ## s1=self.structure1.getvalue().strip() ## s2=self.structure2.getvalue().strip() ## c1=self.chain1.getvalue().strip() ## c2=self.chain2.getvalue().strip() s1=self.s1 s2=self.s2 c1=self.c1 c2=self.c2 if len(c1)>0: structurename1=s1+' and chain %s' % c1 else: structurename1=s1 if len(c2)>0: structurename2=s2+' and chain %s' % c2 else: structurename2=s2 if self.show_interface_options1.getvalue()==self.interface_options_tuple1[0]: for res in self.interface1.keys(): cmd.color(self.interfacecolor1,'%s and resi %s' % (structurename1,res)) elif self.show_interface_options1.getvalue()==self.interface_options_tuple1[1]: for res in self.interface1.keys(): cmd.show('spheres','%s and resi %s' % (structurename1,res)) elif self.show_interface_options1.getvalue()==self.interface_options_tuple1[2]: for res in self.interface1.keys(): cmd.show('sticks','%s and resi %s' % (structurename1,res)) elif self.show_interface_options1.getvalue()==self.interface_options_tuple1[3]: #Make a selection of the ET residues if len(self.interface1)>0: cmd.select('%s_%s_PyETV' % (s1+c1,s2+c2),'%s and resi %s' % (structurename1,string.join(map(str,self.interface1),'+'))) else: cmd.select('%s_%s_PyETV' % (s1+c1,s2+c2),'none') if self.show_interface_options2.getvalue()==self.interface_options_tuple2[0]: for res in self.interface2.keys(): cmd.color(self.interfacecolor2,'%s and resi %s' % (structurename2,res)) elif self.show_interface_options2.getvalue()==self.interface_options_tuple2[1]: for res in self.interface2.keys(): cmd.show('spheres','%s and resi %s' % (structurename2,res)) elif self.show_interface_options2.getvalue()==self.interface_options_tuple2[2]: for res in self.interface2.keys(): cmd.show('sticks','%s and resi %s' % (structurename2,res)) elif self.show_interface_options2.getvalue()==self.interface_options_tuple2[3]: #Make a selection of the ET residues if len(self.interface2)>0: cmd.select('%s_%s_PyETV' % (s2+c2,s1+c1),'%s and resi %s' % (structurename2,string.join(map(str,self.interface2),'+'))) else: cmd.select('%s_%s_PyETV' % (s2+c2,s1+c1),'none') #Compute interface between traces from a selectable list class InterfaceControlGroup2: computeInterface=_et_computeInterface calcDist=_et_calcDist def __init__(self, page, groupname='Protein-protein interface', tracelist=[], defaultstructurename1='(pdb)', defaultstructurename2='(pdb)', defaultchain1='', defaultchain2='', defaultdistance=4, interfacecolor1='red', interfacecolor2='red', defaultinterfaceoption1=0, defaultinterfaceoption2=0, et_messagebox=None): self.interfacecolor1=interfacecolor1 self.interfacecolor2=interfacecolor2 self.et_messagebox=et_messagebox group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) self.structureframe1=Tkinter.Frame(group.interior()) #Field for entering name of structure or model self.structure1 = Pmw.EntryField(self.structureframe1, labelpos='w', label_text='structure 1: ', value=defaultstructurename1, ) self.chain1 = Pmw.EntryField(self.structureframe1, labelpos='w', label_text='chain: ', value=defaultchain1, ) self.structure1.grid(column=0,row=0) self.chain1.grid(column=1,row=0) self.structureframe2=Tkinter.Frame(group.interior()) self.structure2 = Pmw.EntryField(self.structureframe2, labelpos='w', label_text='structure 2: ', value=defaultstructurename2, ) self.chain2 = Pmw.EntryField(self.structureframe2, labelpos='w', label_text='chain: ', value=defaultchain2, ) self.structure2.grid(column=0,row=0) self.chain2.grid(column=1,row=0) self.distance = Pmw.EntryField(group.interior(), labelpos='w', label_text='distance to use for interface: ', validate={'validator':'real','min':1,'max':20}, value=defaultdistance, ) self.mark_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.mark_buttonbox.add('Mark interface',command=self.markInterface) self.interface_options_tuple1 = ('Colors only('+self.interfacecolor1+')', 'as Spheres', 'as Sticks', 'as Selection', 'None') self.interface_options_tuple2 = ('Colors only('+self.interfacecolor2+')', 'as Spheres', 'as Sticks', 'as Selection', 'None') self.show_interface_options1 = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'Show interface residues (structure 1)', items = self.interface_options_tuple1, initialitem = self.interface_options_tuple1[defaultinterfaceoption1], command=self.updateInterface #Need two arguments for this method ) self.show_interface_options2 = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'Show interface residues (structure 2)', items = self.interface_options_tuple2, initialitem = self.interface_options_tuple2[defaultinterfaceoption2], command=self.updateInterface ) self.tracelist=tracelist self.tracesframe=Tkinter.Frame(group.interior()) self.traces_tuple = tuple([t.groupname for t in self.tracelist]) self.show_traces_options1 = Pmw.OptionMenu(self.tracesframe, #group.interior(), labelpos = 'w', label_text = 'Select 1st trace', items = self.traces_tuple, initialitem = self.traces_tuple[0], #command=self.slider_button_release ) self.show_traces_options2 = Pmw.OptionMenu(self.tracesframe, #group.interior(), labelpos = 'w', label_text = 'Select 2nd trace', items = self.traces_tuple, initialitem = self.traces_tuple[1], #command=self.slider_button_release ) self.show_traces_options1.grid(column=0,row=0) self.show_traces_options2.grid(column=1,row=0) for entry in (self.tracesframe, #self.structureframe1, #self.structureframe2, self.distance, self.mark_buttonbox, self.show_interface_options1, self.show_interface_options2, ): entry.pack(fill='x',padx=4,pady=1) # vertical self.balloon=Pmw.Balloon(group.interior()) self.balloon.bind(self.structure1, "Enter a name from the list of objects in the PyMOL Viewer") self.balloon.bind(self.structure2, "Enter a name from the list of objects in the PyMOL Viewer") self.balloon.bind(self.distance, "Maximum inter-residue atom-atom distance (Angstroms)") self.balloon.bind(self.mark_buttonbox, "Click to start interface calculation and display") self.balloon.bind(self.show_interface_options1, "Select display style to distinguish interface residues from the rest of structure 1") self.balloon.bind(self.show_interface_options2, "Select display style to distinguish interface residues from the rest of structure 2") self.interfaceComputed=False self.mark_button_bg=self.mark_buttonbox.button(0).cget('background') self.mark_button_state=self.mark_buttonbox.button(0).cget('state') def markInterface(self): try: self.interfaceComputed=False self.trace1=self.tracelist[self.show_traces_options1.index(Pmw.SELECT)] self.trace2=self.tracelist[self.show_traces_options2.index(Pmw.SELECT)] if self.trace1==self.trace2: print "Cannot compute the interface for identical structures!" return supper1=self.trace1.structurename.upper() supper2=self.trace2.structurename.upper() #supper1=self.structure1.getvalue().strip().upper() #supper2=self.structure2.getvalue().strip().upper() for n in cmd.get_names('all'): if supper1==n.upper(): break else: print 'structure 1 name must be in PyMOL viewer list:' print cmd.get_names('all') return for n in cmd.get_names('all'): if supper2==n.upper(): break else: print 'structure 2 name must be in PyMOL viewer list:' print cmd.get_names('all') return chainindicator1=self.trace1.chainindicator self.s1=self.trace1.structurename #chainindicator1=self.chain1.getvalue().strip() #self.s1=self.structure1.getvalue().strip() #Save these self.c1=chainindicator1 if len(chainindicator1)>0: structurename1=self.s1+' and chain %s' % chainindicator1 else: structurename1=self.s1 chainindicator2=self.trace2.chainindicator self.s2=self.trace2.structurename #chainindicator2=self.chain2.getvalue().strip() #self.s2=self.structure2.getvalue().strip() self.c2=chainindicator2 if len(chainindicator2)>0: structurename2=self.s2+' and chain %s' % chainindicator2 else: structurename2=self.s2 dist=float(self.distance.getvalue().strip()) if len(self.structure1.getvalue().strip())<1: print 'Provide structure 1 name!' return if len(self.structure2.getvalue().strip())<1: print 'Provide structure 2 name!' return self.et_messagebox.show() #In self.interface1, each residue indexes into an array of neighboring residues in the other structure (self.interface1, self.interface2, self.ResAtoms1, self.ResAtoms2)=self.computeInterface(structurename1,structurename2,dist*dist) if (self.interface1 is None) or (self.interface2 is None): self.interfaceComputed=False self.et_messagebox.withdraw() return self.interfaceComputed=True print "%d interface residues in %s" % (len(self.interface1),structurename1) print "%d interface residues in %s" % (len(self.interface2),structurename2) print "Adjacency lists:" print structurename1, self.interface1 print structurename2, self.interface2 self.updateInterface(None) except Exception, detail: print 'An exception occurred in markInterface!' print detail self.et_messagebox.withdraw() def markInterface_run(self): try: chainindicator1=self.chain1.getvalue().strip() self.s1=self.structure1.getvalue().strip() #Save these self.c1=chainindicator1 if len(chainindicator1)>0: structurename1=self.s1+' and chain %s' % chainindicator1 else: structurename1=self.s1 chainindicator2=self.chain2.getvalue().strip() self.s2=self.structure2.getvalue().strip() self.c2=chainindicator2 if len(chainindicator2)>0: structurename2=self.s2+' and chain %s' % chainindicator2 else: structurename2=self.s2 dist=float(self.distance.getvalue().strip()) if len(self.structure1.getvalue().strip())<1: print 'Provide structure 1 name!' self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return if len(self.structure2.getvalue().strip())<1: print 'Provide structure 2 name!' self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return #In self.interface1, each residue indexes into an array of neighboring residues in the other structure (self.interface1, self.interface2, self.ResAtoms1, self.ResAtoms2)=self.computeInterface(structurename1,structurename2,dist*dist) if (self.interface1 is None) or (self.interface2 is None): self.interfaceComputed=False self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) return self.interfaceComputed=True print "%d interface residues in %s" % (len(self.interface1),structurename1) print "%d interface residues in %s" % (len(self.interface2),structurename2) print "Adjacency lists:" print structurename1, self.interface1 print structurename2, self.interface2 self.updateInterface(None) except Exception, detail: print 'An exception occurred in markInterface_run!' print detail #self.markDoneEvent.set() self.markDoneEvent.set() self.markBusyDoneEvent.wait(5) self.mark_buttonbox.button(0).configure(state=self.mark_button_state, background=self.mark_button_bg) def updateInterface(self,event): #TODO: Make this method more aware of changes in the viewer if self.interfaceComputed==False: return ## s1=self.structure1.getvalue().strip() ## s2=self.structure2.getvalue().strip() ## c1=self.chain1.getvalue().strip() ## c2=self.chain2.getvalue().strip() s1=self.s1 s2=self.s2 c1=self.c1 c2=self.c2 if len(c1)>0: structurename1=s1+' and chain %s' % c1 else: structurename1=s1 if len(c2)>0: structurename2=s2+' and chain %s' % c2 else: structurename2=s2 if self.show_interface_options1.getvalue()==self.interface_options_tuple1[0]: for res in self.interface1.keys(): cmd.color(self.interfacecolor1,'%s and resi %s' % (structurename1,res)) elif self.show_interface_options1.getvalue()==self.interface_options_tuple1[1]: for res in self.interface1.keys(): cmd.show('spheres','%s and resi %s' % (structurename1,res)) elif self.show_interface_options1.getvalue()==self.interface_options_tuple1[2]: for res in self.interface1.keys(): cmd.show('sticks','%s and resi %s' % (structurename1,res)) elif self.show_interface_options1.getvalue()==self.interface_options_tuple1[3]: #Make a selection of the ET residues if len(self.interface1)>0: cmd.select('%s_%s_PyETV' % (s1+c1,s2+c2),'%s and resi %s' % (structurename1,string.join(map(str,self.interface1),'+'))) else: cmd.select('%s_%s_PyETV' % (s1+c1,s2+c2),'none') if self.show_interface_options2.getvalue()==self.interface_options_tuple2[0]: for res in self.interface2.keys(): cmd.color(self.interfacecolor2,'%s and resi %s' % (structurename2,res)) elif self.show_interface_options2.getvalue()==self.interface_options_tuple2[1]: for res in self.interface2.keys(): cmd.show('spheres','%s and resi %s' % (structurename2,res)) elif self.show_interface_options2.getvalue()==self.interface_options_tuple2[2]: for res in self.interface2.keys(): cmd.show('sticks','%s and resi %s' % (structurename2,res)) elif self.show_interface_options2.getvalue()==self.interface_options_tuple2[3]: #Make a selection of the ET residues if len(self.interface2)>0: cmd.select('%s_%s_PyETV' % (s2+c2,s1+c1),'%s and resi %s' % (structurename2,string.join(map(str,self.interface2),'+'))) else: cmd.select('%s_%s_PyETV' % (s2+c2,s1+c1),'none') class DiffETControlGroup: #Reuse some functions useful for calculating clustering z-score calcDist=_et_calcDist computeAdjacency=_et_computeAdjacency calcZScore=_et_calcZScore def __init__(self, page, groupname='Trace', defaultstructurename='(pdb)', defaultchain='', defaultrankspath1='.ranks', defaultrankspath2='.ranks', defaultqualitymeasure=0, etcolor1='blue', etcolor2='red', etcolor12='orange', noetcolor='white', et_messagebox=None): self.etcolor1=etcolor1 self.etcolor2=etcolor2 self.etcolor12=etcolor12 self.noetcolor=noetcolor self.et_messagebox=et_messagebox group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) self.balloon=Pmw.Balloon(group.interior()) self.structureframe=Tkinter.Frame(group.interior()) #Field for entering name of structure or model self.structure = Pmw.EntryField(self.structureframe, labelpos='w', label_text='structure to use: ', value=defaultstructurename, ) self.chain = Pmw.EntryField(self.structureframe, labelpos='w', label_text='chain: ', value=defaultchain, ) self.structure.grid(column=0,row=0) self.chain.grid(column=1,row=0) def quickFileValidation(s): if s == '': return Pmw.PARTIAL elif os.path.isfile(s): return Pmw.OK elif os.path.exists(s): return Pmw.PARTIAL else: return Pmw.PARTIAL #Button for assigning ranks to structure self.map_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.map_buttonbox.add('Map ranks to structure',command=self.mapRanks) #Field for entering ranks file self.ranksfile1 = Pmw.EntryField(group.interior(), labelpos='w', label_pyclass = FileDialogButtonClassFactory.get(self.setRanksFileLocation1, '*.ranks'), validate = {'validator':quickFileValidation,}, value = defaultrankspath1, label_text = 'Superfamily ranks file path:') self.ranksfile2 = Pmw.EntryField(group.interior(), labelpos='w', label_pyclass = FileDialogButtonClassFactory.get(self.setRanksFileLocation2, '*.ranks'), validate = {'validator':quickFileValidation,}, value = defaultrankspath2, label_text = 'Subfamily ranks file path:') self.subgroup1 = Pmw.Group(group.interior(),tag_text='Superfamily (blue+orange)') #Tkinter Slider Tkinter for changing ET residue coverage. #TODO: Use a Pmw implementation? self.slider1 = Scale(self.subgroup1.interior(), #from_=self.min, to=self.max, from_=0, to=100, showvalue=1, length=200, orient=HORIZONTAL, resolution=0.01, tickinterval=0, #repeatinterval=500, #Dunno what repeatinterval is for... repeatdelay=500 ) self.slider1.set(30) #self.slider.grid() self.slider1.bind("", self.slider_button_release) #self.slider1.bind("", self.mousebutton_click_slider1) self.slider1.bind("", self.mousebutton_click_slider1) #For Windows self.slider1.bind("", self.mousewheel_roll_slider1) #For Linux (for Mac?) self.slider1.bind("", self.mousewheel_roll_slider1) self.slider1.bind("", self.mousewheel_roll_slider1) #Field for displaying ET coverage self.frame1=Tkinter.Frame(self.subgroup1.interior()) self.percentcoverage1 = Pmw.EntryField(self.frame1, #group.interior(), labelpos='w', label_text='Percent coverage: ', value='', ) self.rankvalue1 = Pmw.EntryField(self.frame1, #group.interior(), labelpos='w', label_text='Rank: ', value='', ) self.percentcoverage1.grid(column=0,row=0) self.rankvalue1.grid(column=1,row=0) self.slider1.pack(fill='x',padx=4,pady=1) # vertical #self.balloon.bind(self.slider1,"Superfamily ranks slider") self.frame1.pack(fill='x',padx=4,pady=1) # vertical #Use options menu (combobox) instead of checkboxes self.et_options_tuple = ('Colors only('+self.etcolor1+','+self.etcolor12+','+self.etcolor2+')', 'as Spheres', 'as Spheres (C-alpha only)', 'Coverage differentials') self.show_et_options = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'Show ET residues', items = self.et_options_tuple, initialitem = self.et_options_tuple[0], command=self.slider_button_release ) ## self.show_et_var=IntVar() ## self.show_et_var.set(0) ## self.show_et_checkbutton = Checkbutton(group.interior(), ## text = "Show ET residues (as spheres)", ## variable = self.show_et_var) self.sync_sliders_var=IntVar() self.sync_sliders_var.set(1) self.sync_sliders_checkbutton = Checkbutton(group.interior(), text = "Synchronize Subfamily ranks slider to Superfamily", variable = self.sync_sliders_var) self.subgroup2 = Pmw.Group(group.interior(),tag_text='Subfamily (red+orange)') self.slider2 = Scale(self.subgroup2.interior(), #from_=self.min, to=self.max, from_=0, to=100, showvalue=1, length=200, orient=HORIZONTAL, resolution=0.01, tickinterval=0, #repeatinterval=500, #Dunno what repeatinterval is for... repeatdelay=500 ) self.slider2.set(30) #self.slider.grid() self.slider2.bind("", self.slider_button_release) #self.slider2.bind("", self.mousebutton_click_slider2) self.slider2.bind("", self.mousebutton_click_slider2) #For Windows self.slider2.bind("", self.mousewheel_roll_slider2) #For Linux (for Mac?) self.slider2.bind("", self.mousewheel_roll_slider2) self.slider2.bind("", self.mousewheel_roll_slider2) #Field for displaying ET coverage self.frame2=Tkinter.Frame(self.subgroup2.interior()) self.percentcoverage2 = Pmw.EntryField(self.frame2, #group.interior(), labelpos='w', label_text='Percent coverage: ', value='', ) self.rankvalue2 = Pmw.EntryField(self.frame2, #group.interior(), labelpos='w', label_text='Rank: ', value='', ) self.percentcoverage2.grid(column=0,row=0) self.rankvalue2.grid(column=1,row=0) self.slider2.pack(fill='x',padx=4,pady=1) # vertical #self.balloon.bind(self.slider2,"Subfamily ranks slider") self.frame2.pack(fill='x',padx=4,pady=1) # vertical self.qualitymeasure_options_tuple = ('3D nobias', '3D bias (j-i)') self.show_qualitymeasure_options = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'quality measure: ', items = self.qualitymeasure_options_tuple, initialitem = self.qualitymeasure_options_tuple[defaultqualitymeasure], ) self.zscore_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.zscore_buttonbox.add('Compute z-scores',command=self.showZScores) self.zscore1only = Pmw.EntryField(group.interior(), labelpos='w', label_text='z-score superfamily only (blue): ', value='', ) self.zscore12 = Pmw.EntryField(group.interior(), labelpos='w', label_text='z-score common (orange): ', value='', ) self.zscore2only = Pmw.EntryField(group.interior(), labelpos='w', label_text='z-score subfamily only (red): ', value='', ) for entry in (self.structureframe, self.ranksfile1, self.ranksfile2, self.map_buttonbox, self.subgroup1, #self.slider1, #self.frame1, #self.percentcoverage1, #self.rankvalue1, self.show_et_options, #self.show_et_checkbutton, self.sync_sliders_checkbutton, self.subgroup2, #self.slider2, #self.frame2, #self.percentcoverage2, #self.rankvalue2, self.zscore_buttonbox, self.show_qualitymeasure_options, self.zscore1only, self.zscore12, self.zscore2only): entry.pack(fill='x',padx=4,pady=1) # vertical self.balloon.bind(self.structure,"Enter a name from the list of objects in the PyMOL Viewer") self.balloon.bind(self.map_buttonbox,"Click once before operating the controls below") self.balloon.bind(self.slider1,"Drag superfamily ranks slider to vary ET residue selection and coverage (blue+orange) of the structure") self.balloon.bind(self.slider2,"Drag subfamily ranks slider to vary ET residue selection and coverage (red+orange) of the structure") self.balloon.bind(self.show_et_options,"Select display style to distinguish ET residue selection from the rest of the structure") self.balloon.bind(self.zscore_buttonbox,"Compute the clustering z-scores of the ET residue selections") self.balloon.bind(self.show_qualitymeasure_options,"Select from several measures of clustering quality") self.ranksObj1=ETRanks() self.ranksObj2=ETRanks() self.ranksStructureOK=False self.adjacencyOK=False def mapRanks(self): structurename=self.structure.getvalue().strip() chainindicator=self.chain.getvalue().strip() self.ranksStructureOK=False self.adjacencyOK=False if len(structurename)<1: print 'Provide structure name!' return try: model=cmd.get_model(structurename) except Exception: print "Structure \'%s\' does not exist!" % structurename return rankspath1=self.ranksfile1.getvalue().strip() if len(rankspath1)<1: print 'Provide path to superfamily ranks file!' return self.ranksObj1.readRanks(rankspath1) if self.ranksObj1.ranksLoaded(): print "Superfamily ranks file \'%s\' loaded" % rankspath1 else: print "Error loading ranks file \'%s\'!" % rankspath1 return rankspath2=self.ranksfile2.getvalue().strip() if len(rankspath2)<1: print 'Provide path to subfamily ranks file!' return self.ranksObj2.readRanks(rankspath2) if self.ranksObj2.ranksLoaded(): print "Subfamily ranks file \'%s\' loaded" % rankspath2 else: print "Error loading ranks file \'%s\'!" % rankspath2 return if self.ranksObj1.getSize()!=self.ranksObj2.getSize(): print "Residue numbers in \'%s\' and \'%s\' are not the same!" % (rankspath1, rankspath2) return #TODO: This sanity check is too restrictive. for i in range(self.ranksObj1.getSize()): if self.ranksObj1.getResnum(i)!=self.ranksObj2.getResnum(i): print "Residue numbers in \'%s\' and \'%s\' are not the same!" % (rankspath1, rankspath2) return #TODO: Make this optional #Check that the residue numbers in the model #and in the ranks file are identical ## resnumDict={} ## for i in range(len(model.atom)): ## if chaindicator==atom[i].chain: ## resnumDict[model.atom[i].resi]=1 ## if len(resnumDict)<1: ## print 'Structure \'%s\' has no residues!' % structurename ## return ## if len(resnumDict)!=self.ranksObj1.getSize(): ## print "Residue numbers in \'%s\' and \'%s\' are not the same!" % (structurename, rankspath1) ## return ## for i in range(self.ranksObj1.getSize()): ## try: ## r=resnumDict[self.ranksObj1.getResnum(i)] ## except KeyError: ## print "Residue numbers in \'%s\' and \'%s\' do not match!" % (structurename, rankspath1) return self.structurename=structurename self.chainindicator=chainindicator self.ranksStructureOK=True #print 'Residue numbers checked with structure \'%s\'' % structurename self.slider_button_release(None) #TODO: Use this method to compare the sequences between structure and ranks files #This check uses the residue numbers, not the amino acid types def checkSequence(self,model,structurename,chainindicator,rankspath): three2one={ "ALA":'A', "ARG":'R', "ASN":'N', "ASP":'D', "CYS":'C', "GLN":'Q', "GLU":'E', "GLY":'G', "HIS":'H', "ILE":'I', "LEU":'L', "LYS":'K', "MET":'M', "PHE":'F', "PRO":'P', "SER":'S', "THR":'T', "TRP":'W', "TYR":'Y', "VAL":'V', "A":"A", "G":"G", "T":"T", "U":"U", "C":"C",} print 'Comparing residue numbers of structure \'%s\' and ranks \'%s\'...' % (structurename+chainindicator, rankspath) #Check that the residue numbers in the model #and in the ranks file are identical resnumDict={} if len(chainindicator)>0: #chainup=chainindicator() #Case of chain indicator is relevant for i in range(len(model.atom)): atomobj=model.atom[i] if chainindicator==atomobj.chain: try: aa1=three2one[atomobj.resn] #Consider only residues with standard amino acids resnumDict[atomobj.resi]=1 except KeyError: pass else: for i in range(len(model.atom)): resnumDict[model.atom[i].resi]=1 print 'Sequence lengths:' print 'structure: ', len(resnumDict) print 'ranks: ', self.ranksObj.getSize() if len(resnumDict)<1: print 'Structure \'%s\' has no residues!' % (structurename+chainindicator) if len(resnumDict)!=self.ranksObj.getSize(): print "Sequence lengths of \'%s\' and \'%s\' are not the same!" % (structurename+chainindicator, rankspath) missing=0 for i in range(self.ranksObj.getSize()): try: r=resnumDict[self.ranksObj.getResnum(i)] except KeyError: missing+=1 if missing>0: print "%d residue numbers in \'%s\' missing in \'%s\'!" % (missing, rankspath, structurename+chainindicator) print '...Done.' def mousewheel_roll_slider1(self, event): slideval=self.slider1.get() #See http://www.daniweb.com/code/snippet217059.html if event.num==4 or event.delta==-120: self.slider1.set(slideval+1) self.slider_button_release(None) if event.num==5 or event.delta==120: self.slider1.set(slideval-1) self.slider_button_release(None) #print event.num, event.delta, slideval def mousebutton_click_slider1(self, event): #slideval=self.slider.get() if event.num==1 or event.num==2: self.slider_button_release(None) #print event.num, event.delta, slideval def mousewheel_roll_slider2(self, event): slideval=self.slider2.get() #See http://www.daniweb.com/code/snippet217059.html if event.num==4 or event.delta==-120: self.slider2.set(slideval+1) self.slider_button_release(None) if event.num==5 or event.delta==120: self.slider2.set(slideval-1) self.slider_button_release(None) #print event.num, event.delta, slideval def mousebutton_click_slider2(self, event): #slideval=self.slider.get() if event.num==1 or event.num==2: self.slider_button_release(None) #print event.num, event.delta, slideval def slider_button_release(self, event): if self.ranksStructureOK: self.et_messagebox.show() if len(self.chainindicator)>0: structurename='%s and chain %s' % (self.structurename,self.chainindicator) else: structurename=self.structurename maxcov1=0 maxrank1=0 maxcov2=0 maxrank2=0 slideval1=self.slider1.get() if self.sync_sliders_var.get()==1: self.slider2.set(slideval1) slideval2=slideval1 else: slideval2=self.slider2.get() #if self.show_et_var.get()==1: if self.show_et_options.getvalue()==self.et_options_tuple[3]: for i in range(self.ranksObj1.getSize()): (resnum1,cov1,rank1)=self.ranksObj1.getResnumCoverageRankTuple(i) (resnum2,cov2,rank2)=self.ranksObj2.getResnumCoverageRankTuple(i) if cov1>maxcov1: maxcov1=cov1 maxrank1=rank1 if cov2>maxcov2: maxcov2=cov2 maxrank2=rank2 cd=(cov1-cov2)/(cov1+cov2) #SuperfamilyCoverage-SubfamilyCoverage if cd>0.2: cmd.color('_et_red_color%s'%int(10*(cd-0.2)/0.8),'%s and resi %s' % (structurename,resnum1)) elif cd<-0.2: cmd.color('_et_blue_color%s'%int(10*(-cd-0.2)/0.8),'%s and resi %s' % (structurename,resnum1)) else: cmd.color('white','%s and resi %s' % (structurename,resnum1)) elif self.show_et_options.getvalue()==self.et_options_tuple[2]: cmd.hide('spheres',structurename) #Need to hide spheres in case non-CA atoms are displayed for i in range(self.ranksObj1.getSize()): (resnum1,cov1,rank1)=self.ranksObj1.getResnumCoverageRankTuple(i) (resnum2,cov2,rank2)=self.ranksObj2.getResnumCoverageRankTuple(i) #assert(resnum1==resnum2) if slideval1>=cov1: et1=True if cov1>maxcov1: maxcov1=cov1 maxrank1=rank1 else: et1=False if slideval2>=cov2: et2=True if cov2>maxcov2: maxcov2=cov2 maxrank2=rank2 else: et2=False if et1 and not et2: cmd.color(self.etcolor1,'%s and resi %s' % (structurename,resnum1)) cmd.show('spheres','%s and resi %s and name CA' % (structurename,resnum1)) elif et1 and et2: cmd.color(self.etcolor12,'%s and resi %s' % (structurename,resnum1)) cmd.show('spheres','%s and resi %s and name CA' % (structurename,resnum1)) elif et2 and not et1: cmd.color(self.etcolor2,'%s and resi %s' % (structurename,resnum1)) cmd.show('spheres','%s and resi %s and name CA' % (structurename,resnum1)) else: cmd.color(self.noetcolor,'%s and resi %s' % (structurename,resnum1)) cmd.hide('spheres','%s and resi %s' % (structurename,resnum1)) elif self.show_et_options.getvalue()==self.et_options_tuple[1]: for i in range(self.ranksObj1.getSize()): (resnum1,cov1,rank1)=self.ranksObj1.getResnumCoverageRankTuple(i) (resnum2,cov2,rank2)=self.ranksObj2.getResnumCoverageRankTuple(i) #assert(resnum1==resnum2) if slideval1>=cov1: et1=True if cov1>maxcov1: maxcov1=cov1 maxrank1=rank1 else: et1=False if slideval2>=cov2: et2=True if cov2>maxcov2: maxcov2=cov2 maxrank2=rank2 else: et2=False if et1 and not et2: cmd.color(self.etcolor1,'%s and resi %s' % (structurename,resnum1)) cmd.show('spheres','%s and resi %s' % (structurename,resnum1)) elif et1 and et2: cmd.color(self.etcolor12,'%s and resi %s' % (structurename,resnum1)) cmd.show('spheres','%s and resi %s' % (structurename,resnum1)) elif et2 and not et1: cmd.color(self.etcolor2,'%s and resi %s' % (structurename,resnum1)) cmd.show('spheres','%s and resi %s' % (structurename,resnum1)) else: #Still assign the right color even we hide it, in case the user makes #this part visible cmd.color(self.noetcolor,'%s and resi %s' % (structurename,resnum1)) cmd.hide('spheres','%s and resi %s' % (structurename,resnum1)) #elif self.show_et_options.getvalue()==self.et_options_tuple[0]: else: for i in range(self.ranksObj1.getSize()): (resnum1,cov1,rank1)=self.ranksObj1.getResnumCoverageRankTuple(i) (resnum2,cov2,rank2)=self.ranksObj2.getResnumCoverageRankTuple(i) #assert(resnum1==resnum2) if slideval1>=cov1: et1=True if cov1>maxcov1: maxcov1=cov1 maxrank1=rank1 else: et1=False if slideval2>=cov2: et2=True if cov2>maxcov2: maxcov2=cov2 maxrank2=rank2 else: et2=False if et1 and not et2: cmd.show cmd.color(self.etcolor1,'%s and resi %s' % (structurename,resnum1)) elif et1 and et2: cmd.color(self.etcolor12,'%s and resi %s' % (structurename,resnum1)) elif et2 and not et1: cmd.color(self.etcolor2,'%s and resi %s' % (structurename,resnum1)) else: cmd.color(self.noetcolor,'%s and resi %s' % (structurename,resnum1)) self.percentcoverage1.setvalue(maxcov1) self.rankvalue1.setvalue(maxrank1) self.percentcoverage2.setvalue(maxcov2) self.rankvalue2.setvalue(maxrank2) self.et_messagebox.withdraw() def setRanksFileLocation1(self,value): self.ranksfile1.setvalue(value) def setRanksFileLocation2(self,value): self.ranksfile2.setvalue(value) def showZScores(self): if self.ranksStructureOK: try: self.et_messagebox.show() if self.show_qualitymeasure_options.getvalue()==self.qualitymeasure_options_tuple[0]: bias=0 elif self.show_qualitymeasure_options.getvalue()==self.qualitymeasure_options_tuple[1]: bias=1 if not self.adjacencyOK: if len(self.chainindicator)>0: structurename='%s and chain %s' % (self.structurename,self.chainindicator) else: structurename=self.structurename print "Computing adjacency matrix A(i,j)..." self._A,ResAtoms,self._Ar=self.computeAdjacency(structurename) if self._A==None: self.et_messagebox.show() return else: self.adjacencyOK=True print "... done" #Get lists of ET residues et1only=[] et12=[] et2only=[] notet=[] slideval1=self.slider1.get() slideval2=self.slider2.get() for i in range(self.ranksObj1.getSize()): (resnum1,cov1,rank1)=self.ranksObj1.getResnumCoverageRankTuple(i) (resnum2,cov2,rank2)=self.ranksObj2.getResnumCoverageRankTuple(i) #assert(resnum1==resnum2) if slideval1>=cov1: et1=True else: et1=False if slideval2>=cov2: et2=True else: et2=False if et1 and not et2: et1only.append(int(resnum1)) elif et1 and et2: et12.append(int(resnum1)) elif et2 and not et1: et2only.append(int(resnum1)) else: notet.append(int(resnum1)) print "ET residue selection lists:" print et1only print et12 print et2only print "Computing z-scores..." if len(et1only)>0: z1only=self.calcZScore(et1only,self.ranksObj1.getSize(),self._A,bias) else: z1only='NA' if len(et12)>0: z12=self.calcZScore(et12,self.ranksObj1.getSize(),self._A,bias) else: z12='NA' if len(et2only)>0: z2only=self.calcZScore(et2only,self.ranksObj1.getSize(),self._A,bias) else: z2only='NA' self.zscore1only.setvalue(z1only) self.zscore12.setvalue(z12) self.zscore2only.setvalue(z2only) if len(notet)>0: print 'Non-ET residue z-score: ', self.calcZScore(notet,self.ranksObj1.getSize(),self._A,bias) #Test #Residues with L>0.090000: #cnet=['54', '50', '52', '110', '81', '85', '12', '42'] #Residues with L>0.080000: #cnet=['25', '21', '54', '50', '52', '110', '80', '81', '85', '12', '19', '42', '1', '76'] #Residues with L>0.070000: #cnet=['24', '25', '21', '23', '120', '124', '54', '50', '52', '110', '80', '81', '85', '31', '69', '12', '19', '48', '44', '42', '43', '1', '76'] #Residues with L>0.050000: #cnet=['24', '25', '21', '23', '29', '120', '122', '124', '58', '54', '50', '52', '110', '80', '81', '85', '31', '61', '64', '69', '98', '12', '19', '48', '44', '42', '43', '1', '76'] #Residues with L>0.030000: #cnet=['24', '25', '20', '21', '22', '23', '29', '120', '121', '122', '123', '124', '58', '55', '54', '57', '56', '50', '53', '52', '117', '111', '110', '112', '80', '81', '119', '118', '85', '106', '31', '60', '61', '64', '65', '67', '69', '99', '98', '12', '15', '19', '89', '48', '46', '44', '42', '43', '1', '9', '76', '74', '70', '78'] #print 'Conductivity network z-score: ', self.calcZScore(cnet) #print cnet, len(cnet) print "...done" except Exception, detail: print 'An exception occurred in showZScores!' print detail self.et_messagebox.withdraw() ############################################################### class InterproteinPairETRanks: def __init__(self): self.dataloaded=False self.maxpairs=200 def dataLoaded(self): return self.dataloaded def readData(self,datapath): self.network={} #(resnum1,resnum2) self.coverages={} self.dataloaded=False FILE=open(datapath,'r') numpairs=0 try: for line in FILE: if line.find('%')>-1: continue if len(line.rstrip())>=50: ## resnum1=line[36:40].strip() ## resnum2=line[50:54].strip() ## ETpair=float(line[18:29].strip()) resnum1=line[20:25].strip() #Using new file format of Angela (08/03/11) resnum2=line[30:35].strip() ETpair=float(line[40:52].strip()) cvg=float(line[52:64].strip()) self.network[(resnum1,resnum2)]=ETpair self.coverages[(resnum1,resnum2)]=cvg print resnum1, resnum2, ETpair, cvg numpairs+=1 if numpairs==self.maxpairs: break finally: FILE.close() if len(self.network)>0: ## for respair1, value1 in self.network.items(): ## for respair2, value2 in self.network.items(): ## if value1>=value2: ## self.coverages[respair1]+=1 ## self.coverages[respair1]=self.coverages[respair1]*100.0/numpairs self.dataloaded=True class InterproteinPairRankControlGroup: def __init__(self, page, groupname='Interprotein ET Pair Ranks Network', defaultstructurename1='(pdb)', defaultstructurename2='(pdb)', defaultrankspath='.ranks', etcolor1='red', noetcolor1='wheat', etcolor2='blue', noetcolor2='palecyan', defaultetoption=2, defaultslidercoverage=0.05): self.etcolor1=etcolor1 self.noetcolor1=noetcolor1 self.etcolor2=etcolor2 self.noetcolor2=noetcolor2 group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) #Field for entering name of structure or model self.structure1 = Pmw.EntryField(group.interior(), labelpos='w', label_text='structure to use (chain 1): ', value=defaultstructurename1, ) self.structure2 = Pmw.EntryField(group.interior(), labelpos='w', label_text='structure to use (chain 2): ', value=defaultstructurename2, ) def quickFileValidation(s): if s == '': return Pmw.PARTIAL elif os.path.isfile(s): return Pmw.OK elif os.path.exists(s): return Pmw.PARTIAL else: return Pmw.PARTIAL #Button for assigning ranks to structure self.map_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.map_buttonbox.add('Map pair ranks to structure',command=self.mapRanks) #Field for entering ranks file self.ranksfile = Pmw.EntryField(group.interior(), labelpos='w', label_pyclass = FileDialogButtonClassFactory.get(self.setRanksFileLocation,'*'), validate = {'validator':quickFileValidation,}, value = defaultrankspath, label_text = 'pair ranks file path:') #Tkinter Slider Tkinterfor changing ET residue coverage. #TODO: Use a Pmw implementation? self.slider = Scale(group.interior(), #from_=self.min, to=self.max, from_=0, to=1, showvalue=1, length=200, orient=HORIZONTAL, resolution=0.001, tickinterval=0, #repeatinterval=500, #Dunno what repeatinterval is for... repeatdelay=500 ) self.slider.set(defaultslidercoverage) #self.slider.grid() self.slider.bind("", self.slider_button_release) #self.slider.bind("", self.slider_button_release) #Field for displaying ET coverage self.frame1=Tkinter.Frame(group.interior()) self.percentcoverage = Pmw.EntryField(self.frame1, #group.interior(), labelpos='w', label_text='Percent coverage: ', value='', ) self.rankvalue = Pmw.EntryField(self.frame1, #group.interior(), labelpos='w', label_text='Rank: ', value='', ) self.percentcoverage.grid(column=0,row=0) self.rankvalue.grid(column=1,row=0) self.frame2=Tkinter.Frame(group.interior()) self.et_options_tuple = ('Colors only('+self.etcolor1+','+self.etcolor2+')', 'as Spheres', 'as Spheres (C-alpha only)', 'Prismatic (Gobstopper)') #TODO Prismatic self.show_et_options = Pmw.OptionMenu(self.frame2, #group.interior(), labelpos = 'w', label_text = 'Show ET residues', items = self.et_options_tuple, initialitem = self.et_options_tuple[defaultetoption], command=self.slider_button_release ) ## self.show_et_var=IntVar() ## self.show_et_var.set(0) ## self.show_et_checkbutton = Checkbutton(group.interior(), ## text = "Show ET residues (as spheres)", ## variable = self.show_et_var) self.pair_et_var=IntVar() self.pair_et_var.set(0) self.pair_et_checkbutton = Checkbutton(self.frame2, #group.interior(), text = 'Show pair (CA) distances', variable = self.pair_et_var) self.show_et_options.grid(column=0,row=0) self.pair_et_checkbutton.grid(column=1,row=0) for entry in (self.structure1, self.structure2, self.ranksfile, self.map_buttonbox, self.slider, self.frame1, self.frame2): entry.pack(fill='x',padx=4,pady=1) # vertical self.dataObj=InterproteinPairETRanks() self.ranksStructureOK=False def mapRanks(self): structurename1=self.structure1.getvalue().strip() self.ranksStructureOK=False if len(structurename1)<1: print 'Provide structure name!' return try: model1=cmd.get_model(structurename1) except Exception: print "Structure \'%s\' does not exist!" % structurename1 return structurename2=self.structure2.getvalue().strip() #self.ranksStructureOK=False if len(structurename2)<1: print 'Provide structure name!' return try: model2=cmd.get_model(structurename2) except Exception: print "Structure \'%s\' does not exist!" % structurename2 return rankspath=self.ranksfile.getvalue().strip() if len(rankspath)<1: print 'Provide path to pair ranks file!' return self.dataObj.readData(rankspath) if self.dataObj.dataLoaded(): print "Pair ranks file \'%s\' loaded" % rankspath else: print "Error loading pair ranks file \'%s\'!" % rankspath return #Check that the residue numbers in the model #and in the ranks file are identical ## resnumDict={} ## for i in range(len(model.atom)): ## resnumDict[model.atom[i].resi]=1 ## if len(resnumDict)<1: ## print 'Structure \'%s\' has no residues!' % structurename ## return ## if len(resnumDict)!=self.ranksObj.getSize(): ## print "Residue numbers in \'%s\' and \'%s\' are not the same!" % (structurename, rankspath) ## return ## for i in range(self.ranksObj.getSize()): ## try: ## r=resnumDict[self.ranksObj.getResnum(i)] ## except KeyError: ## print "Residue numbers in \'%s\' and \'%s\' do not match!" % (structurename, rankspath) ## return self.structurename1=structurename1 self.structurename2=structurename2 self.ranksStructureOK=True ## print 'Residue numbers checked with structure \'%s\'' % structurename self.slider_button_release(None) def slider_button_release(self, event): if self.ranksStructureOK: maxcov=0 maxrank=0 slideval=self.slider.get() if self.show_et_options.getvalue()==self.et_options_tuple[2]: cmd.hide('spheres',self.structurename1) #Need to hide spheres in case non-CA atoms are displayed cmd.hide('spheres',self.structurename2) #Also need to hide spheres first because a residue may appear in more than one pair cmd.color(self.noetcolor1,'%s' % (self.structurename1)) cmd.color(self.noetcolor2,'%s' % (self.structurename2)) for respair, rank in self.dataObj.network.items(): cov=self.dataObj.coverages[respair] if slideval>=cov: if cov>maxcov: maxcov=cov maxrank=rank cmd.color(self.etcolor1,'%s and resi %s' % (self.structurename1,respair[0])) cmd.show('spheres','%s and resi %s and name CA' % (self.structurename1,respair[0])) cmd.color(self.etcolor2,'%s and resi %s' % (self.structurename2,respair[1])) cmd.show('spheres','%s and resi %s and name CA' % (self.structurename2,respair[1])) elif self.show_et_options.getvalue()==self.et_options_tuple[1]: cmd.hide('spheres','%s' % (self.structurename1)) cmd.hide('spheres','%s' % (self.structurename2)) cmd.color(self.noetcolor1,'%s' % (self.structurename1)) cmd.color(self.noetcolor2,'%s' % (self.structurename2)) for respair, rank in self.dataObj.network.items(): cov=self.dataObj.coverages[respair] if slideval>=cov: if cov>maxcov: maxcov=cov maxrank=rank cmd.color(self.etcolor1,'%s and resi %s' % (self.structurename1,respair[0])) cmd.show('spheres','%s and resi %s' % (self.structurename1,respair[0])) cmd.color(self.etcolor2,'%s and resi %s' % (self.structurename2,respair[1])) cmd.show('spheres','%s and resi %s' % (self.structurename2,respair[1])) ## elif self.show_et_options.getvalue()==self.et_options_tuple[3]: #Do Prismatic ## for i in range(self.ranksObj.getSize()): ## (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) ## if slideval>=cov: ## if cov>maxcov: ## maxcov=cov ## maxrank=rank ## cmd.color('_et_prism_color%d'%(int(cov-0.000001)),'%s and resi %s' % (self.structurename,resnum)) ## else: ## cmd.color('white','%s and resi %s' % (self.structurename,resnum)) ## else: ## #It turns out that calling cmd.color or cmd.select with a list of residues, e.g. 'resi 1+2+...', can crash pymol ## #if the list is too big (>300) ## for i in range(self.ranksObj.getSize()): ## (resnum,cov,rank)=self.ranksObj.getResnumCoverageRankTuple(i) ## if slideval>=cov: ## if cov>maxcov: ## maxcov=cov ## maxrank=rank ## cmd.color(self.etcolor,'%s and resi %s' % (self.structurename,resnum)) ## else: ## cmd.color(self.noetcolor,'%s and resi %s' % (self.structurename,resnum)) #Draw lines between residues if self.pair_et_var.get()==1: pair_distance_name='et_pair_%s_%s_PyETV'%(self.structurename1,self.structurename2) cmd.delete(pair_distance_name) for respair, rank in self.dataObj.network.items(): cov=self.dataObj.coverages[respair] if slideval>=cov: cmd.distance(pair_distance_name,'%s and resi %s and name CA' % (self.structurename1,respair[0]), '%s and resi %s and name CA' %(self.structurename2,respair[1])) self.percentcoverage.setvalue(maxcov) self.rankvalue.setvalue(maxrank) def setRanksFileLocation(self,value): self.ranksfile.setvalue(value) ####################################################################### #Take the minimum pair rank coverage as the score of a residue #This class is patterned after ConductivityNetwork. class PairETRanks: def __init__(self): self.dataloaded=False def dataLoaded(self): return self.dataloaded def buildCluster(self,seed,neighbors,pcov): remain=neighbors[:] tmpcluster=[seed] for r in neighbors: for t in tmpcluster: try: L=self.network[(r,t)] if L<=pcov: tmpcluster.append(r) remain.remove(r) break except KeyError: pass try: L=self.network[(t,r)] if L<=pcov: tmpcluster.append(r) remain.remove(r) break except KeyError: pass return tmpcluster, remain def clusters(self,pcov): resnumlist=[] for resnum, pcov_ in self.resnumsMaxL.items(): if pcov_<=pcov: resnumlist.append(resnum) if len(resnumlist)==0: return None clusterlist=[] remain=resnumlist while len(remain)>0: seed=remain[0] tmpcluster,remain=self.buildCluster(seed,remain[1:],pcov) clusterlist.append(tmpcluster) return clusterlist def readData(self,datapath): self.network={} #(resnum1,resnum2): L value (resnum1 (maps to) minimum pair coverage value self.dataloaded=False FILE=open(datapath,'r') try: for line in FILE: if line.find('%')>-1: continue if len(line.rstrip())>=50: ## resnum1=line[5:10].strip() ## resnum2=line[15:20].strip() ## ETpair=float(line[25:37].strip()) ## L=float(line[37:49].strip()) #Angela computed coverage #### self.network[(resnum1,resnum2)]=ETpair ## self.network[(resnum1,resnum2)]=L resnum1=line[19:25].strip() resnum2=line[33:39].strip() L=float(line[5:19].strip()) #cvg(ETP/Ave) self.network[(resnum1,resnum2)]=L try: tmpL=self.resnumsMaxL[resnum1] if tmpL>L: self.resnumsMaxL[resnum1]=L except KeyError: self.resnumsMaxL[resnum1]=L try: tmpL=self.resnumsMaxL[resnum2] if tmpL>L: self.resnumsMaxL[resnum2]=L except KeyError: self.resnumsMaxL[resnum2]=L finally: FILE.close() if len(self.network)>0: self.dataloaded=True #This control group preceded InterproteinPairRankControlGroup class PairETControlGroup: def __init__(self, page, groupname='Pair ET Ranks Network', defaultstructurename='(pdb)', defaultrankspath='.ranks', etcolor='red', noetcolor='white'): self.etcolor=etcolor self.noetcolor=noetcolor group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) #Field for entering name of structure or model self.structure = Pmw.EntryField(group.interior(), labelpos='w', label_text='structure to use: ', value=defaultstructurename, ) def quickFileValidation(s): if s == '': return Pmw.PARTIAL elif os.path.isfile(s): return Pmw.OK elif os.path.exists(s): return Pmw.PARTIAL else: return Pmw.PARTIAL #Button for assigning ranks to structure self.map_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.map_buttonbox.add('Map pair ranks to structure',command=self.mapRanks) #Field for entering ranks file self.ranksfile = Pmw.EntryField(group.interior(), labelpos='w', label_pyclass = FileDialogButtonClassFactory.get(self.setRanksFileLocation,'*.dat'), validate = {'validator':quickFileValidation,}, value = defaultrankspath, label_text = 'pair ranks file path:') #Tkinter Slider Tkinterfor changing ET residue coverage. #TODO: Use a Pmw implementation? self.slider = Scale(group.interior(), #from_=self.min, to=self.max, from_=0, to=2, showvalue=1, length=200, orient=HORIZONTAL, resolution=0.01, tickinterval=0, #repeatinterval=500, #Dunno what repeatinterval is for... repeatdelay=500 ) self.slider.set(0.01) #self.slider.grid() self.slider.bind("", self.slider_button_release) #self.slider.bind("", self.slider_button_release) #Field for displaying ET coverage ## self.percentcoverage = Pmw.EntryField(group.interior(), ## labelpos='w', ## label_text='Percent coverage: ', ## value='', ## ) self.rankvalue = Pmw.EntryField(group.interior(), labelpos='w', label_text='pair percent coverage: ', value='', ) self.et_options_tuple = ('Colors only('+self.etcolor+')', 'as Spheres', 'as Spheres (C-alpha only)', 'cvg(ETP/Ave) clusters') self.show_et_options = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'Show ET residues', items = self.et_options_tuple, initialitem = self.et_options_tuple[0], command=self.slider_button_release ) ## self.show_et_var=IntVar() ## self.show_et_var.set(0) ## self.show_et_checkbutton = Checkbutton(group.interior(), ## text = "Show conductivity network residues (as spheres)", ## variable = self.show_et_var) for entry in (self.structure, self.ranksfile, self.map_buttonbox, self.slider, ## self.percentcoverage, self.rankvalue, #self.show_et_checkbutton self.show_et_options): entry.pack(fill='x',padx=4,pady=1) # vertical self.dataObj=PairETRanks() self.ranksStructureOK=False def mapRanks(self): structurename=self.structure.getvalue().strip() self.ranksStructureOK=False if len(structurename)<1: print 'Provide structure name!' return try: model=cmd.get_model(structurename) except Exception: print "Structure \'%s\' does not exist!" % structurename return rankspath=self.ranksfile.getvalue().strip() if len(rankspath)<1: print 'Provide path to pair ranks file!' return self.dataObj.readData(rankspath) if self.dataObj.dataLoaded(): print "Pair ranks file \'%s\' loaded" % rankspath else: print "Error loading pair ranks file \'%s\'!" % rankspath return #Check that the residue numbers in the model #and in the ranks file are identical ## resnumDict={} ## for i in range(len(model.atom)): ## resnumDict[model.atom[i].resi]=1 ## if len(resnumDict)<1: ## print 'Structure \'%s\' has no residues!' % structurename ## return ## if len(resnumDict)!=self.ranksObj.getSize(): ## print "Residue numbers in \'%s\' and \'%s\' are not the same!" % (structurename, rankspath) ## return ## for i in range(self.ranksObj.getSize()): ## try: ## r=resnumDict[self.ranksObj.getResnum(i)] ## except KeyError: ## print "Residue numbers in \'%s\' and \'%s\' do not match!" % (structurename, rankspath) ## return self.structurename=structurename self.ranksStructureOK=True ## print 'Residue numbers checked with structure \'%s\'' % structurename self.slider_button_release(None) def slider_button_release(self, event): if self.ranksStructureOK: #reslist=[] maxcov=0 slideval=self.slider.get() if self.show_et_options.getvalue()==self.et_options_tuple[3]: # clusters=self.dataObj.clusters(slideval) if clusters: print clusters print "Number of cvg(ETP/Ave) clusters", len(clusters) cmd.hide('spheres',self.structurename) #Get largest cluster cluster1=[] size1=0 for clust in clusters: if len(clust)>size1: size1=len(clust) cluster1=clust if len(cluster1)>0: clusters.remove(cluster1) #Get second largest cluster cluster2=[] size2=0 for clust in clusters: if len(clust)>size2: size2=len(clust) cluster2=clust if len(cluster2)>0: clusters.remove(cluster2) #Get third largest cluster cluster3=[] size3=0 for clust in clusters: if len(clust)>size3: size3=len(clust) cluster3=clust cmd.hide('spheres',self.structurename) cmd.color('white',self.structurename) for r in cluster1: cmd.color('red','%s and resi %s' % (self.structurename,r)) cmd.show('spheres','%s and resi %s' % (self.structurename,r)) for r in cluster2: cmd.color('green','%s and resi %s' % (self.structurename,r)) cmd.show('spheres','%s and resi %s' % (self.structurename,r)) for r in cluster3: cmd.color('blue','%s and resi %s' % (self.structurename,r)) cmd.show('spheres','%s and resi %s' % (self.structurename,r)) else: cmd.hide('spheres',self.structurename) cmd.color('white',self.structurename) elif self.show_et_options.getvalue()==self.et_options_tuple[2]: cmd.hide('spheres',self.structurename) for resnum, cov in self.dataObj.resnumsMaxL.items(): if slideval>=cov: #reslist.append(resnum) if cov>maxcov: maxcov=cov cmd.color(self.etcolor,'%s and resi %s' % (self.structurename,resnum)) cmd.show('spheres','%s and resi %s and name CA' % (self.structurename,resnum)) else: #TODO: Color only the spheres? cmd.color(self.noetcolor,'%s and resi %s' % (self.structurename,resnum)) cmd.hide('spheres','%s and resi %s' % (self.structurename,resnum)) #if self.show_et_var.get()==1: elif self.show_et_options.getvalue()==self.et_options_tuple[1]: for resnum, cov in self.dataObj.resnumsMaxL.items(): if slideval>=cov: #reslist.append(resnum) if cov>maxcov: maxcov=cov cmd.color(self.etcolor,'%s and resi %s' % (self.structurename,resnum)) cmd.show('spheres','%s and resi %s' % (self.structurename,resnum)) else: #TODO: Color only the spheres? cmd.color(self.noetcolor,'%s and resi %s' % (self.structurename,resnum)) cmd.hide('spheres','%s and resi %s' % (self.structurename,resnum)) else: #print self.dataObj.resnumsMaxL for resnum, cov in self.dataObj.resnumsMaxL.items(): if slideval>=cov: #reslist.append(resnum) if cov>maxcov: maxcov=cov cmd.color(self.etcolor,'%s and resi %s' % (self.structurename,resnum)) else: cmd.color(self.noetcolor,'%s and resi %s' % (self.structurename,resnum)) ## self.percentcoverage.setvalue(maxcov) self.rankvalue.setvalue(maxcov) #print "Residues with L>%f:" % (slideval) #print reslist def setRanksFileLocation(self,value): self.ranksfile.setvalue(value) ################################################################### class ConductivityNetwork: def __init__(self): self.dataloaded=False def dataLoaded(self): return self.dataloaded def readData(self,datapath): self.network={} #(resnum1,resnum2): L value (resnum1=27: resnum1=line[0:5].strip() resnum2=line[5:11].strip() #Conductivity values between residues #next to each other in sequence are usually #large, so ignore these. if int(resnum2)==int(resnum1)+1 or \ int(resnum1)==int(resnum2)+1: continue L=float(line[11:27].strip()) self.network[(resnum1,resnum2)]=L try: tmpL=self.resnumsMaxL[resnum1] if tmpL0: self.dataloaded=True #A residue is part of the conductivity network if one of its #links passes the conductivity threshold #(rankspath -> datapath) class ConductivityViewerGroup: def __init__(self, page, groupname='Conductivity Network', defaultstructurename='(pdb)', defaultrankspath='.dat', etcolor='red', noetcolor='white'): self.etcolor=etcolor self.noetcolor=noetcolor group = Pmw.Group(page,tag_text=groupname) group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) #Field for entering name of structure or model self.structure = Pmw.EntryField(group.interior(), labelpos='w', label_text='structure to use: ', value=defaultstructurename, ) def quickFileValidation(s): if s == '': return Pmw.PARTIAL elif os.path.isfile(s): return Pmw.OK elif os.path.exists(s): return Pmw.PARTIAL else: return Pmw.PARTIAL #Button for assigning ranks to structure self.map_buttonbox = Pmw.ButtonBox(group.interior(), padx=0) self.map_buttonbox.add('Map conductivity to structure',command=self.mapRanks) #Field for entering ranks file self.ranksfile = Pmw.EntryField(group.interior(), labelpos='w', label_pyclass = FileDialogButtonClassFactory.get(self.setRanksFileLocation,'*.dat'), validate = {'validator':quickFileValidation,}, value = defaultrankspath, label_text = 'Conductivity data file path:') #Tkinter Slider Tkinterfor changing ET residue coverage. #TODO: Use a Pmw implementation? self.slider = Scale(group.interior(), #from_=self.min, to=self.max, from_=0, to=2, showvalue=1, length=200, orient=HORIZONTAL, resolution=0.01, tickinterval=0, #repeatinterval=500, #Dunno what repeatinterval is for... repeatdelay=500 ) self.slider.set(0.01) #self.slider.grid() self.slider.bind("", self.slider_button_release) #self.slider.bind("", self.slider_button_release) #Field for displaying ET coverage ## self.percentcoverage = Pmw.EntryField(group.interior(), ## labelpos='w', ## label_text='Percent coverage: ', ## value='', ## ) self.rankvalue = Pmw.EntryField(group.interior(), labelpos='w', label_text='Minimum conductivity: ', value='', ) self.et_options_tuple = ('Colors only('+self.etcolor+')', 'as Spheres', 'as Spheres (C-alpha only)') self.show_et_options = Pmw.OptionMenu(group.interior(), labelpos = 'w', label_text = 'Show network residues', items = self.et_options_tuple, initialitem = self.et_options_tuple[0], command=self.slider_button_release ) ## self.show_et_var=IntVar() ## self.show_et_var.set(0) ## self.show_et_checkbutton = Checkbutton(group.interior(), ## text = "Show conductivity network residues (as spheres)", ## variable = self.show_et_var) for entry in (self.structure, self.ranksfile, self.map_buttonbox, self.slider, ## self.percentcoverage, self.rankvalue, #self.show_et_checkbutton self.show_et_options): entry.pack(fill='x',padx=4,pady=1) # vertical self.dataObj=ConductivityNetwork() self.ranksStructureOK=False def mapRanks(self): structurename=self.structure.getvalue().strip() self.ranksStructureOK=False if len(structurename)<1: print 'Provide structure name!' return try: model=cmd.get_model(structurename) except Exception: print "Structure \'%s\' does not exist!" % structurename return rankspath=self.ranksfile.getvalue().strip() if len(rankspath)<1: print 'Provide path to conductivity data file!' return self.dataObj.readData(rankspath) if self.dataObj.dataLoaded(): print "Conductivity data file \'%s\' loaded" % rankspath else: print "Error loading conductivity data file \'%s\'!" % rankspath return #Check that the residue numbers in the model #and in the ranks file are identical ## resnumDict={} ## for i in range(len(model.atom)): ## resnumDict[model.atom[i].resi]=1 ## if len(resnumDict)<1: ## print 'Structure \'%s\' has no residues!' % structurename ## return ## if len(resnumDict)!=self.ranksObj.getSize(): ## print "Residue numbers in \'%s\' and \'%s\' are not the same!" % (structurename, rankspath) ## return ## for i in range(self.ranksObj.getSize()): ## try: ## r=resnumDict[self.ranksObj.getResnum(i)] ## except KeyError: ## print "Residue numbers in \'%s\' and \'%s\' do not match!" % (structurename, rankspath) ## return self.structurename=structurename self.ranksStructureOK=True ## print 'Residue numbers checked with structure \'%s\'' % structurename self.slider_button_release(None) def slider_button_release(self, event): if self.ranksStructureOK: reslist=[] ## maxcov=0 minL=100 slideval=self.slider.get() if self.show_et_options.getvalue()==self.et_options_tuple[2]: cmd.hide('spheres',self.structurename) for resnum, L in self.dataObj.resnumsMaxL.items(): if slideval%f:" % (slideval) print reslist def setRanksFileLocation(self,value): self.ranksfile.setvalue(value) ################################################################### class ETTools: def __init__(self,app): showmode=1 #0 - simple interface, for public. 1 - show (everything) more. if not cmd.__dict__.has_key('_et_tools_pyetv_opened'): cmd._et_tools_pyetv_opened=False #Value tells the plugin if it has been opened before numPrismColors=100 self.createPrismColors(numPrismColors) #100 is hardcoded into the Prismatic options above self.createDiffETColors(10) #Check if these members have been defined previously (e.g. by a .pml file) #These are used in the first Difference ET control group to load #structures and ranks files from a URL. if not cmd.__dict__.has_key('_et_tools_structurename'): cmd._et_tools_structurename='(pdb)' if not cmd.__dict__.has_key('_et_tools_structureurl'): cmd._et_tools_structureurl='' if not cmd.__dict__.has_key('_et_tools_rankspath1'): cmd._et_tools_rankspath1='.ranks' if not cmd.__dict__.has_key('_et_tools_rankspath2'): cmd._et_tools_rankspath2='.ranks' if not cmd.__dict__.has_key('_et_tools_ranksurl1'): cmd._et_tools_ranksurl1='' if not cmd.__dict__.has_key('_et_tools_ranksurl2'): cmd._et_tools_ranksurl2='' #New options if not cmd.__dict__.has_key('_et_tools_selectpage'): #This flag tells the plugin to select a particular page cmd._et_tools_selectpage='ET' if not cmd.__dict__.has_key('_et_tools_structurename2'): cmd._et_tools_structurename2='(pdb)' if len(cmd._et_tools_ranksurl1.strip())>0 and \ len(cmd._et_tools_ranksurl2.strip())>0: #import urllib tmprankspath1 = urllib.urlretrieve(cmd._et_tools_ranksurl1)[0] tmprankspath2 = urllib.urlretrieve(cmd._et_tools_ranksurl2)[0] if os.path.getsize(tmprankspath1)>0 and \ os.path.getsize(tmprankspath2)>0: cmd._et_tools_rankspath1=tmprankspath1 cmd._et_tools_rankspath2=tmprankspath2 cmd._et_tools_ranksurl1='' cmd._et_tools_ranksurl2='' parent = app.root self.parent = parent self.dialog3 = Pmw.Dialog(parent, buttons = ('Close',), title = 'PyETV: Processing, please wait...', command = self.close3) self.dialog3.withdraw() msg = Tkinter.Label(self.dialog3.interior(), text = ' PyETV processing your request, please wait... Done ', #background = 'black', #foreground = 'white', #pady = 20, ) msg.pack() #Create another window for displaying gobstopper/prismatic color ramp as legend self.dialog2 = Pmw.Dialog(parent, buttons = ('Close',), title = 'PyETV Prismatic/Gobstopper legend', command = self.close2) self.dialog2.withdraw() ramplength=400 rampthick=40 canvas=Tkinter.Canvas(self.dialog2.interior(), width=ramplength, height=rampthick) canvas.pack() rampstripthick=ramplength/100 for i in range(numPrismColors): canvas.create_rectangle(i*rampstripthick, 0, (i+1)*rampstripthick, rampthick/2, outline='grey', fill=("#%02x%02x%02x" % cmd._et_tools_prism_rgb[i])) canvas.create_text(rampstripthick, 3*rampthick/4, text='Important (low ET percent coverage)', anchor='w') canvas.create_text(ramplength-rampstripthick, 3*rampthick/4, text='Unimportant', anchor='e') # Create the main dialog. self.dialog = Pmw.Dialog(parent, buttons = ('Exit PyETV',), title = 'PyETV PyMOL Evolutionary Trace Viewer 1.1', command = self.close) self.dialog.withdraw() Pmw.setbusycursorattributes(self.dialog.component('hull')) self.notebook = Pmw.NoteBook(self.dialog.interior()) #self.notebook.pack(fill='both',expand=1,padx=10,pady=10) ##################################################################### #Create as many ETControlGroup's as unique chains in a pdb structure #e.g. 1gotA, 1gotB, 1gotG ##################################################################### # #First option: #Expect a list of structurenames # cmd._et_tools_structurenamelist #and URLs of ranks files # cmd._et_tools_ranksurllist ## if cmd.__dict__.has_key('_et_tools_structurenamelist'): ## import urllib ## self.tracelist=[] ## numstructures=len(cmd._et_tools_structurenamelist) ## for i in range(numstructures): ## structurename=cmd._et_tools_structurenamelist[i] ## page=self.notebook.add(structurename) ## try: ## rankspath=urllib.urlretrieve(cmd._et_tools_ranksurllist[i])[0] ## except KeyError: ## rankspath='' ## self.tracelist.append(ETControlGroup(page, ## groupname=structurename, ## defaultstructurename=structurename, ## defaultrankspath=rankspath, ## etcolor='red', ## noetcolor='salmon')) ## self.tracelist[-1].mapRanks() #Second option: #Expect a python list of structure names # cmd._et_tools_structurenamelist #and the URL of the directory containing the .zip of the trace results # cmd._et_tools_zipurl #Third option: #Expect a python list of structure names # cmd._et_tools_structurenamelist #and a list of URL's of etvx files # cmd._et_tools_etvxurllist #the ranks section will be extracted from the etvx file #We want the structure to show up immediately #after launching PyMOL. This can't be done using plugins. #The pdb structures may be loaded from the etvx files, or by #loading the full structure and selecting and creating objects #representing the required chains # if cmd.__dict__.has_key('_et_tools_structurenamelist'): #import urllib self.tracelist=[] numstructures=len(cmd._et_tools_structurenamelist) #Create a control group that controls all sliders if numstructures>1: first_structure=cmd._et_tools_structurenamelist[0] last_structure=cmd._et_tools_structurenamelist[-1] if type(first_structure)==tuple: firsttabname=first_structure[0]+first_structure[1] #structure + chain indicator else: firsttabname=first_structure if type(last_structure)==tuple: lasttabname=last_structure[0]+last_structure[1] #structure + chain indicator else: lasttabname=last_structure #Sometimes, we get a name that ends with an '_', e.g. '1tem_'. #Underscores are not allowed in tab names for a notebook, so we have to get rid of it. mastergroupname='Control sliders from %s to %s' % (firsttabname.replace('_',' '),lasttabname.replace('_',' ')) page=self.notebook.add('Complex') self.mastercontrol=ETMasterControlGroup(page, groupname=mastergroupname, slavelist=self.tracelist, defaultetoption=3, defaultslidercoverage=100) cmd._et_tools_selectpage='Complex' for i in range(numstructures): #This could be either a name of a PyMOL object ('1finA'), or a tuple of a PyMOL object and a chain indicator (('1fin','A')) structure_chain=cmd._et_tools_structurenamelist[i] if type(structure_chain)==tuple: structurenameonly=structure_chain[0] structurechain=structure_chain[1] tabname=structurenameonly+structurechain else: structurenameonly=structure_chain #Assume a string structurechain='' tabname=structurenameonly if numstructures>1: page=self.mastercontrol.notebook.add(tabname.replace('_',' ')) else: page=self.notebook.add(tabname.replace('_',' ')) rankspath='' try: filepath=cmd._et_tools_etvxurllist[i].strip() #Consider loading from URL or local file if filepath.find('http')==0: #Check if file is .etvx or .ranks if filepath[-5:]=='.etvx': tmpetvxpath=urllib.urlretrieve(filepath)[0] if os.path.getsize(tmpetvxpath)>0: rankspath=self.extractRanks(tmpetvxpath,tabname) else: #Assume file is in .ranks format tmprankspath=urllib.urlretrieve(filepath)[0] if os.path.getsize(tmprankspath)>0: rankspath=os.path.dirname(tmprankspath)+os.sep+tabname+'.ranks' try: os.rename(tmprankspath,rankspath) except OSError: #rankspath exists, try removing it first os.remove(rankspath) os.rename(tmprankspath,rankspath) else: #Check if file is .etvx or .ranks if filepath[-5:]=='.etvx': rankspath=self.extractRanks(filepath,tabname) else: #Assume file is in .ranks format rankspath=filepath except KeyError: pass if cmd.__dict__.has_key('_et_tools_colors'): try: (etcolor_,noetcolor_)=cmd._et_tools_colors[cmd._et_tools_structurenamelist[i]] except KeyError: etcolor_='red' noetcolor_='salmon' else: etcolor_='red' noetcolor_='salmon' #cmd.load(pdbpath,object=structurename) self.tracelist.append(ETControlGroup(page, groupname=tabname, defaultstructurename=structurenameonly, defaultchain=structurechain, defaultrankspath=rankspath, defaultetoption=3, defaultslidercoverage=100, etcolor=etcolor_, noetcolor=noetcolor_, et_loader_on=False, et_colorramp=self.dialog2, et_messagebox=self.dialog3 )) self.tracelist[-1].mapRanks() #TODO: Next time the plugin is opened, should the etvx/ranks files be downloaded again? if numstructures>1: page=self.mastercontrol.notebook.add('Zcoupling') self.couplingCalculatorComplex=CouplingGroup2(page, groupname='Compute ET coupling z-score', tracelist=self.tracelist, et_messagebox=self.dialog3 ) self.InterfaceGroupComplex=InterfaceControlGroup2(page, groupname='Mark interface between structures 1 and 2', tracelist=self.tracelist, defaultinterfaceoption1=1, defaultinterfaceoption2=1, et_messagebox=self.dialog3 ) self.mastercontrol.notebook.pack(fill='both',padx=4,pady=1) # Set up a page (aka tab or folder) page = self.notebook.add('ET1') self.traceA=ETControlGroup(page, groupname='View Evolutionary Trace 1', defaultstructurename=cmd._et_tools_structurename, defaultrankspath=cmd._et_tools_rankspath1, etcolor='red', noetcolor='salmon', #interface_on=False et_colorramp=self.dialog2, et_messagebox=self.dialog3 ) #self.traceA._group.grid(column=0,row=0) if 1:#showmode==1: page = self.notebook.add('ET2') self.traceB=ETControlGroup(page, groupname='View Evolutionary Trace 2', defaultstructurename=cmd._et_tools_structurename2, defaultrankspath=cmd._et_tools_rankspath2, etcolor='blue', noetcolor='lightblue', #interface_on=False, et_colorramp=self.dialog2, et_messagebox=self.dialog3 ) #self.traceB._group.grid(column=1,row=0) if 1: #showmode==1: page = self.notebook.add('Zcoupling') self.couplingCalculator1=CouplingGroup(page, groupname='Compute ET coupling z-score between Trace 1 and Trace 2', trace1=self.traceA, trace2=self.traceB, et_messagebox=self.dialog3 ) self.InterfaceGroup=InterfaceControlGroup(page, groupname='Mark interface between structures 1 and 2', defaultinterfaceoption1=0, defaultinterfaceoption2=0, et_messagebox=self.dialog3 ) page = self.notebook.add('Assembly') self.AssemblyControl=ETAssemblyControlGroup(page, groupname='Load Biological Unit from PISA', defaultetoption=3, defaultslidercoverage=100, et_colorramp=self.dialog2, et_messagebox=self.dialog3 ) ## page = self.notebook.add('More ET') ## #Make as many of these as you like ## self.traceC=ETControlGroup(page, ## groupname='Trace C', ## #defaultstructurename='query_1finA', ## #defaultrankspath='ET_1finA.ranks', ## etcolor='magenta', ## noetcolor='pink') ## self.traceD=ETControlGroup(page, ## groupname='Trace D', ## #defaultstructurename='query_1finB', ## #defaultrankspath='ET_1finB.ranks', ## etcolor='green', ## noetcolor='palegreen') if showmode==1: #Make as many of these as you like page = self.notebook.add('Diff ET') self.difftrace1=DiffETControlGroup(page, groupname='Difference trace', defaultstructurename=cmd._et_tools_structurename, defaultrankspath1=cmd._et_tools_rankspath1, defaultrankspath2=cmd._et_tools_rankspath2, et_messagebox=self.dialog3 ) ## page = self.notebook.add('Diff ET 2') ## #Make as many of these as you like ## self.difftrace2=DiffETControlGroup(page, ## groupname='Diff trace', ## ) ## page = self.notebook.add('Conductivity') ## #Make as many of these as you like ## self.network1=ConductivityViewerGroup(page, ## groupname='Conductivity Network 1', ## defaultstructurename='query_2phyA', ## defaultrankspath='pyp-conductivity.dat', ## etcolor='orange', ## noetcolor='white') ## self.network2=ConductivityViewerGroup(page, ## groupname='Conductivity Network 2', ## defaultstructurename='query_2phyA', ## defaultrankspath='2phy_MI.dat', ## etcolor='cyan', ## noetcolor='white') ## page = self.notebook.add('Pair ET') ## #Make as many of these as you like ## self.pairET=PairETControlGroup(page, ## groupname='Pair ET', ## defaultstructurename='query_2phyA', ## defaultrankspath='2phyA.cvg_change', ## etcolor='red', ## noetcolor='white') if showmode==2: page = self.notebook.add('Interprotein ET') #Make as many of these as you like self.interproteintrace=InterproteinPairRankControlGroup(page, groupname='Interprotein ET Pair Network', defaultstructurename1='query_1f6mF', defaultstructurename2='query_1f6mH', defaultrankspath='1f6mFH.pp_rank_sorted') ## defaultstructurename1='query_1finA', ## defaultstructurename2='query_1finB', ## defaultrankspath='1finAB.pp_rank_sorted') page = self.notebook.add('Compute') #Make as many of these as you like self.SCWGroup=SCWGroup(page, groupname='Clustering z-score', #defaultstructurename='query_2phyA' ) page = self.notebook.add('Credits') group = Pmw.Group(page,tag_text='Credits') group.pack(fill = 'both', expand = 1, padx = 10, pady = 5) creditstext=''' PyETV PyMOL Evolutionary Trace Viewer Rhonald Lua Lichtarge Lab, Baylor College of Medicine Houston, Texas Protein interfaces, surfaces and assemblies service PISA at European Bioinformatics Institute (http://www.ebi.ac.uk/msd-srv/prot_int/pistart.html), authored by E. Krissinel and K. Henrick The code for creating a file selection dialog box was taken from apbs_tools.py of M. Lerner. Thank you to W. L. DeLano for PyMOL, and to the developers of apbs_tools.py and remote_pdb_load.py for providing these examples on how to write a PyMOL plugin, and to others who made their python scripts available on the Web. ''' credits = Tkinter.Label(group.interior(), text = creditstext, background = 'black', foreground = 'white', #pady = 20, ) credits.pack(expand = 1, fill = 'both', padx = 4, pady = 4) #Test #cmd.load('query_1finA.pdb') #cmd.load('query_1finB.pdb') #if cmd._et_tools_selectpage=='Diff ET 1': # self.notebook.selectpage('Diff ET 1') #elif cmd._et_tools_selectpage=='ET': # self.notebook.selectpage('ET') if cmd._et_tools_selectpage=='Diff ET 1': #Backward compatibility self.notebook.selectpage('Diff ET') #Sometimes, we get a name that ends with an '_', e.g. '1tem_'. #Underscores are not allowed in tab names for a notebook, so we have to get rid of it. if cmd._et_tools_selectpage.replace('_',' ') in self.notebook.pagenames(): self.notebook.selectpage(cmd._et_tools_selectpage.replace('_',' ')) self.notebook.pack(fill='both',expand=1,padx=10,pady=10) self.notebook.setnaturalsize() self.dialog.show() cmd._et_tools_pyetv_opened=True def close(self, result): if 1: #if result=='Exit ET tools': if __name__ == '__main__': # # dies with traceback, but who cares # self.parent.destroy() else: #self.dialog.deactivate(result) self.dialog.withdraw() #This just hides the window, does not destroy and free resources? self.dialog2.withdraw() self.dialog3.withdraw() def close2(self, result): if 1: if 0: #__name__ == '__main__': # # dies with traceback, but who cares # self.parent.destroy() else: #self.dialog.deactivate(result) self.dialog2.withdraw() #This just hides the window, does not destroy and free resources? def close3(self, result): if 1: if 0: #__name__ == '__main__': # # dies with traceback, but who cares # self.parent.destroy() else: #self.dialog.deactivate(result) self.dialog3.withdraw() #This just hides the window, does not destroy and free resources? def createPrismColors(self,numcolors): if cmd._et_tools_pyetv_opened: return #Do the following only once cmd._et_tools_prism_rgb=[] #hexlist=[] for i in range(numcolors): hsv=(i*0.8/numcolors,1.0,1.0) #David's color scheme #reversegray=False #True or False #if reversegray: # hsv=(0,0,(i+1)*1.0/numcolors) #else: # hsv=(0,0,(numcolors-i)*1.0/numcolors) rgb=colorsys.hsv_to_rgb(hsv[0],hsv[1],hsv[2]) cmd._et_tools_prism_rgb.append((int(255*rgb[0]), int(255*rgb[1]), int(255*rgb[2]))) #For creating a color ramp in Tkinter.Canvas #Make a perl list of prismatic colors in hex #hexlist.append("\"%.2x%.2x%.2x\"" % (int(255*rgb[0]), int(255*rgb[1]), int(255*rgb[2]))) cmd.set_color('_et_prism_color%d'%i,rgb) #print string.join(hexlist,',') def createDiffETColors(self,numcolors): #Make red and blue spectrum of colors for difference ET for i in range(numcolors): hsv=(0.0,(i+1)*1.0/numcolors,1.0) #red rgb=colorsys.hsv_to_rgb(hsv[0],hsv[1],hsv[2]) cmd.set_color('_et_red_color%d'%i,rgb) hsv=(0.6,(i+1)*1.0/numcolors,1.0) #blue(ish) rgb=colorsys.hsv_to_rgb(hsv[0],hsv[1],hsv[2]) cmd.set_color('_et_blue_color%d'%i,rgb) def extractRanks(self,etvxpath,pdb_chain): #Get the ranks section FILE=open(etvxpath,'r') data='' ready=False try: for line in FILE: if line[:5]=='~tree': break if ready: data+=line if line[:9]=='~ET_ranks': ready=True finally: FILE.close() #Write ranks section to file ranksfilename=os.path.dirname(etvxpath)+os.sep+pdb_chain+'.ranks' FILE_RANKS=open(ranksfilename,'w') FILE_RANKS.write(data) FILE_RANKS.close() return ranksfilename # Create demo in root window for testing. if __name__ == '__main__': class App: def my_show(self,*args,**kwargs): pass app = App() app.root = Tk() Pmw.initialise(app.root) app.root.title('Exit button for __main__') widget = ETTools(app) exitButton = Button(app.root, text = 'Exit', command = app.root.destroy) exitButton.pack() app.root.mainloop() #Problem: command line scripts (e.g. pymol xxx.pml) are executed #before this plugin file is fully read. ##def Set_Diff_ET_Input(structurename,rankspath1,rankspath2): ## cmd._et_tools_structurename=structurename ## cmd._et_tools_rankspath1=rankspath1 ## cmd._et_tools_rankspath2=rankspath2 ##def Set_Diff_ET_Input_URL(structurename,ranksurl1,ranksurl2): ## import urllib #Learned this trick from remove_pdb ## rankspath1 = urllib.urlretrieve(ranksurl1)[0] ## rankspath2 = urllib.urlretrieve(ranksurl2)[0] ## cmd._et_tools_structurename=structurename ## cmd._et_tools_rankspath1=rankspath1 ## cmd._et_tools_rankspath2=rankspath2 #cmd.extend('Set_Diff_ET_Input', Set_Diff_ET_Input) #cmd.extend('Set_Diff_ET_Input_URL', Set_Diff_ET_Input_URL)