rdkit.Chem.Features.ShowFeats

Package rdkit :: Package Chem :: Package Features :: Module ShowFeats |
[hide private]
[frames] | no frames]

# Source Code for Module rdkit.Chem.Features.ShowFeats

      1  # $Id: ShowFeats.py 537 2007-08-20 14:54:35Z landrgr1 $
      2  #
      3  # Created by Greg Landrum Aug 2006
      4  #
      5  #
      6  _version = "0.3.2"
      7
      8
      9  _usage="""
     10     ShowFeats [optional args] <filenames>
     11
     12    if "-" is provided as a filename, data will be read from stdin (the console)
     13  """
     14
     15  _welcomeMessage="This is ShowFeats version %s"%(_version)
     16
     17
     18  import math
     19  #set up the logger:
     20  from rdkit import RDLogger as logging
     21  logger = logging.logger()
     22  logger.setLevel(logging.INFO)
     23
     24  from rdkit import Geometry
     25  from rdkit.Chem.Features import FeatDirUtilsRD as FeatDirUtils
     26
     27  _featColors = {
     28    'Donor':(0,1,1),
     29    'Acceptor':(1,0,1),
     30    'NegIonizable':(1,0,0),
     31    'PosIonizable':(0,0,1),
     32    'ZnBinder':(1,.5,.5),
     33    'Aromatic':(1,.8,.2),
     34    'LumpedHydrophobe':(.5,.25,0),
     35    'Hydrophobe':(.5,.25,0),
     36    }
     37
     38 -def _getVectNormal(v,tol=1e-4):
     39    if math.fabs(v.x)>tol:
     40      res = Geometry.Point3D(v.y,-v.x,0)
     41    elif math.fabs(v.y)>tol:
     42      res = Geometry.Point3D(-v.y,v.x,0)
     43    elif math.fabs(v.z)>tol:
     44      res = Geometry.Point3D(1,0,0)
     45    else:
     46      raise ValueError,'cannot find normal to the null vector'
     47    res.Normalize()
     48    return res
     49
     50  _canonArrowhead=None
     51 -def _buildCanonArrowhead(headFrac,nSteps,aspect):
     52    global _canonArrowhead
     53    startP = RDGeometry.Point3D(0,0,headFrac)
     54    _canonArrowhead=[startP]
     55
     56    scale = headFrac*aspect
     57    baseV = RDGeometry.Point3D(scale,0,0)
     58    _canonArrowhead.append(baseV)
     59
     60    twopi = 2*math.pi
     61    for i in range(1,nSteps):
     62      v = RDGeometry.Point3D(scale*math.cos(i*twopi),scale*math.sin(i*twopi),0)
     63      _canonArrowhead.append(v)
     64
     65
     66  _globalArrowCGO=[]
     67  _globalSphereCGO=[]
     68  # taken from pymol's cgo.py
     69  BEGIN=2
     70  END=3
     71  TRIANGLE_FAN=6
     72  COLOR=6
     73  VERTEX=4
     74  NORMAL=5
     75  SPHERE=7
     76  CYLINDER=9
     77  ALPHA=25
     78
     79 -def _cgoArrowhead(viewer,tail,head,radius,color,label,headFrac=0.3,nSteps=10,aspect=.5):
     80    global _globalArrowCGO
     81    delta = head-tail
     82    normal = _getVectNormal(delta)
     83    delta.Normalize()
     84
     85    dv = head-tail
     86    dv.Normalize()
     87    dv *= headFrac
     88    startP = head
     89
     90    normal*=headFrac*aspect
     91
     92    cgo = [BEGIN,TRIANGLE_FAN,
     93           COLOR,color[0],color[1],color[2],
     94            NORMAL,dv.x,dv.y,dv.z,
     95           VERTEX,head.x+dv.x,head.y+dv.y,head.z+dv.z]
     96    base = [BEGIN,TRIANGLE_FAN,
     97            COLOR,color[0],color[1],color[2],
     98            NORMAL,-dv.x,-dv.y,-dv.z,
     99            VERTEX,head.x,head.y,head.z]
    100    v = startP+normal
    101    cgo.extend([NORMAL,normal.x,normal.y,normal.z])
    102    cgo.extend([VERTEX,v.x,v.y,v.z])
    103    base.extend([VERTEX,v.x,v.y,v.z])
    104    for i in range(1,nSteps):
    105      v = FeatDirUtils.ArbAxisRotation(360./nSteps*i,delta,normal)
    106      cgo.extend([NORMAL,v.x,v.y,v.z])
    107      v += startP
    108      cgo.extend([VERTEX,v.x,v.y,v.z])
    109      base.extend([VERTEX,v.x,v.y,v.z])
    110
    111    cgo.extend([NORMAL,normal.x,normal.y,normal.z])
    112    cgo.extend([VERTEX,startP.x+normal.x,startP.y+normal.y,startP.z+normal.z])
    113    base.extend([VERTEX,startP.x+normal.x,startP.y+normal.y,startP.z+normal.z])
    114    cgo.append(END)
    115    base.append(END)
    116    cgo.extend(base)
    117
    118    #viewer.server.renderCGO(cgo,label)
    119    _globalArrowCGO.extend(cgo)
    120
    121 -def ShowArrow(viewer,tail,head,radius,color,label,transparency=0,includeArrowhead=True):
    122    global _globalArrowCGO
    123    if transparency:
    124      _globalArrowCGO.extend([ALPHA,1-transparency])
    125    else:
    126      _globalArrowCGO.extend([ALPHA,1])
    127    _globalArrowCGO.extend([CYLINDER,tail.x,tail.y,tail.z,
    128                            head.x,head.y,head.z,
    129                            radius*.10,
    130                            color[0],color[1],color[2],
    131                            color[0],color[1],color[2],
    132                            ])
    133
    134    if includeArrowhead:
    135      _cgoArrowhead(viewer,tail,head,radius,color,label)
    136
    137
    138 -def ShowMolFeats(mol,factory,viewer,radius=0.5,confId=-1,showOnly=True,
    139                   name='',transparency=0.0,colors=None,excludeTypes=[],
    140                   useFeatDirs=True,featLabel=None,dirLabel=None,includeArrowheads=True,
    141                   writeFeats=False,showMol=True,featMapFile=False):
    142    global _globalSphereCGO
    143    if not name:
    144      if mol.HasProp('_Name'):
    145        name =  mol.GetProp('_Name')
    146      else:
    147        name = 'molecule'
    148    if not colors:
    149      colors = _featColors
    150
    151    if showMol:
    152      viewer.ShowMol(mol,name=name,showOnly=showOnly,confId=confId)
    153
    154    molFeats=factory.GetFeaturesForMol(mol)
    155    if not featLabel:
    156      featLabel='%s-feats'%name
    157      viewer.server.resetCGO(featLabel)
    158    if not dirLabel:
    159      dirLabel=featLabel+"-dirs"
    160      viewer.server.resetCGO(dirLabel)
    161
    162    for i,feat in enumerate(molFeats):
    163      family=feat.GetFamily()
    164      if family in excludeTypes:
    165        continue
    166      pos = feat.GetPos(confId)
    167      color = colors.get(family,(.5,.5,.5))
    168      nm = '%s(%d)'%(family,i+1)
    169
    170      if transparency:
    171        _globalSphereCGO.extend([ALPHA,1-transparency])
    172      else:
    173        _globalSphereCGO.extend([ALPHA,1])
    174      _globalSphereCGO.extend([COLOR,color[0],color[1],color[2],
    175                               SPHERE,pos.x,pos.y,pos.z,
    176                               radius])
    177      if writeFeats:
    178        aidText = ' '.join([str(x+1) for x in feat.GetAtomIds()])
    179        print '%s\t%.3f\t%.3f\t%.3f\t1.0\t# %s'%(family,pos.x,pos.y,pos.z,aidText)
    180
    181      if featMapFile:
    182        print >>featMapFile,"  family=%s pos=(%.3f,%.3f,%.3f) weight=1.0"%(family,pos.x,pos.y,pos.z),
    183
    184      if useFeatDirs:
    185        ps = []
    186        if family=='Aromatic':
    187          ps,fType = FeatDirUtils.GetAromaticFeatVects(mol.GetConformer(confId),
    188                                                                 feat.GetAtomIds(),pos,
    189                                                                 scale=1.0)
    190        elif family=='Donor':
    191          aids = feat.GetAtomIds()
    192          if len(aids)==1:
    193            featAtom=mol.GetAtomWithIdx(aids[0])
    194            hvyNbrs=[x for x in featAtom.GetNeighbors() if x.GetAtomicNum()!=1]
    195            if len(hvyNbrs)==1:
    196              ps,fType = FeatDirUtils.GetDonor1FeatVects(mol.GetConformer(confId),
    197                                                         aids,scale=1.0)
    198            elif len(hvyNbrs)==2:
    199              ps,fType = FeatDirUtils.GetDonor2FeatVects(mol.GetConformer(confId),
    200                                                         aids,scale=1.0)
    201            elif len(hvyNbrs)==3:
    202              ps,fType = FeatDirUtils.GetDonor3FeatVects(mol.GetConformer(confId),
    203                                                         aids,scale=1.0)
    204        elif family=='Acceptor':
    205          aids = feat.GetAtomIds()
    206          if len(aids)==1:
    207            featAtom=mol.GetAtomWithIdx(aids[0])
    208            hvyNbrs=[x for x in featAtom.GetNeighbors() if x.GetAtomicNum()!=1]
    209            if len(hvyNbrs)==1:
    210              ps,fType = FeatDirUtils.GetAcceptor1FeatVects(mol.GetConformer(confId),
    211                                                            aids,scale=1.0)
    212            elif len(hvyNbrs)==2:
    213              ps,fType = FeatDirUtils.GetAcceptor2FeatVects(mol.GetConformer(confId),
    214                                                         aids,scale=1.0)
    215            elif len(hvyNbrs)==3:
    216              ps,fType = FeatDirUtils.GetAcceptor3FeatVects(mol.GetConformer(confId),
    217                                                         aids,scale=1.0)
    218
    219        for tail,head in ps:
    220          ShowArrow(viewer,tail,head,radius,color,dirLabel,
    221                    transparency=transparency,includeArrowhead=includeArrowheads)
    222          if featMapFile:
    223            vect = head-tail
    224            print >>featMapFile,'dir=(%.3f,%.3f,%.3f)'%(vect.x,vect.y,vect.z),
    225
    226      if featMapFile:
    227        aidText = ' '.join([str(x+1) for x in feat.GetAtomIds()])
    228        print >>featMapFile,'# %s'%(aidText)
    229
    230
    231
    232
    233  # --- ----  --- ----  --- ----  --- ----  --- ----  --- ----
    234  import sys,os,getopt
    235  from rdkit import RDConfig
    236  from optparse import OptionParser
    237  parser=OptionParser(_usage,version='%prog '+_version)
    238
    239  parser.add_option('-x','--exclude',default='',
    240                    help='provide a list of feature names that should be excluded')
    241  parser.add_option('-f','--fdef',default=os.path.join(RDConfig.RDDataDir,'BaseFeatures.fdef'),
    242                    help='provide the name of the feature definition (fdef) file.')
    243  parser.add_option('--noDirs','--nodirs',dest='useDirs',default=True,action='store_false',
    244                    help='do not draw feature direction indicators')
    245  parser.add_option('--noHeads',dest='includeArrowheads',default=True,action='store_false',
    246                    help='do not draw arrowheads on the feature direction indicators')
    247  parser.add_option('--noClear','--noClear',dest='clearAll',default=False,action='store_true',
    248                    help='do not clear PyMol on startup')
    249  parser.add_option('--noMols','--nomols',default=False,action='store_true',
    250                    help='do not draw the molecules')
    251  parser.add_option('--writeFeats','--write',default=False,action='store_true',
    252                    help='print the feature information to the console')
    253  parser.add_option('--featMapFile','--mapFile',default='',
    254                    help='save a feature map definition to the specified file')
    255  parser.add_option('--verbose',default=False,action='store_true',
    256                    help='be verbose')
    257
    258  if __name__=='__main__':
    259    from rdkit import Chem
    260    from rdkit.Chem import AllChem
    261    from rdkit.Chem.PyMol import MolViewer
    262
    263    options,args = parser.parse_args()
    264    if len(args)<1:
    265      parser.error('please provide either at least one sd or mol file')
    266
    267    try:
    268      v = MolViewer()
    269    except:
    270      logger.error('Unable to connect to PyMol server.\nPlease run ~landrgr1/extern/PyMol/launch.sh to start it.')
    271      sys.exit(1)
    272    if options.clearAll:
    273      v.DeleteAll()
    274
    275
    276    try:
    277      fdef = file(options.fdef,'r').read()
    278    except IOError:
    279      logger.error('ERROR: Could not open fdef file %s'%options.fdef)
    280      sys.exit(1)
    281
    282    factory = AllChem.BuildFeatureFactoryFromString(fdef)
    283
    284    if options.writeFeats:
    285       print '# Family   \tX    \tY   \tZ   \tRadius\t # Atom_ids'
    286
    287    if options.featMapFile:
    288      if options.featMapFile=='-':
    289        options.featMapFile=sys.stdout
    290      else:
    291        options.featMapFile=file(options.featMapFile,'w+')
    292      print >>options.featMapFile,'# Feature map generated by ShowFeats v%s'%_version
    293      print >>options.featMapFile,"ScoreMode=All"
    294      print >>options.featMapFile,"DirScoreMode=Ignore"
    295      print >>options.featMapFile,"BeginParams"
    296      for family in factory.GetFeatureFamilies():
    297        print >>options.featMapFile,"   family=%s width=1.0 radius=3.0"%family
    298      print >>options.featMapFile,"EndParams"
    299      print >>options.featMapFile,"BeginPoints"
    300
    301    i = 1
    302    for midx,molN in enumerate(args):
    303      if molN!='-':
    304        featLabel='%s_Feats'%molN
    305      else:
    306        featLabel='Mol%d_Feats'%(midx+1)
    307
    308      v.server.resetCGO(featLabel)
    309      # this is a big of kludgery to work around what seems to be a pymol cgo bug:
    310      v.server.sphere((0,0,0),.01,(1,0,1),featLabel)
    311      dirLabel=featLabel+"-dirs"
    312
    313      v.server.resetCGO(dirLabel)
    314      # this is a big of kludgery to work around what seems to be a pymol cgo bug:
    315      v.server.cylinder((0,0,0),(.01,.01,.01),.01,(1,0,1),dirLabel)
    316
    317      if molN != '-':
    318        try:
    319          ms = Chem.SDMolSupplier(molN)
    320        except:
    321          logger.error('Problems reading input file: %s'%molN)
    322          ms = []
    323      else:
    324        ms = Chem.SDMolSupplier()
    325        ms.SetData(sys.stdin.read())
    326
    327      for m in ms:
    328        nm = 'Mol_%d'%(i)
    329        if m.HasProp('_Name'):
    330          nm += '_'+m.GetProp('_Name')
    331        if options.verbose:
    332          if m.HasProp('_Name'):
    333            print "#Molecule: %s"%m.GetProp('_Name')
    334          else:
    335            print "#Molecule: %s"%nm
    336        ShowMolFeats(m,factory,v,transparency=0.25,excludeTypes=options.exclude,name=nm,
    337                     showOnly=False,
    338                     useFeatDirs=options.useDirs,
    339                     featLabel=featLabel,dirLabel=dirLabel,
    340                     includeArrowheads=options.includeArrowheads,
    341                     writeFeats=options.writeFeats,showMol=not options.noMols,
    342                     featMapFile=options.featMapFile)
    343        i += 1
    344        if not i%100:
    345          logger.info("Done %d poses"%i)
    346      if ms:
    347        v.server.renderCGO(_globalSphereCGO,featLabel,1)
    348        if options.useDirs:
    349          v.server.renderCGO(_globalArrowCGO,dirLabel,1)
    350
    351    if options.featMapFile:
    352      print >>options.featMapFile,"EndPoints"
    353
    354
    355    sys.exit(0)
    356