Package rdkit :: Package Chem :: Module DSViewer

[hide private]
[frames] | no frames]

# Source Code for Module rdkit.Chem.DSViewer

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