Package Pmv :: Module superImposeCommands
[hide private]
[frames] | no frames]

Source Code for Module Pmv.superImposeCommands

  1  ############################################################################# 
  2  # 
  3  # Author: Sophie I. COON, William LINDSTROM, Michel F. SANNER 
  4  # 
  5  # Copyright: M. Sanner TSRI 2000 
  6  # 
  7  ############################################################################# 
  8  # 
  9  # $Header: /opt/cvs/python/packages/share1.5/Pmv/superImposeCommands.py,v 1.21 2006/08/17 23:25:17 vareille Exp $ 
 10  # 
 11  # $Id: superImposeCommands.py,v 1.21 2006/08/17 23:25:17 vareille Exp $ 
 12  # 
 13   
 14  import Numeric, os 
 15  import Tkinter, Pmw 
 16   
 17  from Pmv.stringSelectorGUI import StringSelectorGUI 
 18  from Pmv.mvCommand import MVCommand, MVAtomICOM 
 19  from Pmv.guiTools import MoleculeChooser 
 20   
 21  from ViewerFramework.VFCommand import CommandGUI 
 22   
 23  from MolKit.molecule import Molecule, Atom, AtomSet 
 24  from MolKit.protein import Protein, Residue, Chain, ProteinSet, ResidueSet, ChainSet 
 25   
 26  from DejaVu.Spheres import Spheres 
 27  from DejaVu.IndexedPolylines import IndexedPolylines 
 28   
 29  from mglutil.alignmentEditor import * 
 30  from mglutil.gui.InputForm.Tk.gui import InputFormDescr, InputForm 
 31  from mglutil.util.callback import CallBackFunction 
 32  from mglutil.gui.BasicWidgets.Tk.customizedWidgets import ListChooser 
 33  #from mglutil.math import rigidFit 
 34  from mglutil.math.rigidFit import RigidfitBodyAligner 
 35   
 36  from SimpleDialog import SimpleDialog 
 37   
