Chem.DSViewer

Package Chem :: Module DSViewer |
[hide private]
[frames] | no frames]

# Source Code for Module Chem.DSViewer

      1  # $Id: DSViewer.py 746 2008-07-07 13:21:24Z glandrum $
      2  #
      3  # Copyright (C) 2005-2006 Rational Discovery LLC
      4  #
      5  #   @@ All Rights Reserved  @@
      6  #
      7  """ uses DSViewer to interact with molecules
      8
      9  """
     10  import Chem
     11  from win32com.client import Dispatch
     12  import tempfile,os
     13
     14  _nextDisplayId=1
     15 -class Displayable(object):
     16 -  def __init__(self,doc,id=-1):
     17      global _nextDisplayId
     18      if id<0:
     19        id = _nextDisplayId
     20        _nextDisplayId += 1
     21
     22      self.doc = doc
     23      self.id = id
     24      self.visible=True
     25      self.children = []
     26
     27 -  def Select(self,atoms=[],state=True,recurse=False):
     28      if state:
     29        selText = 'true'
     30      else:
     31        selText = 'false'
     32      if not atoms or atoms=='*':
     33        atomStr = '; atom "*"'
     34      else:
     35        # DSViewer has atom ids from 1, we do it from 0:
     36        atoms = ['id=%d'%(x) for x in atoms]
     37        atomStr = '; atom %s'%','.join(atoms)
     38
     39      cmd = 'SetProperty object RD_Visual=%d %s: select=%s'%(self.id,atomStr,
     40                                                                   selText)
     41      r = int(str(self.doc.DoCommand(cmd)))
     42      if not r and not atoms:
     43        # this handles an annoying case where if you try to select
     44        # a molecule by ID in DSViewer, you get nothing selected:
     45        atomStr=''
     46        cmd = 'SetProperty object RD_Visual=%d %s: select=%s'%(self.id,atomStr,
     47                                                               selText)
     48        r = int(str(self.doc.DoCommand(cmd)))
     49      #print 'sel cmd:',cmd
     50      #print 'result:', r
     51
     52      # stupid DSViewer will select the bonds between pairs of highlighted atoms,
     53      # stop that nonsense right now:
     54      if r:
     55        cmd = 'SetProperty object RD_Visual=%d; bond index="*": select=off'%(self.id)
     56        self.doc.DoCommand(cmd)
     57
     58      if recurse:
     59        for child in self.children:
     60          child.Select(atoms=atoms,state=state,recurse=True)
     61      return r
     62
     63 -  def Hide(self,recurse=True):
     64      self.Select(state=True,recurse=True)
     65      self.doc.DoCommand('hide')
     66      self.Select(state=False,recurse=True)
     67 -  def Show(self,recurse=True):
     68      self.Select(state=True,recurse=True)
     69      self.doc.DoCommand('Show')
     70      self.Select(state=False,recurse=True)
     71
     72 -  def ShowOnly(self,recurse=True):
     73      self.doc.DoCommand('HideAll')
     74      self.Select(state=True,recurse=True)
     75      self.doc.DoCommand('Show')
     76      self.Select(state=False,recurse=True)
     77
     78 -  def __del__(self):
     79      self.doc.DoCommand('UnselectAll')
     80      count=self.Select(state=True,recurse=True)
     81      if count:
     82        self.doc.DoCommand('Delete')
     83
     84 -class MolViewer(object):
     85 -  def __init__(self,force=0,title='Untitled',**kwargs):
     86      self.app = Dispatch('WebLabViewerPro.Application')
     87      self.app.Visible=1
     88      if force or self.app.ActiveDocument is None:
     89        self.doc = self.app.New(title)
     90      else:
     91        self.doc = self.app.ActiveDocument
     92
     93      self.displayables={}
     94
     95 -  def DeleteAll(self):
     96      self.doc.DoCommand('SelectAll')
     97      self.doc.DoCommand('Delete')
     98      self.displayables = {}
     99
    100 -  def DeleteAllExcept(self,excludes):
    101      excludes = [x.lower() for x in excludes]
    102      allNames = self.displayables.keys()
    103      for nm in allNames:
    104        if nm not in excludes:
    105          del self.displayables[nm]
    106
    107
    108
    109 -  def ShowMol(self,mol,name='molecule',showOnly=True,highlightFeatures=[],
    110                molB="",confId=-1,zoom=True):
    111      if showOnly:
    112        self.DeleteAll()
    113        obj = None
    114      else:
    115        obj = self.displayables.get(name.lower(),None)
    116        #if obj:
    117        #  obj.Select(state=True)
    118        #  self.doc.DoCommand('Delete')
    119        #  obj.Select(state=False)
    120
    121      if not molB:
    122        molB = Chem.MolToMolBlock(mol,confId=confId)
    123
    124      tmp = name + "\n" + molB[molB.index('\n')+1:]
    125      molB = tmp
    126
    127      if not obj:
    128        obj = Displayable(self.doc)
    129      if not hasattr(obj,'_molBlock') or obj._molBlock != molB:
    130        obj._molBlock = molB
    131        fN = tempfile.mktemp('.mol')
    132        open(fN,'w+').write(molB)
    133        self.doc.DoCommand('PasteFrom %s'%fN)
    134        self.doc.DoCommand('SetProperty molecule id=0 : RD_Visual=%d'%(obj.id))
    135        self.doc.DoCommand('SetProperty molecule id=0 : id=%d'%(obj.id))
    136        self.doc.DoCommand('SetProperty molecule id=0 : select=off')
    137        os.unlink(fN)
    138      else:
    139        obj.Select(state=True)
    140        self.doc.DoCommand('Show')
    141
    142      self.displayables[name.lower()] = obj
    143
    144      if zoom:
    145        self.doc.DoCommand('Center')
    146        self.doc.DoCommand('FitView')
    147
    148      return
    149
    150 -  def LoadFile(self,filename,name,showOnly=False):
    151      if showOnly:
    152        self.DeleteAll()
    153      self.doc.DoCommand('PasteFrom %s'%filename)
    154      obj = Displayable(self.doc)
    155      self.doc.DoCommand('SetProperty molecule id=0 : id=%d'%(obj.id))
    156      self.doc.DoCommand('SetProperty molecule id=0 : select=off')
    157      count = self.doc.DoCommand('SetProperty AminoAcidChain id=0 : RD_Visual=%d'%(obj.id))
    158      if not count or int(count)<=0:
    159        count = self.doc.DoCommand('SetProperty molecule id=0 : RD_Visual=%d'%(obj.id))
    160      self.displayables[name.lower()] = obj
    161      return obj
    162
    163
    164 -  def GetSelectedAtoms(self,whichSelection=''):
    165      #print 'WHICH',repr(whichSelection),self.displayables.has_key(whichSelection.lower())
    166      if not whichSelection:
    167        d = str(self.doc.DoCommand('GetPropertyValue atom select=true: id=?'))
    168        d2 = str(self.doc.DoCommand('GetPropertyValue atom select=true: molecule=?'))
    169        if d2:
    170          molIds = []
    171          tmpD = {}
    172          for id in d2.split(','):
    173            id = int(id.split('/')[1])+1
    174            if tmpD.has_key(id):
    175              molIds.append(tmpD[id])
    176            else:
    177              for k,v in self.displayables.iteritems():
    178                if id==v.id:
    179                  tmpD[id] = k
    180                  molIds.append(k)
    181        else:
    182            molIds = ['']*(d.count(',')+1)
    183      elif self.displayables.has_key(whichSelection.lower()):
    184        whichSelection = whichSelection.lower()
    185        whichSelection = self.displayables[whichSelection].id
    186        d = str(self.doc.DoCommand('GetPropertyValue molecule RD_Visual=%d; atom select=true: id=?'%whichSelection))
    187        molIds = [whichSelection]*(d.count(',')+1)
    188      else:
    189        d = None
    190        molIds = None
    191
    192      if d:
    193        splitD = d.split(',')
    194        #print 'splitD:',splitD
    195        #print 'molIds:',molIds
    196        try:
    197          res = []
    198          for i in range(len(splitD)):
    199            # DSViewer has atom ids from 1, we do it from 0:
    200            idx = int(splitD[i])
    201            res.append((molIds[i],idx))
    202        except:
    203          import traceback
    204          traceback.print_exc()
    205          res = []
    206      else:
    207        res = []
    208      return res
    209
    210 -  def HighlightAtoms(self,indices,where,extraHighlight=False):
    211      self.doc.DoCommand('UnSelectAll')
    212      self.SelectAtoms(where,indices)
    213 -  def SelectAtoms(self,itemId,atomIndices,selName='selection'):
    214      self.doc.DoCommand('UnSelectAll')
    215      self.doc.DoCommand('SetProperty atom id="*": select=off')
    216      o = self.displayables.get(itemId.lower(),None)
    217      #print 'O:',itemId,atomIndices
    218      if o:
    219        o.Select(atoms=atomIndices)
    220
    221 -  def SetDisplayUpdate(self,val):
    222      if not val:
    223        self.doc.DoCommand('UpdateView off')
    224      else:
    225        self.doc.DoCommand('UpdateView on')
    226
    227 -  def GetAtomCoords(self,sels):
    228      res = {}
    229      for label,idx in sels:
    230        whichSelection = label.lower()
    231        whichSelection = self.displayables[label].id
    232        # DSViewer has atom ids from 1, we do it from 0:
    233        idx += 1
    234        cmd = 'GetPropertyValue molecule RD_Visual=%d; atom id=%d: xyz=?'%(whichSelection,idx)
    235        coords = self.doc.DoCommand(cmd)
    236        coords = [float(x) for x in coords.split(' ')]
    237        res[(label,idx)] = coords
    238        #print 'grab:',label,idx,coords
    239      return res
    240
    241 -  def AddPharmacophore(self,locs,colors,label,sphereRad=0.5):
    242      label=label.lower()
    243      self.SetDisplayUpdate(False)
    244      parent = Displayable(self.doc)
    245      for i,loc in enumerate(locs):
    246        color = colors[i]
    247        color = ' '.join([str(int(255*x)) for x in color])
    248        obj = Displayable(self.doc)
    249        nm = 'sphere-%d'%obj.id
    250        self.doc.DoCommand('Sphere %s'%nm)
    251        self.doc.DoCommand('SetProperty Object name=%s : xyz=%f %f %f'%(nm,loc[0],loc[1],loc[2]))
    252        self.doc.DoCommand('SetProperty Object name=%s : radius=%f'%(nm,sphereRad))
    253        self.doc.DoCommand('SetProperty Object name=%s : color=%s'%(nm,color))
    254        self.doc.DoCommand('SetProperty Object name=%s : RD_Visual=%d'%(nm,parent.id))
    255        self.doc.DoCommand('SetProperty Object name=%s : id=%d'%(nm,parent.id))
    256        #parent.children.append(obj)
    257      self.displayables[label] = parent
    258      self.SetDisplayUpdate(True)
    259
    260
    261 -  def SetDisplayStyle(self,obj,style=''):
    262      self.doc.DoCommand('UnSelectAll')
    263      obj = obj.lower()
    264      o = self.displayables.get(obj,None)
    265      if o:
    266        o.Select(state=True)
    267        if style=='sticks':
    268          self.doc.DoCommand('DisplayStyle Atom Stick')
    269        elif style=='lines':
    270          self.doc.DoCommand('DisplayStyle Atom Line')
    271        elif style=='':
    272          self.doc.DoCommand('DisplayStyle Atom Off')
    273        o.Select(state=False)
    274
    275
    276 -  def HideAll(self):
    277      self.doc.DoCommand('HideAll')
    278 -  def HideObject(self,objName):
    279      self.doc.DoCommand('UnSelectAll')
    280      objName = objName.lower()
    281      o = self.displayables.get(objName,None)
    282      if o:
    283        o.Hide()
    284
    285 -  def DisplayObject(self,objName):
    286      self.doc.DoCommand('UnSelectAll')
    287      objName = objName.lower()
    288      o = self.displayables.get(objName,None)
    289      if o:
    290        o.Show()
    291
    292 -  def Zoom(self,objName):
    293      self.doc.DoCommand('UnSelectAll')
    294      objName = objName.lower()
    295      o = self.displayables.get(objName,None)
    296      if o:
    297        r = o.Select(state=True)
    298        self.doc.DoCommand('Center')
    299        self.doc.DoCommand('FitView')
    300        o.Select(state=False)
    301
    302 -  def SelectProteinNeighborhood(self,aroundObj,inObj,distance=5.0,
    303                                  name='neighborhood',showSurface=False):
    304
    305      """ FIX: the surface display stuff here is all screwed up due to
    306      differences between the way PyMol and DSViewer handle surfaces.
    307      In PyMol they are essentially a display mode for the protein, so
    308      they don't need to be managed separately.
    309      In DSViewer, on the other hand, the surface is attached to the
    310      protein, but it needs to be hidden or shown on its own.  I haven't
    311      figured out how to do that yet.
    312      """
    313      self.doc.DoCommand('UnSelectAll')
    314      o = self.displayables.get(aroundObj.lower(),None)
    315      p = self.displayables.get(inObj.lower(),None)
    316      if o and p:
    317        self.SetDisplayUpdate(False)
    318        p.Show()
    319        self.doc.DoCommand('UnSelectAll')
    320        tmp = self.doc.DoCommand('SetProperty object RD_Visual=%d;object id="*":select=on'%o.id)
    321        tmp = self.doc.DoCommand('SelectByRadius inside %f atom'%distance)
    322        # that selects all atoms in the radius, now we need to make sure
    323        #  only atoms in _inObj_ are selected:
    324        for obj in self.displayables.values():
    325          if obj.id != p.id:
    326            self.doc.DoCommand('SetProperty object RD_Visual=%d;object id="*":select=off'%obj.id)
    327
    328        # ----
    329        # now get all the residue names for the selected atoms:
    330        rs = self.doc.DoCommand('GetPropertyValue atom select=true: parent=?')
    331        if rs:
    332          rs = rs.split(',')
    333          residues = {}
    334          for r in rs:
    335            residues[r] = 1
    336
    337          # and select each atom in those residues:
    338          parents=','.join(['parent="%s"'%x for x in residues.keys()])
    339          cmd = 'SetProperty atom %s: select=on'%parents
    340          tmp=self.doc.DoCommand(cmd)
    341        if showSurface:
    342          # create the surface:
    343          self.doc.DoCommand('Surface')
    344          obj = Displayable(self.doc)
    345          self.displayables[name]=obj
    346          self.doc.DoCommand('SetProperty surface id="*":RD_Visual=%d'%obj.id)
    347
    348          self.doc.DoCommand('UnSelectAll')
    349
    350
    351        self.SetDisplayUpdate(True)
    352
    353 -  def Redraw(self):
    354      self.SetDisplayUpdate(True)
    355
    356
    357
    358  if __name__=='__main__':
    359    import Chem
    360    from Chem import rdDistGeom, rdForceFieldHelpers
    361
    362    m = Chem.MolFromSmiles('c1cccc2c1cccc2')
    363    rdDistGeom.EmbedMolecule(m)
    364    rdForceFieldHelpers.UFFOptimizeMolecule(m)
    365
    366    s = MolViewer()
    367    s.ShowMol(m)
    368