38 -class PmvAlignmentEditor(AlignmentEditor,MVCommand):
39 """ An alignment editor that knows about Pmv 40 """ 41
42 - def __init__(self,alignment=None,vf=None,name=None,**kw):
43 MVCommand.__init__(self) 44 self.vf = vf 45 AlignmentEditor.__init__(self,alignment=alignment,master=vf.GUI.ROOT, 46 name=name) 47 self.addPmvMenu()
48
49 - def addPmvMenu(self):
50 if isinstance(self.mBar, Pmw.ScrolledFrame): 51 PmvButton = Tkinter.Menubutton(self.mBar.interior(), 52 text='Pmv commands', 53 underline=0) 54 else: 55 PmvButton = Tkinter.Menubutton(self.mBar, text='Pmv commands', 56 underline=0) 57 58 self.menuButtons['Pmv commands']=PmvButton 59 PmvButton.pack(side=Tkinter.LEFT, padx='1m') 60 PmvButton.menu = Tkinter.Menu(PmvButton) 61 PmvButton.menu.add_command( 62 label='Get/Assign Molecule Sequence', 63 command = self.getSequence) 64 PmvButton.menu.add_command( 65 label='Set reference sequence', 66 command = self.setRefSequence) 67 PmvButton.menu.add_command( 68 label='Set mobile sequence', 69 command = self.setMobSequence) 70 PmvButton.menu.add_command( 71 label='Calculate Superposition', 72 command = self.getPairsFromAlignment) 73 PmvButton['menu']=PmvButton.menu 74 apply(self.mBar.tk_menuBar, self.menuButtons.values())
75
76 - def setRefSequence(self):
77 molName = MoleculeChooser(self.vf).go().name 78 self.vf.alnEditor.master.lift() 79 if molName not in self.vf.alignment.seqNames: 80 return 81 #recolor the previous reference sequence, if it exists 82 if hasattr(self,'refMolName'): 83 uniqtag = self.refMolName+'_name' 84 item = self.vf.alnEditor.canvas.find_withtag(uniqtag) 85 color = self.vf.alnEditor.colors['default'] 86 self.vf.alnEditor.canvas.itemconfig(item,fill=color) 87 uniqtag = molName+'_name' 88 self.vf.alnEditor.colors['special'][uniqtag]='red' 89 item = self.vf.alnEditor.canvas.find_withtag(uniqtag) 90 self.vf.alnEditor.canvas.itemconfig(item,fill='red') 91 self.refMolName = molName
92
93 - def setMobSequence(self):
94 molName = MoleculeChooser(self.vf).go().name 95 self.vf.alnEditor.master.lift() 96 if molName not in self.vf.alignment.seqNames: 97 return 98 #recolor the previous reference sequence, if it exists 99 if hasattr(self,'mobMolName'): 100 uniqtag = self.mobMolName+'_name' 101 item = self.vf.alnEditor.canvas.find_withtag(uniqtag) 102 color = self.vf.alnEditor.colors['default'] 103 self.vf.alnEditor.canvas.itemconfig(item,fill=color) 104 uniqtag = molName+'_name' 105 self.vf.alnEditor.colors['special'][uniqtag]='green' 106 item = self.vf.alnEditor.canvas.find_withtag(uniqtag) 107 self.vf.alnEditor.canvas.itemconfig(item,fill='green') 108 self.mobMolName = molName
109
110 - def getPairsFromAlignment(self):
111 """ This is where we want to figure out the selection 112 """ 113 refCount=0 114 mobCount=0 115 refResidues = self.vf.expandNodes(self.refMolName)[0].children.children 116 mobResidues = self.vf.expandNodes(self.mobMolName)[0].children.children 117 refNodes = ResidueSet() 118 mobNodes = ResidueSet() 119 #get the item no's for each sequence 120 refItems = self.vf.alnEditor.canvas.find_withtag(self.refMolName) 121 mobItems = self.vf.alnEditor.canvas.find_withtag(self.mobMolName) 122 for x in range(len(refItems)): 123 ref = self.vf.alnEditor.canvas.itemcget(refItems[x],'text') 124 mob = self.vf.alnEditor.canvas.itemcget(mobItems[x],'text') 125 if ref.isalpha(): 126 refRes = refResidues[refCount] 127 refCount=refCount+1 128 if mob.isalpha(): 129 mobRes = mobResidues[mobCount] 130 mobCount=mobCount+1 131 refTags = self.vf.alnEditor.canvas.gettags(refItems[x]) 132 mobTags = self.vf.alnEditor.canvas.gettags(mobItems[x]) 133 if 'selected' in mobTags and 'selected' in refTags: 134 if ref.isalpha() and mob.isalpha(): 135 refNodes.append(refRes) 136 mobNodes.append(mobRes) 137 print len(refNodes),len(mobNodes),refNodes[0],mobNodes[0] 138 #return refNodes,mobNodes 139 apply(self.vf.superimposeAtomsGC.doitWrapper, (refNodes,), {'log':0}) 140 apply(self.vf.superimposeAtomsGC.doitWrapper, (mobNodes,), {'log':0}) 141 self.vf.superimposeAtomsGC.typeVar.set('By Picking')
142
143 - def getSequence(self,mol=None):
144 if not mol: 145 mol = MoleculeChooser(self.vf).go() 146 if not mol: 147 return 148 self.vf.alnEditor.master.lift() 149 #for extracting sequence(s) from molecules 150 chains = mol.children 151 seqList = [] 152 numbers = [] 153 for chain in chains: 154 seqList = seqList+chain.children.type+['-','|','-'] 155 for residue in chain.children: 156 numbers.append(chain.name + residue.type + residue.number) 157 molSequence = Sequence(sequence=seqList,numbers=numbers,name=mol.name) 158 seqName = mol.name 159 if seqName in self.vf.alignment.seqNames: 160 # if sequence with this molecule name is already in the alignment, 161 # only need to update the numbers 162 sequence = self.vf.alignment.sequences[seqName] 163 sequence.applyNumbers(numbers) 164 return 165 self.vf.alignment.addSequence(molSequence) 166 self.vf.alnEditor.redraw()
167
168 - def select(self,items,deselect=0):
169 icomLevel = self.vf.ICOMbar.LevelOption._menubutton.config()['text'][-1] 170 if icomLevel == 'Atom': 171 msg = "The selection level is currently ATOM. Continuing will\nchange it to RESIDUE" 172 d = SimpleDialog(self.vf.GUI.ROOT,text=msg, 173 buttons = ["Abort","Continue"], 174 title = "Warning", 175 default=1) 176 if not d.go(): 177 return 178 AlignmentEditor.select(self,items,deselect) 179 lastSelect = self.lastSelect #just been updated by previous line 180 negate=lastSelect[0] 181 selStrings={} 182 for item in lastSelect[1]: 183 resTag,seqTag,uniqTag = self.canvas.gettags(item)[:3] 184 # if the item is part of a sequence linked to a molecule, 185 # the selection can be applied to Pmv. Since the resTag in this case 186 # is the unique object identifier for the residue, this is easy 187 if seqTag in self.vf.Mols.name: 188 molName = seqTag 189 selectionKey = molName+':'+resTag[:1]+':' 190 resnum = resTag[1:] 191 if selectionKey in selStrings.keys(): 192 selStrings[selectionKey]=selStrings[selectionKey]+','+resnum 193 else: 194 selStrings[selectionKey]=','+resnum 195 for selStr in selStrings.keys(): 196 print selStr+selStrings[selStr] 197 self.vf.select(selStr+selStrings[selStr],negate)
198
199 -class SuperImposeAtomsCommand(MVCommand):
200
201 - def onAddCmdToViewer(self):
202 self.rigidfitAligner = RigidfitBodyAligner()
203
204 - def doit(self, refAtoms, mobAtoms):
205 """ 206 The SuperImposeAtomsCommand takes two set of Atoms of the same length 207 compute the rotation and translation matrices to superimpose the 208 mobAtoms onto the refAtoms using rigidFit module and then transform the 209 corresponding geometry. 210 """ 211 refCoords = refAtoms.coords 212 mobCoords = mobAtoms.coords 213 214 self.rigidfitAligner.setRefCoords(refCoords) 215 216 # Nothing can be done if the two sets of coords are not of the same 217 # size 218 if not len(refCoords) == len(mobCoords): 219 print " ERROR: Cannot perform the superimposition because the 2 \ 220 mv.lsets of Atoms are not of the same length" 221 return 222 223 # Get the rotation and the translation ysing mglutil.math.rigidFit 224 self.rigidfitAligner.rigidFit(mobCoords) 225 #rotation, translation= rigidFit.rigid_fit( refCoords, inCoords) 226 rotMat = Numeric.identity(4).astype('f') 227 rotMat[:3,:3] = self.rigidfitAligner.rotationMatrix 228 rotMat = Numeric.reshape(rotMat, (16,)) 229 transMat = Numeric.array(self.rigidfitAligner.translationMatrix) 230 231 # transform the geometry representing the atoms only if a gui has been 232 # created: 233 if not self.vf.hasGui: 234 return 235 236 # Transform the mob geometry 237 mobMol = mobAtoms.top.uniq()[0] 238 mob = mobMol.geomContainer.masterGeom 239 self.vf.transformObject('rotation', mob.fullName, matrix=tuple(rotMat)) 240 self.vf.transformObject('translation', mob.fullName, matrix=tuple(transMat))
241 242
243 - def __call__(self, refAtoms, mobAtoms, **kw):
244 """ 245 None <- superimposeAtoms(refAtoms, mobAtoms, **kw) 246 """ 247 if not kw.has_key('redraw'): kw['redraw'] = 1 248 apply(self.doitWrapper, (refAtoms, mobAtoms), kw)
249 250
251 -class SuperImposeAtomsGUICommand(MVCommand, MVAtomICOM):
252 """ 253 The SuperImposeAtomsGUICommand provides a GUI interface to the SuperImposeAtomsCommand. 254 - For now Only two 2 sets of Atoms belonging to a ref molecule and a mobile molecule 255 can be superimposed simultaneously. 256 257 - The command provides two way of defining those two sets of atoms: 258 259 * By picking nodes at the different levels (Molecule, Chain, Residue, Atom) the first pick 260 will define the reference set and the second the mobile set. The picking process will have 261 be done later on the same way and defines a list of pairs of atoms. 262 If the user drags a box only the first node will be considered. Nodes are then converted into 263 an set of Atoms. The 'Edit Atoms Pairs' allows the user to see the pairs but also to alter those 264 sets. For example only the backbone atoms can be considered or all atoms etc. The user can also 265 create his own filter by typing a lambda function in the entry of the combobox. 266 If the 2 sets are not of the same length the extra atoms can be removed either from the beginning, 267 the end or half and half of the longest set allowing a bit more flexibility. 268 If the resulting 2 sets are None then the superimposition cannot be computed. You can reset the 269 process and start over or alter your set using the tools described above. 270 271 * By string: If the user knows the set of nodes of respectively the reference molecule and mobile 272 molecule to be use for the computation two string selector widgets allows him to proceed more 273 efficiently. 274 275 - Known bug: 276 * If the reference molecule is transformed independently of the mobile molecule the mobile 277 molecule will be superimposed onto the original location of the reference molecule. (Working on it) 278 * Cannot superimpose simultaneously multiple sets of molecule. 279 * And probably many more .... 280 """ 281
282 - def __init__(self, func=None):
283 MVCommand.__init__(self, func) 284 MVAtomICOM.__init__(self) 285 self.refAtomList = [] 286 self.inAtomList = [] 287 #self.superImposedPairs = {} 288 self.newPairs = {} 289 self.pair = [] 290 self.mobMolName = None 291 self.refMolName = None 292 self.filters = {'CA Atoms':lambda x: x.name == 'CA', 293 'Backbone Atoms': lambda x: x.name in ['CA', 'C', 294 'N', 'O', 295 'CA@A','C@A', 296 'N@A','O@A'], 297 'Heavy Atoms': lambda x: not x.element == 'H', 298 'All Atoms': None} 299 self.defaultFilter = 'Backbone Atoms'
300 301
302 - def onAddCmdToViewer(self):
303 # Check first is any of the command that superimpose depends on are 304 # already loaded. 305 if not self.vf.commands.has_key('setICOM'): 306 self.vf.loadCommand('interactiveCommands', 'setICOM', 'Pmv', 307 topCommand = 0) 308 if not self.vf.commands.has_key('superimposeAtoms'): 309 self.vf.loadCommand('superImposeCommands', 'superimposeAtoms', 310 'Pmv', topCommand = 0) 311 312 if not self.vf.commands.has_key('startContinuousPicking'): 313 self.vf.loadCommand('dejaVuCommands','startContinuousPicking', 314 'ViewerFramework', topCommand = 0) 315 316 if not self.vf.commands.has_key('stopContinuousPicking'): 317 self.vf.loadCommand('dejaVuCommands','stopContinuousPicking', 318 'ViewerFramework', topCommand = 0) 319 if not self.vf.commands.has_key('labelByExpression'): 320 self.vf.loadCommand('labelCommands', 'labelByExpression', 'Pmv', 321 topCommand = 0) 322 323 self.sphere1 = Spheres(name='elt1', radii=0.5, vertices = [], 324 materials = ( (0.,1.,0.),), protected=True) 325 self.sphere2 = Spheres(name = 'elt2', radii=0.5, vertices =[], 326 materials = ( (1.,1.,0.),), protected=True)
327 328 #self.form = None 329
330 - def onRemoveObjectFromViewer(self,obj):
331 if hasattr(self.vf,'alignment'): 332 self.vf.alnEditor.deleteSequence(obj.name) 333 self.vf.alnEditor.redraw() 334 if obj.name == self.refMolName: 335 self.refMolName=None 336 if obj.name == self.mobMolName: 337 self.mobMolName=None
338
339 - def guiCallback(self):
340 self.vf.setICOM(self, topCommand=0)
341
342 - def buildFormDescr(self, formName):
343 if formName == 'superimpose': 344 idf = InputFormDescr(title="Set Superimposition Parameters") 345 346 idf.append( {'widgetType':Tkinter.Label, 347 'wcfg': {'text':'Get Nodes:'}, 348 'gridcfg':{'sticky':'w'}}) 349 350 self.typeVar = Tkinter.StringVar() 351 self.typeVar.set('By Picking') 352 353 idf.append( {'widgetType':Tkinter.Radiobutton, 354 'name': 'string', 355 'wcfg':{'variable':self.typeVar, 356 'text': 'From String', 357 'value':'From String', 358 'command':self.string_cb, 359 }, 360 'gridcfg':{'sticky':'w', 'columnspan':3}}) 361 362 idf.append( {'widgetType':Tkinter.Radiobutton, 363 'name': 'string', 364 'wcfg':{'variable':self.typeVar, 365 'text': 'From Alignment', 366 'value':'From Alignment', 367 'command':self.alignment_cb, 368 }, 369 'gridcfg':{'sticky':'w', 'columnspan':3}}) 370 371 idf.append( {'widgetType':Tkinter.Radiobutton, 372 'name': 'refPicking', 373 'wcfg':{'variable':self.typeVar, 374 'text': 'By Picking', 375 'value':'By Picking', 376 }, 377 'gridcfg':{'sticky':'w'} }) 378 379 idf.append( {'widgetType':Tkinter.Label, 380 'wcfg': {'text':'Reference nodes:'}, 381 'gridcfg':{'sticky':'w'}}) 382 383 idf.append( {'widgetType':Tkinter.Label, 384 'wcfg': {'text':'Mobile nodes:'}, 385 'gridcfg':{'sticky':'e', 'row':-1}}) 386 387 388 idf.append({'widgetType':Tkinter.Label, 389 'name':'firstNode', 390 'wcfg':{ 'text':''}, 391 'gridcfg':{'sticky':'we'}}) 392 393 idf.append({'widgetType': Tkinter.Label, 394 'name':'secondNode', 395 'wcfg':{ 'text':''}, 396 'gridcfg':{'sticky':'we', 'row':-1}}) 397 398 idf.append({'widgetType':Tkinter.Button, 399 'name':'editPairs', 400 'wcfg':{'text':'Edit Ref Atom -- Mob Atom Pairs', 401 'command':self.editPairs_cb,}, 402 'gridcfg':{'sticky':'we','columnspan':3} 403 }) 404 405 # Continuous Superimposition 406 idf.append({'widgetType':Tkinter.Checkbutton, 407 'name':'continuous', 408 'wcfg':{'variable':Tkinter.IntVar(), 409 'text':'Continuous Superimposition', 410 'command':self.continuous_cb, 411 'padx':10,'pady':10}, 412 'gridcfg':{'sticky':'w'}}) 413 414 # Reset & SuperImpose button. 415 idf.append({'widgetType':Tkinter.Button, 416 'name':'final', 417 'wcfg':{'width':15,'text':'Superimpose', 418 'command':self.superimpose_cb}, 419 'gridcfg':{'sticky':'we', 'row':-1}}) 420 421 idf.append({'widgetType':Tkinter.Button, 422 'name':'reset', 423 'wcfg':{'text':'Reset', 'command':self.reset_cb}, 424 'gridcfg':{'sticky':'we', 'row':-1}}) 425 426 elif formName == 'editPair': 427 idf = InputFormDescr(title='Edit Reference Atom - Mobile Atom Pairs') 428 idf.append({'widgetType':Pmw.ComboBox, 429 'name':'choice', 430 'defaultValue':self.defaultFilter, 431 'wcfg': 432 {'label_text':'Atoms to be consider for superimposition:', 433 'labelpos':'n','label_padx':10,'label_pady':10, 434 'scrolledlist_items': self.filters.keys(), 435 'selectioncommand':self.setDefault}, 436 'gridcfg':{'sticky':'w'}}) 437 438 # If sets not of the same length: 439 idf.append({'widgetType':Pmw.ComboBox, 440 'name':'slice', 441 'defaultValue':'Beginning', 442 'wcfg': 443 {'label_text':'Sets not of the same length', 444 'labelpos':'n','label_padx':10,'label_pady':10, 445 'scrolledlist_items':['Beginning', 446 'End', 447 'Half/Half'] 448 }, 449 'gridcfg':{'sticky':'w', 'row':-1}}) 450 451 entries = map(lambda x: (x, None), self.newPairs.keys()) 452 idf.append({'widgetType':ListChooser, 453 'name':'newpairs', 454 'wcfg':{'mode':'extended', 455 'entries':entries, 456 'lbwcfg':{'exportselection':1}, 457 'title':'Reference Atoms -- Mobile Atoms'}, 458 'gridcfg':{'sticky':'wens', 'columnspan':2}}) 459 460 461 idf.append({'widgetType':Tkinter.Button, 462 'name': 'delete', 463 'wcfg':{'width':15,'text': 'Delete Pairs', 464 'command':self.delete_cb}, 465 'gridcfg':{'sticky':'we', 'columnspan':2}}) 466 467 idf.append({'widgetType':Tkinter.Button, 468 'name': 'dismiss', 469 'wcfg':{'text': 'DISMISS', 470 'command':self.dismiss_cb}, 471 'gridcfg':{'sticky':'we', 'columnspan':2}}) 472 473 474 elif formName == 'editString': 475 idf = InputFormDescr(title = 'Get Nodes From String') 476 idf.append({'widgetType':Tkinter.Label, 477 'wcfg':{'text':'Reference Nodes: '}, 478 'gridcfg':{'sticky':'w'}}) 479 480 idf.append({'widgetType':Tkinter.Label, 481 'wcfg':{'text':'Mobile Nodes: '}, 482 'gridcfg':{'sticky':'w', 'row':-1}}) 483 484 idf.append({'widgetType':Tkinter.Label, 485 'wcfg':{'text':' '}, 486 'gridcfg':{'columnspan':2, 'sticky':'w'}}) 487 488 idf.append({ 'widgetType':StringSelectorGUI, 489 'name':'refNodes','required':1, 490 'wcfg':{ 'molSet': self.vf.Mols, 491 'vf': self.vf, 492 'all':1, 493 'crColor':(1.,0.,0.), 494 }, 495 'gridcfg':{'sticky':'we' }}) 496 497 idf.append({ 'widgetType':StringSelectorGUI, 498 'name':'mobNodes','required':1, 499 'wcfg':{ 'molSet': self.vf.Mols, 500 'vf': self.vf, 501 'all':1, 502 'crColor':(0.,0.,1.), 503 }, 504 'gridcfg':{'row':-1, 'sticky':'we' }}) 505 506 return idf
507
508 - def initICOM(self, modifier):
509 # Create the form if not existing yet 510 form = self.showForm(formName = 'superimpose', modal=0, blocking=0) 511 self.firstLabel = form.descr.entryByName['firstNode']['widget'] 512 self.secondLabel = form.descr.entryByName['secondNode']['widget'] 513 514 self.contVar = form.descr.entryByName['continuous']['wcfg']['variable'] 515 self.pairForm = None 516 517 # set the callback of continuousPicking to label the picked node 518 # 1- get a handle on the cbManager 519 cbManager = self.vf.startContinuousPicking.cbManager 520 # 2- Save the existing callbacks 521 self.oldCallBacks = cbManager.callbacks 522 # 3- Set to the new callback 523 cbManager.SetCallback(CallBackFunction(self.labelByName)) 524 525 self.vf.startContinuousPicking() 526 self.supcb = 0
527 528
529 - def setDefault(self, text):
530 self.defaultFilter = text 531 if hasattr(self, 'pair') and len(self.pair) == 2: 532 filter = self.filters[text] 533 set1 = self.pair[0] 534 set2 = self.pair[1] 535 536 if filter: 537 set1 = set1.get(filter) 538 set2 = set2.get(filter) 539 if (set1 and set2) and (len(set1) == len(set2)): 540 self.updateChooser(set1, set2)
541
542 - def editPairs_cb(self, event=None):
543 pairForm = self.showForm('editPair', force = 1, modal=0, blocking=0, 544 onDestroy= self.dismiss_cb) 545 # show panel with the listchooser of the panel and 546 # Choose the atoms to do the superimposition 547 548 self.chooser = pairForm.descr.entryByName['newpairs']['widget']
549
550 - def dismiss_cb(self, event=None):
551 if self.cmdForms.has_key('editPair'): 552 self.cmdForms['editPair'].destroy() 553 del self.cmdForms['editPair']
554
555 - def string_cb(self, event=None):
556 #get rid of the alignment GUI 557 if hasattr(self.vf,'alnEditor'): 558 self.vf.alnEditor.exit() 559 val = self.showForm('editString') 560 print val 561 if not val == {} or (val.has_key('refNodes') and val.has_key('mobNodes')): 562 apply(self.doitWrapper, (val['refNodes'],), {'log':0}) 563 apply(self.doitWrapper, (val['mobNodes'],), {'log':0}) 564 self.typeVar.set('By Picking')
565 566
567 - def continuous_cb(self, event=None):
568 #get rid of the alignment GUI 569 if hasattr(self.vf,'alnEditor'): 570 self.vf.alnEditor.exit() 571 form = self.cmdForms['superimpose'] 572 supButton = form.descr.entryByName['final']['widget'] 573 if self.contVar.get() == 1: 574 supButton.configure(state=Tkinter.DISABLED) 575 if len(self.newPairs)>=4: 576 self.superimpose_cb() 577 else: 578 supButton.configure(state=Tkinter.NORMAL)
579 580
581 - def labelByName(self, pick):
582 # Continuous labeling. 583 if pick is None: return 584 atom = self.vf.findPickedAtoms(pick) 585 if atom: 586 level = self.vf.ICmdCaller.level.value 587 self.vf.ICmdCaller.level.AddCallback(self.unlabelLevel) 588 if level == Molecule : level = Protein 589 self.node = atom.findType(level) 590 funcItems = map(lambda x: x.full_name(), self.node) 591 self.vf.labelByExpression(self.node, 592 font = 'arial1.glf', 593 location = 'First', 594 textcolor = 'red', only = 1, 595 lambdaFunc = 1,negate=0, 596 function = 'lambda x: str(x.full_name())\n\n', 597 topCommand=0, 598 )
599
600 - def unlabelLevel(self, newLevel, oldLevel):
601 if not hasattr(self, 'node'): return 602 603 if oldLevel == Molecule: oldLevel = Protein 604 # need to be at the former level for all the former picked stuff 605 # so take it all. 606 node = self.vf.getSelection() 607 nodes = node.findType(oldLevel) 608 # Careful in labelByProperty fix a bug if no label should not break! 609 self.vf.labelByExpression(nodes, negate=1, log=0)
610
611 - def stopICOM(self):
612 # Destroy the inputForm 613 self.cmdForms['superimpose'].root.destroy() 614 # Set the form to None. 615 del self.cmdForms['superimpose'] 616 617 # Set back the continuousPicking to unsolicitedPick 618 cbManager = self.vf.startContinuousPicking.cbManager 619 if not len(self.oldCallBacks) == 0: 620 cbManager.SetCallback(self.oldCallBacks[0]) 621 if len(self.oldCallBacks)>1: 622 for cb in self.oldCallBacks[1:]: 623 cbManager.AddCallBack(cb) 624 625 # Remove the unlabel callback bound to the self.vf.ICmdCaller.level 626 if self.unlabelLevel in self.vf.ICmdCaller.level.callbacks: 627 self.vf.ICmdCaller.level.RemoveCallback(self.unlabelLevel) 628 629 # Unlabel whatever is labeled 630 level = self.vf.ICmdCaller.level.value 631 632 nodes = self.vf.getSelection().findType(level) 633 if not nodes is None or len(nodes)!=0: 634 self.vf.labelByExpression(nodes, negate=1, log=0) 635 636 # Stop the continuous picking. 637 self.vf.stopContinuousPicking() 638 639 self.sphere1.Set(vertices=[], tagModified=False) 640 self.sphere2.Set(vertices=[], tagModified=False)
641 ## self.visualFeedBack(vertices =[]) 642 643
644 - def updateChooser(self, set1, set2):
645 for elt1, elt2 in map(None, set1, set2): 646 key = elt1.full_name() + '--' + elt2.full_name() 647 self.newPairs[key] = (elt1, elt2) 648 if not self.pairForm is None: 649 entry = (key, None) 650 self.chooser.add(entry)
651 652
653 - def reset_cb(self, event=None):
654 """Button to reset the superimposition and the list of pairs.""" 655 # Reset the chooser and the lists of pairs 656 if self.newPairs == {}: return 657 if not self.pairForm is None: 658 self.chooser.clear() 659 self.newPairs = {} 660 # Reset the geometry. 661 vi = self.vf.GUI.VIEWER 662 geom = self.mobileMol.geomContainer.masterGeom 663 oldCurrent = vi.currentObject 664 vi.SetCurrentObject(geom) 665 # transform only the given geometry. 666 if vi.redirectTransformToRoot == 1: 667 old = vi.redirectTransformToRoot 668 vi.TransformRootOnly(0) 669 else: 670 old = 0 671 # Right now reset all the transformations applied to the mobile object. 672 # Maybe should separate from the superimposition and only reset these. 673 vi.ResetCurrentObject() 674 # Put everything back like it was before. 675 if old == 1: 676 vi.TransformRootOnly(1) 677 vi.SetCurrentObject(oldCurrent) 678 679 self.sphere1.Set(vertices=[], tagModified=False) 680 self.sphere2.Set(vertices=[], tagModified=False) 681 self.firstLabel.configure(text='') 682 self.secondLabel.configure(text='')
683 684 ## self.visualFeedBack.Set(vertices=[], tagModified=False) 685 686
687 - def delete_cb(self, event = None):
688 # Delete the selected pair from the listchooser and from the pairlist 689 selectedNewPairs = self.chooser.get() 690 # Undisplay the label (Maybe only if the last pair is being deleted ) 691 self.firstLabel.configure(text='') 692 self.secondLabel.configure(text='') 693 for pair in selectedNewPairs: 694 if len(self.chooser.entries) >=4: 695 self.chooser.remove(pair) 696 del self.newPairs[pair] 697 if self.contVar.get()==1 or self.supcb==1: 698 self.superimpose_cb()
699
700 - def superimpose_cb(self, event=None):
701 if len(self.newPairs) >= 4 : 702 # Need at least 4 pairs of atoms to do the superimposition 703 setAtm1 = AtomSet(map(lambda x: x[0], 704 self.newPairs.values())) 705 setAtm2 = AtomSet(map(lambda x: x[1], 706 self.newPairs.values())) 707 if len(setAtm1) != len(setAtm2): 708 message = ' ERROR: the 2 sets of atoms are not of the length\nthe superimposition cannot be performed. ' 709 self.warningMsg(msg) 710 return 711 712 self.vf.superimposeAtoms(setAtm1, setAtm2) 713 self.supcb = 1
714 ## self.visualFeedBack.Set(vertices=self.visualVertices, 715 ## tagModified=False) 716
717 - def __call__(self, atoms, **kw):
718 ats = self.vf.expandNodes(atoms) 719 if not len(ats): return 'ERROR' 720 kw['redraw']=1 721 kw['log']=0 722 return apply(self.doitWrapper, (ats,), kw)
723 724
725 - def doit(self, nodes):
726 """ 727 Create the 2 sets of atom that will be used to do the superimposition. 728 Then call the superImposeCommand with these 2 sets. 729 If continuous is on then the superimposition will be updated each time 730 a pair of atoms is added otherwise the superimposition will be updated 731 every 4 pairs of atoms. 732 """ 733 734 # Get the ICOM level 735 icomLevel = self.vf.ICmdCaller.level.value 736 # Not doing anything if no nodes picked: 737 if not nodes: return 738 739 if self.typeVar.get() == 'By Picking': 740 # only take the first node picked. 741 node = nodes[0] 742 nodeMol = node.top 743 744 elif self.typeVar.get() == 'From String': 745 node = nodes 746 molecules = nodes.top.uniq() 747 if len(molecules)>1: 748 # nodes need to belong to only one molecule 749 return 750 else: nodeMol = molecules[0] 751 752 elif self.typeVar.get() == 'From Alignment': 753 node = nodes 754 molecules = nodes.top.uniq() 755 if len(molecules)>1: 756 # nodes need to belong to only one molecule 757 return 758 else: nodeMol = molecules[0] 759 760 # 2- Get the atoms from the chosen nodes 761 atms = node.findType(Atom) 762 763 # First set of nodes == defines the first set of 1st elt in the pairs 764 if len(self.pair) == 0 : 765 self.secondLabel.configure(text ='') 766 # Defines reference molecule: 767 if self.newPairs == {}: 768 self.refMol = nodeMol 769 # Draw the feedBack sphere. 770 mGeom = self.refMol.geomContainer.masterGeom 771 self.vf.GUI.VIEWER.AddObject(self.sphere1, parent = mGeom) 772 773 if nodeMol != self.refMol: 774 self.firstLabel.configure(text ='') 775 # if the node belongs to the another molecule return. 776 # The pairs are defined allways in the same order. 777 return 778 779 self.pair.append(atms) 780 #self.pair.append(node) 781 if self.typeVar.get() == 'By Picking': 782 self.firstLabel.configure(text=node.full_name()) 783 784 elif len(self.pair) == 1 : 785 # Creates Second set of elt in the pair. 786 if self.newPairs=={}: 787 if nodeMol != self.refMol: 788 # set the mobile molecule and finish the first pair 789 self.mobileMol = nodeMol 790 mGeom = self.mobileMol.geomContainer.masterGeom 791 self.vf.GUI.VIEWER.AddObject(self.sphere2, 792 parent = mGeom) 793 794 if nodeMol != self.mobileMol: 795 return 796 self.pair.append(atms) 797 #self.pair.append(node) 798 if self.typeVar.get() == 'By Picking': 799 self.secondLabel.configure(text=node.full_name()) 800 801 # Now we have the two set of elts to create pairs: 802 # 1- Check if the 2 sets have the same length: 803 set1 = self.pair[0] 804 set1.sort() 805 set2 = self.pair[1] 806 set2.sort() 807 if not set1 or not set2: 808 print "ERROR: One of the sets is None" 809 return 810 elif len(set1) != len(set2): 811 if node.__class__ == Atom: 812 print 'ERROR: the 2 sets of atoms are not of the same size' 813 return 814 815 set1,set2 816 if node.__class__ in [Protein,ProteinSet, Residue, ResidueSet, Chain, ChainSet]: 817 filter = self.defaultFilter 818 if self.filters.has_key(filter): 819 set1 = self.pair[0].get(self.filters[filter]) 820 set2 = self.pair[1].get(self.filters[filter]) 821 if not set1 or not set2: 822 print 'ERROR: cannot compute the superimposition' 823 print 'not set1 or not set2' 824 return 825 826 elif len(set1) != len(set2): 827 print 'ERROR: cannot compute the superimposition' 828 print 'len(set1) != len(set2)' 829 return 830 831 #print 'set1', set1 832 #print 'set2', set2 833 self.updateChooser(set1, set2) 834 self.pair = [] 835 836 if len(self.newPairs)>=4 and self.contVar.get() == 1: 837 # Continuous picking is on and superimposition can be done if 838 # there are more than 4 pairs. 839 self.superimpose_cb()
840
841 - def alignment_cb(self, event=None):
842 if not hasattr(self.vf,'alignment'): 843 self.vf.alignment = Alignment() 844 if not hasattr(self.vf,'alnEditor'): 845 self.vf.alnEditor = PmvAlignmentEditor(vf=self.vf) 846 self.vf.alnEditor.alignment = self.vf.alignment 847 else: 848 self.vf.alnEditor.redraw() 849 self.vf.alnEditor.master.deiconify() 850 for mol in self.vf.Mols: 851 if mol.name not in self.vf.alignment.seqNames: 852 self.vf.alnEditor.getSequence(mol)
853 854 855 SuperImposeAtomsGUICommandGUI = CommandGUI() 856 SuperImposeAtomsGUICommandGUI.addMenuCommand('menuRoot', 'Compute', 857 'superimposeAtoms', 858 859 cascadeName = "Superimpose") 860 861 862
863 -class SuperimposeCoordsCommand(MVCommand):
864
865 - def onAddCmdToViewer(self):
866 if not self.vf.commands.has_key('superimposeAtoms'): 867 self.vf.loadCommand('superImposeCommands', 'superimposeAtoms', 868 'Pmv', topCommand = 0)
869 870
871 - def doit(self, refAtoms, inAtoms, inAllAtoms = None):
872 """ 873 The SuperimposeCoordsCommand takes two set of Atoms of the same length 874 refAtoms and inAtoms, a subset of inAllAtoms, 875 plus an optional third set, inAllAtoms, 876 It computes the rotation and translation matrices to superimpose the 877 inAtoms onto the refAtoms using rigidFit module. Then transforms the 878 coords of inAllAtoms. 879 """ 880 # superimpose the inAtoms set onto the refAtoms set. 881 self.vf.superimposeAtoms(refAtoms, inAtoms) 882 if not inAllAtoms: 883 inAllAtoms = inAtoms 884 # then calls the self.vf.superimposeAtoms.rigidfitAligner 885 # transformCoords method. 886 ra = self.vf.superimposeAtoms.rigidfitAligner 887 newcoords = ra.transformCoords(inAllAtoms.coords) 888 if not newcoords is None and newcoords.shape[1]!=3: 889 newcoords=newcoords[:,:3] 890 891 ## refCoords = refAtoms.coords 892 ## inCoords = inAtoms.coords 893 ## #there could be other atoms which are not being used as reference pts 894 ## if not inAllAtoms: 895 ## inAllAtoms = inAtoms 896 897 ## # Nothing can be done if the two sets of coords are not of the same 898 ## # size 899 ## if not len(refCoords) == len(inCoords): 900 ## print " ERROR: Cannot perform the superimposition because the 2 \ 901 ## mv.lsets of Atoms are not of the same length" 902 ## return 903 904 ## # Get the rotation and the translation from mglutil.math.rigidFit 905 ## rotation, translation = rigidFit.rigid_fit( refCoords, inCoords) 906 907 ## transMat = Numeric.array(translation) 908 ## refCoords = Numeric.array(refAtoms.coords) 909 910 ## inAllCoords = Numeric.array(inAllAtoms.coords) 911 912 ## # transform the coords 913 914 ## # apply the rotation to the inAtoms.coords 915 ## newcoords = Numeric.matrixmultiply(inAllCoords , rotation) 916 917 ## # apply the translation to inAtoms.coords 918 ## newcoords = newcoords + transMat 919 920 #add the new conformation to atomSet._coords 921 inAllAtoms.addConformation(newcoords) 922 923 #set conformation of in Atoms to the new conformation 924 confNum = len(inAllAtoms[0]._coords)-1 925 inAllAtoms.setConformation(confNum)
926 927
928 - def __call__(self, refAtoms, inAtoms, inAllAtoms=None, **kw):
929 """ 930 None <- superimposeCoords(refAtoms, inAtoms, inAllAtoms, **kw) 931 refAtoms: atoms in reference structure 932 inAtoms: corresponding atoms in structure to be moved 933 by rigidFit to refAtoms 934 inAllAtoms: complete set of all atoms whose coords are to be 935 transformed bytranslation and rotation matrices from rigidFit. 936 (Possibly inAtoms will contain all atoms in molecule to be 937 moved so inAllAtoms will be None.) 938 """ 939 if not kw.has_key('redraw'): kw['redraw'] = 0 940 apply(self.doitWrapper, (refAtoms, inAtoms, inAllAtoms), kw)
941 942 943 commandList = [ 944 {'name':'superimposeAtoms', 'cmd':SuperImposeAtomsCommand(), 945 'gui':None}, 946 ## {'name':'superimposeAtomsGC', 'cmd':SuperImposeAtomsGUICommand(), 947 ## 'gui':SuperImposeAtomsGUICommandGUI}, 948 {'name':'superimposeCoords', 'cmd':SuperimposeCoordsCommand(), 949 'gui':None}] 950
951 -def initModule(viewer):
952 for dict in commandList: 953 viewer.addCommand(dict['cmd'], dict['name'], dict['gui'])
954