Package rdkit :: Package Chem :: Package Draw :: Module MolDrawing
[hide private]
[frames] | no frames]

Source Code for Module rdkit.Chem.Draw.MolDrawing

  1  # $Id$ 
  2  # 
  3  #  Copyright (C) 2008-2011 Greg Landrum 
  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  from rdkit import Chem 
 12  from rdkit import RDConfig 
 13  import numpy 
 14  import math 
 15  import sys 
 16  import copy 
 17  import pprint 
 18  from rdkit.six import cmp 
 19   
 20  periodicTable=Chem.GetPeriodicTable() 
 21   
22 -class Font(object):
23 face='sans' 24 size='12' 25 weight='normal' 26 name=None
27 - def __init__(self,face=None,size=None,name=None,weight=None):
28 if face: self.face=face 29 if size: self.size=size 30 if name: self.name=name 31 if weight: self.weight=weight
32
33 -class DrawingOptions(object):
34 dotsPerAngstrom= 30 35 useFraction= 0.85 36 37 atomLabelFontFace= "sans" 38 atomLabelFontSize= 12 39 atomLabelMinFontSize= 7 40 41 bondLineWidth= 1.2 42 dblBondOffset= .25 43 dblBondLengthFrac= .8 44 45 defaultColor= (1,0,0) 46 selectColor= (1,0,0) 47 bgColor = (1,1,1) 48 49 colorBonds= True 50 noCarbonSymbols= True 51 includeAtomNumbers= False 52 atomNumberOffset= 0 53 radicalSymbol= u'\u2219' 54 55 dash= (4,4) 56 57 wedgeDashedBonds= True 58 showUnknownDoubleBonds= True 59 60 # used to adjust overall scaling for molecules that have been laid out with non-standard 61 # bond lengths 62 coordScale= 1.0 63 64 elemDict={ 65 1:(0.55,0.55,0.55), 66 7:(0,0,1), 67 8:(1,0,0), 68 9:(.2,.8,.8), 69 15:(1,.5,0), 70 16:(.8,.8,0), 71 17:(0,.8,0), 72 35:(.5,.3,.1), 73 53:(.63,.12,.94), 74 0:(.5,.5,.5), 75 }
76
77 -class MolDrawing(object):
78 atomPs = None 79 canvas = None 80 canvasSize = None 81
82 - def __init__(self,canvas=None, drawingOptions=None):
83 self.canvas = canvas 84 if canvas: 85 self.canvasSize=canvas.size 86 self.atomPs = {} 87 if drawingOptions is None: 88 self.drawingOptions=DrawingOptions() 89 else: 90 self.drawingOptions=drawingOptions 91 self.boundingBoxes = {} 92 93 if self.drawingOptions.bgColor is not None: 94 self.canvas.addCanvasPolygon(((0,0), 95 (canvas.size[0],0), 96 (canvas.size[0],canvas.size[1]), 97 (0,canvas.size[1])), 98 color=self.drawingOptions.bgColor, 99 fill=True,stroke=False)
100 101
102 - def transformPoint(self,pos):
103 res = [0,0] 104 res[0] = (pos[0] + self.molTrans[0])*self.currDotsPerAngstrom*self.drawingOptions.useFraction + self.drawingTrans[0] 105 res[1] = self.canvasSize[1]-((pos[1] + self.molTrans[1])*self.currDotsPerAngstrom*self.drawingOptions.useFraction + \ 106 self.drawingTrans[1]) 107 return res
108 109
110 - def _getBondOffset(self,p1,p2):
111 # get the vector between the points: 112 dx = p2[0]-p1[0] 113 dy = p2[1]-p1[1] 114 115 # figure out the angle and the perpendicular: 116 ang = math.atan2(dy,dx) 117 perp = ang + math.pi/2. 118 119 # here's the offset for the parallel bond: 120 offsetX = math.cos(perp)*self.drawingOptions.dblBondOffset*self.currDotsPerAngstrom 121 offsetY = math.sin(perp)*self.drawingOptions.dblBondOffset*self.currDotsPerAngstrom 122 123 return perp,offsetX,offsetY
124
125 - def _getOffsetBondPts(self,p1,p2, 126 offsetX,offsetY, 127 lenFrac=None):
128 if not lenFrac: 129 lenFrac = self.drawingOptions.dblBondLengthFrac 130 131 dx = p2[0]-p1[0] 132 dy = p2[1]-p1[1] 133 # ---- 134 # now figure out where to start and end it: 135 136 # offset the start point: 137 fracP1 = p1[0]+offsetX,p1[1]+offsetY 138 139 # now move a portion of the way along the line to the neighbor: 140 frac = (1.-lenFrac)/2 141 fracP1 = fracP1[0]+dx*frac,\ 142 fracP1[1]+dy*frac 143 144 fracP2 = fracP1[0]+dx*lenFrac,\ 145 fracP1[1]+dy*lenFrac 146 return fracP1,fracP2
147
148 - def _offsetDblBond(self,p1,p2,bond,a1,a2,conf,dir=1, 149 lenFrac=None):
150 perp,offsetX,offsetY = self._getBondOffset(p1,p2) 151 offsetX = offsetX*dir 152 offsetY = offsetY*dir 153 154 # if we're a ring bond, we may need to flip over to the other side: 155 if bond.IsInRing(): 156 bondIdx = bond.GetIdx() 157 a1Idx = a1.GetIdx() 158 a2Idx = a2.GetIdx() 159 # find a ring bond from a1 to an atom other than a2: 160 for otherBond in a1.GetBonds(): 161 if otherBond.GetIdx()!=bondIdx and \ 162 otherBond.IsInRing(): 163 sharedRing=False 164 for ring in self.bondRings: 165 if bondIdx in ring and otherBond.GetIdx() in ring: 166 sharedRing=True 167 break 168 if not sharedRing: 169 continue 170 a3 = otherBond.GetOtherAtom(a1) 171 if a3.GetIdx() != a2Idx: 172 p3 = self.transformPoint(conf.GetAtomPosition(a3.GetIdx())*self.drawingOptions.coordScale) 173 dx2 = p3[0] - p1[0] 174 dy2 = p3[1] - p1[1] 175 dotP = dx2*offsetX + dy2*offsetY 176 if dotP < 0: 177 perp += math.pi 178 offsetX = math.cos(perp)*self.drawingOptions.dblBondOffset*self.currDotsPerAngstrom 179 offsetY = math.sin(perp)*self.drawingOptions.dblBondOffset*self.currDotsPerAngstrom 180 181 fracP1,fracP2 = self._getOffsetBondPts(p1,p2, 182 offsetX,offsetY, 183 lenFrac=lenFrac) 184 return fracP1,fracP2
185
186 - def _getBondAttachmentCoordinates(self, p1, p2, labelSize):
187 newpos = [None, None] 188 if labelSize != None: 189 labelSizeOffset = [labelSize[0][0]/2 + (cmp(p2[0], p1[0]) * labelSize[0][2]), labelSize[0][1]/2] 190 if p1[1] == p2[1]: 191 newpos[0] = p1[0] + cmp(p2[0], p1[0]) * labelSizeOffset[0] 192 else: 193 if abs(labelSizeOffset[1] * (p2[0] - p1[0]) / (p2[1] - p1[1])) < labelSizeOffset[0]: 194 newpos[0] = p1[0] + cmp(p2[0], p1[0]) * abs(labelSizeOffset[1] * (p2[0] - p1[0]) / (p2[1] - p1[1])) 195 else: 196 newpos[0] = p1[0] + cmp(p2[0], p1[0]) * labelSizeOffset[0] 197 if p1[0] == p2[0]: 198 newpos[1] = p1[1] + cmp(p2[1], p1[1]) * labelSizeOffset[1] 199 else: 200 if abs(labelSizeOffset[0] * (p1[1] - p2[1]) / (p2[0] - p1[0])) < labelSizeOffset[1]: 201 newpos[1] = p1[1] + cmp(p2[1], p1[1]) * abs(labelSizeOffset[0] * (p1[1] - p2[1]) / (p2[0] - p1[0])) 202 else: 203 newpos[1] = p1[1] + cmp(p2[1], p1[1]) * labelSizeOffset[1] 204 else: 205 newpos = copy.deepcopy(p1) 206 return newpos
207
208 - def _drawWedgedBond(self,bond,pos,nbrPos, 209 width=None,color=None, 210 dash=None):
211 if width is None: 212 width = self.drawingOptions.bondLineWidth 213 if color is None: 214 color = self.drawingOptions.defaultColor 215 perp,offsetX,offsetY = self._getBondOffset(pos,nbrPos) 216 offsetX *=.75 217 offsetY *=.75 218 poly = ((pos[0],pos[1]), 219 (nbrPos[0]+offsetX,nbrPos[1]+offsetY), 220 (nbrPos[0]-offsetX,nbrPos[1]-offsetY)) 221 #canvas.drawPolygon(poly,edgeColor=color,edgeWidth=1,fillColor=color,closed=1) 222 if not dash: 223 self.canvas.addCanvasPolygon(poly,color=color) 224 elif self.drawingOptions.wedgeDashedBonds and self.canvas.addCanvasDashedWedge: 225 self.canvas.addCanvasDashedWedge(poly[0],poly[1],poly[2],color=color) 226 else: 227 self.canvas.addCanvasLine(pos,nbrPos,linewidth=width*2,color=color, 228 dashes=dash)
229
230 - def _drawBond(self,bond,atom,nbr,pos,nbrPos,conf, 231 width=None,color=None,color2=None,labelSize1=None,labelSize2=None):
232 if width is None: 233 width = self.drawingOptions.bondLineWidth 234 if color is None: 235 color = self.drawingOptions.defaultColor 236 p1_raw = copy.deepcopy(pos) 237 p2_raw = copy.deepcopy(nbrPos) 238 newpos = self._getBondAttachmentCoordinates(p1_raw, p2_raw, labelSize1) 239 newnbrPos = self._getBondAttachmentCoordinates(p2_raw, p1_raw, labelSize2) 240 bType=bond.GetBondType() 241 if bType == Chem.BondType.SINGLE: 242 bDir = bond.GetBondDir() 243 if bDir in (Chem.BondDir.BEGINWEDGE,Chem.BondDir.BEGINDASH): 244 # if the bond is "backwards", change the drawing direction: 245 if bond.GetBeginAtom().GetChiralTag() in (Chem.ChiralType.CHI_TETRAHEDRAL_CW, 246 Chem.ChiralType.CHI_TETRAHEDRAL_CCW): 247 p1,p2 = newpos,newnbrPos 248 wcolor=color 249 else: 250 p2,p1 = newpos,newnbrPos 251 if color2 is not None: 252 wcolor=color2 253 else: 254 wcolor=self.drawingOptions.defaultColor 255 if bDir==Chem.BondDir.BEGINWEDGE: 256 self._drawWedgedBond(bond,p1,p2,color=wcolor,width=width) 257 elif bDir==Chem.BondDir.BEGINDASH: 258 self._drawWedgedBond(bond,p1,p2,color=wcolor,width=width, 259 dash=self.drawingOptions.dash) 260 261 else: 262 self.canvas.addCanvasLine(newpos, newnbrPos, linewidth=width, color=color, color2=color2) 263 elif bType == Chem.BondType.DOUBLE: 264 crossBond = (self.drawingOptions.showUnknownDoubleBonds and \ 265 bond.GetStereo() == Chem.BondStereo.STEREOANY) 266 if not crossBond and \ 267 ( bond.IsInRing() or (atom.GetDegree()!=1 and bond.GetOtherAtom(atom).GetDegree()!=1) ): 268 self.canvas.addCanvasLine(newpos,newnbrPos,linewidth=width,color=color,color2=color2) 269 fp1,fp2 = self._offsetDblBond(newpos,newnbrPos,bond,atom,nbr,conf) 270 self.canvas.addCanvasLine(fp1,fp2,linewidth=width,color=color,color2=color2) 271 else: 272 fp1,fp2 = self._offsetDblBond(newpos,newnbrPos,bond,atom,nbr,conf,dir=.5, 273 lenFrac=1.0) 274 fp3,fp4 = self._offsetDblBond(newpos,newnbrPos,bond,atom,nbr,conf,dir=-.5, 275 lenFrac=1.0) 276 if crossBond: 277 fp2,fp4=fp4,fp2 278 self.canvas.addCanvasLine(fp1,fp2,linewidth=width,color=color,color2=color2) 279 self.canvas.addCanvasLine(fp3,fp4,linewidth=width,color=color,color2=color2) 280 281 elif bType == Chem.BondType.AROMATIC: 282 self.canvas.addCanvasLine(newpos,newnbrPos,linewidth=width,color=color,color2=color2) 283 fp1,fp2 = self._offsetDblBond(newpos,newnbrPos,bond,atom,nbr,conf) 284 self.canvas.addCanvasLine(fp1,fp2,linewidth=width,color=color,color2=color2, 285 dash=self.drawingOptions.dash) 286 elif bType == Chem.BondType.TRIPLE: 287 self.canvas.addCanvasLine(newpos,newnbrPos,linewidth=width,color=color,color2=color2) 288 fp1,fp2 = self._offsetDblBond(newpos,newnbrPos,bond,atom,nbr,conf) 289 self.canvas.addCanvasLine(fp1,fp2,linewidth=width,color=color,color2=color2) 290 fp1,fp2 = self._offsetDblBond(newpos,newnbrPos,bond,atom,nbr,conf,dir=-1) 291 self.canvas.addCanvasLine(fp1,fp2,linewidth=width,color=color,color2=color2) 292 else: 293 self.canvas.addCanvasLine(newpos, newnbrPos, linewidth=width, color=color, color2=color2, 294 dash=(1,2))
295
296 - def scaleAndCenter(self,mol,conf,coordCenter=False,canvasSize=None,ignoreHs=False):
297 if canvasSize is None: 298 canvasSize=self.canvasSize 299 xAccum = 0 300 yAccum = 0 301 minX = 1e8 302 minY = 1e8 303 maxX = -1e8 304 maxY = -1e8 305 306 nAts = mol.GetNumAtoms() 307 for i in range(nAts): 308 if ignoreHs and mol.GetAtomWithIdx(i).GetAtomicNum()==1: continue 309 pos = conf.GetAtomPosition(i)*self.drawingOptions.coordScale 310 xAccum += pos[0] 311 yAccum += pos[1] 312 minX = min(minX,pos[0]) 313 minY = min(minY,pos[1]) 314 maxX = max(maxX,pos[0]) 315 maxY = max(maxY,pos[1]) 316 317 dx = abs(maxX-minX) 318 dy = abs(maxY-minY) 319 xSize = dx*self.currDotsPerAngstrom 320 ySize = dy*self.currDotsPerAngstrom 321 322 if coordCenter: 323 molTrans = -xAccum/nAts,-yAccum/nAts 324 else: 325 molTrans = -(minX+(maxX-minX)/2),-(minY+(maxY-minY)/2) 326 self.molTrans = molTrans 327 328 if xSize>=.95*canvasSize[0]: 329 scale = .9*canvasSize[0]/xSize 330 xSize*=scale 331 ySize*=scale 332 self.currDotsPerAngstrom*=scale 333 self.currAtomLabelFontSize = max(self.currAtomLabelFontSize*scale, 334 self.drawingOptions.atomLabelMinFontSize) 335 if ySize>=.95*canvasSize[1]: 336 scale = .9*canvasSize[1]/ySize 337 xSize*=scale 338 ySize*=scale 339 self.currDotsPerAngstrom*=scale 340 self.currAtomLabelFontSize = max(self.currAtomLabelFontSize*scale, 341 self.drawingOptions.atomLabelMinFontSize) 342 drawingTrans = canvasSize[0]/2,canvasSize[1]/2 343 self.drawingTrans = drawingTrans
344
345 - def _drawLabel(self,label,pos,baseOffset,font,color=None,**kwargs):
346 if color is None: 347 color = self.drawingOptions.defaultColor 348 x1 = pos[0] 349 y1 = pos[1] 350 labelP = x1,y1 351 labelSize = self.canvas.addCanvasText(label,(x1,y1,baseOffset),font,color,**kwargs) 352 return labelSize
353
354 - def AddMol(self,mol,centerIt=True,molTrans=None,drawingTrans=None, 355 highlightAtoms=[],confId=-1,flagCloseContactsDist=2, 356 highlightMap=None, ignoreHs=False,highlightBonds=[],**kwargs):
357 """Set the molecule to be drawn. 358 359 Parameters: 360 hightlightAtoms -- list of atoms to highlight (default []) 361 highlightMap -- dictionary of (atom, color) pairs (default None) 362 363 Notes: 364 - specifying centerIt will cause molTrans and drawingTrans to be ignored 365 """ 366 conf = mol.GetConformer(confId) 367 if 'coordScale' in kwargs: 368 self.drawingOptions.coordScale=kwargs['coordScale'] 369 370 self.currDotsPerAngstrom=self.drawingOptions.dotsPerAngstrom 371 self.currAtomLabelFontSize=self.drawingOptions.atomLabelFontSize 372 if centerIt: 373 self.scaleAndCenter(mol,conf,ignoreHs=ignoreHs) 374 else: 375 if molTrans is None: 376 molTrans = (0,0) 377 self.molTrans = molTrans 378 if drawingTrans is None: 379 drawingTrans = (0,0) 380 self.drawingTrans = drawingTrans 381 382 font = Font(face=self.drawingOptions.atomLabelFontFace,size=self.currAtomLabelFontSize) 383 384 obds=None 385 if not mol.HasProp('_drawingBondsWedged'): 386 # this is going to modify the molecule, get ready to undo that 387 obds=[x.GetBondDir() for x in mol.GetBonds()] 388 Chem.WedgeMolBonds(mol,conf) 389 390 includeAtomNumbers = kwargs.get('includeAtomNumbers',self.drawingOptions.includeAtomNumbers) 391 self.atomPs[mol] = {} 392 self.boundingBoxes[mol] = [0]*4 393 self.activeMol = mol 394 self.bondRings = mol.GetRingInfo().BondRings() 395 labelSizes = {} 396 for atom in mol.GetAtoms(): 397 labelSizes[atom.GetIdx()] = None 398 if ignoreHs and atom.GetAtomicNum()==1: 399 drawAtom=False 400 else: 401 drawAtom=True 402 idx = atom.GetIdx() 403 pos = self.atomPs[mol].get(idx,None) 404 if pos is None: 405 pos = self.transformPoint(conf.GetAtomPosition(idx)*self.drawingOptions.coordScale) 406 self.atomPs[mol][idx] = pos 407 if drawAtom: 408 self.boundingBoxes[mol][0]=min(self.boundingBoxes[mol][0],pos[0]) 409 self.boundingBoxes[mol][1]=min(self.boundingBoxes[mol][1],pos[1]) 410 self.boundingBoxes[mol][2]=max(self.boundingBoxes[mol][2],pos[0]) 411 self.boundingBoxes[mol][3]=max(self.boundingBoxes[mol][3],pos[1]) 412 413 if not drawAtom: continue 414 nbrSum = [0,0] 415 for bond in atom.GetBonds(): 416 nbr = bond.GetOtherAtom(atom) 417 if ignoreHs and nbr.GetAtomicNum()==1: continue 418 nbrIdx = nbr.GetIdx() 419 if nbrIdx > idx: 420 nbrPos = self.atomPs[mol].get(nbrIdx,None) 421 if nbrPos is None: 422 nbrPos = self.transformPoint(conf.GetAtomPosition(nbrIdx)*self.drawingOptions.coordScale) 423 self.atomPs[mol][nbrIdx] = nbrPos 424 self.boundingBoxes[mol][0]=min(self.boundingBoxes[mol][0],nbrPos[0]) 425 self.boundingBoxes[mol][1]=min(self.boundingBoxes[mol][1],nbrPos[1]) 426 self.boundingBoxes[mol][2]=max(self.boundingBoxes[mol][2],nbrPos[0]) 427 self.boundingBoxes[mol][3]=max(self.boundingBoxes[mol][3],nbrPos[1]) 428 429 else: 430 nbrPos = self.atomPs[mol][nbrIdx] 431 nbrSum[0] += nbrPos[0]-pos[0] 432 nbrSum[1] += nbrPos[1]-pos[1] 433 434 iso = atom.GetIsotope() 435 436 labelIt= not self.drawingOptions.noCarbonSymbols or \ 437 atom.GetAtomicNum()!=6 or \ 438 atom.GetFormalCharge()!=0 or \ 439 atom.GetNumRadicalElectrons() or \ 440 includeAtomNumbers or \ 441 iso or \ 442 atom.HasProp('molAtomMapNumber') or \ 443 atom.GetDegree()==0 444 orient='' 445 if labelIt: 446 baseOffset = 0 447 if includeAtomNumbers: 448 symbol = str(atom.GetIdx()) 449 symbolLength = len(symbol) 450 else: 451 base = atom.GetSymbol() 452 symbolLength = len(base) 453 nHs = atom.GetTotalNumHs() 454 if nHs>0: 455 if nHs>1: 456 hs='H<sub>%d</sub>'%nHs 457 symbolLength += 1 + len(str(nHs)) 458 else: 459 hs ='H' 460 symbolLength += 1 461 else: 462 hs = '' 463 chg = atom.GetFormalCharge() 464 if chg!=0: 465 if chg==1: 466 chg = '+' 467 elif chg==-1: 468 chg = '-' 469 elif chg>1: 470 chg = '+%d'%chg 471 elif chg<-1: 472 chg = '-%d'%chg 473 symbolLength += len(chg) 474 else: 475 chg = '' 476 if chg: 477 chg = '<sup>%s</sup>'%chg 478 479 if atom.GetNumRadicalElectrons(): 480 rad = self.drawingOptions.radicalSymbol*atom.GetNumRadicalElectrons() 481 rad = '<sup>%s</sup>'%rad 482 symbolLength += atom.GetNumRadicalElectrons() 483 else: 484 rad = '' 485 486 isotope='' 487 isotopeLength = 0 488 if iso: 489 isotope='<sup>%d</sup>'%atom.GetIsotope() 490 isotopeLength = len(str(atom.GetIsotope())) 491 symbolLength += isotopeLength 492 mapNum='' 493 mapNumLength = 0 494 if atom.HasProp('molAtomMapNumber'): 495 mapNum=':'+atom.GetProp('molAtomMapNumber') 496 mapNumLength = 1 + len(str(atom.GetProp('molAtomMapNumber'))) 497 symbolLength += mapNumLength 498 deg = atom.GetDegree() 499 # This should be done in a better way in the future: 500 # 'baseOffset' should be determined by getting the size of 'isotope' and the size of 'base', or the size of 'mapNum' and the size of 'base' 501 # (depending on 'deg' and 'nbrSum[0]') in order to determine the exact position of the base 502 if deg==0: 503 if periodicTable.GetElementSymbol(atom.GetAtomicNum()) in ('O','S','Se','Te','F','Cl','Br','I','At'): 504 symbol = '%s%s%s%s%s%s'%(hs,isotope,base,chg,rad,mapNum) 505 else: 506 symbol = '%s%s%s%s%s%s'%(isotope,base,hs,chg,rad,mapNum) 507 elif deg>1 or nbrSum[0]<1: 508 symbol = '%s%s%s%s%s%s'%(isotope,base,hs,chg,rad,mapNum) 509 baseOffset = 0.5 - (isotopeLength + len(base) / 2.) / symbolLength 510 else: 511 symbol = '%s%s%s%s%s%s'%(rad,chg,hs,isotope,base,mapNum) 512 baseOffset = -0.5 + (mapNumLength + len(base) / 2.) / symbolLength 513 if deg==1: 514 if abs(nbrSum[1])>1: 515 islope=nbrSum[0]/abs(nbrSum[1]) 516 else: 517 islope=nbrSum[0] 518 if abs(islope)>.3: 519 if islope>0: 520 orient='W' 521 else: 522 orient='E' 523 elif abs(nbrSum[1])>10: 524 if nbrSum[1]>0: 525 orient='N' 526 else : 527 orient='S' 528 else: 529 orient = 'C' 530 if highlightMap and idx in highlightMap: 531 color = highlightMap[idx] 532 elif highlightAtoms and idx in highlightAtoms: 533 color = self.drawingOptions.selectColor 534 else: 535 color = self.drawingOptions.elemDict.get(atom.GetAtomicNum(),(0,0,0)) 536 labelSize = self._drawLabel(symbol, pos, baseOffset, font, color=color,orientation=orient) 537 labelSizes[atom.GetIdx()] = [labelSize, orient] 538 539 for bond in mol.GetBonds(): 540 atom, idx = bond.GetBeginAtom(), bond.GetBeginAtomIdx() 541 nbr, nbrIdx = bond.GetEndAtom(), bond.GetEndAtomIdx() 542 pos = self.atomPs[mol].get(idx,None) 543 nbrPos = self.atomPs[mol].get(nbrIdx,None) 544 if highlightBonds and bond.GetIdx() in highlightBonds: 545 width=2.0*self.drawingOptions.bondLineWidth 546 color = self.drawingOptions.selectColor 547 color2 = self.drawingOptions.selectColor 548 elif highlightAtoms and idx in highlightAtoms and nbrIdx in highlightAtoms: 549 width=2.0*self.drawingOptions.bondLineWidth 550 color = self.drawingOptions.selectColor 551 color2 = self.drawingOptions.selectColor 552 elif highlightMap is not None and idx in highlightMap and nbrIdx in highlightMap: 553 width=2.0*self.drawingOptions.bondLineWidth 554 color = highlightMap[idx] 555 color2 = highlightMap[nbrIdx] 556 else: 557 width=self.drawingOptions.bondLineWidth 558 if self.drawingOptions.colorBonds: 559 color = self.drawingOptions.elemDict.get(atom.GetAtomicNum(),(0,0,0)) 560 color2 = self.drawingOptions.elemDict.get(nbr.GetAtomicNum(),(0,0,0)) 561 else: 562 color = self.drawingOptions.defaultColor 563 color2= color 564 self._drawBond(bond,atom,nbr,pos,nbrPos,conf, 565 color=color,width=width,color2=color2,labelSize1=labelSizes[idx],labelSize2=labelSizes[nbrIdx]) 566 567 # if we modified the bond wedging state, undo those changes now 568 if obds: 569 for i,d in enumerate(obds): 570 mol.GetBondWithIdx(i).SetBondDir(d) 571 572 573 if flagCloseContactsDist>0: 574 tol = flagCloseContactsDist*flagCloseContactsDist 575 for i,atomi in enumerate(mol.GetAtoms()): 576 pi = numpy.array(self.atomPs[mol][i]) 577 for j in range(i+1,mol.GetNumAtoms()): 578 pj = numpy.array(self.atomPs[mol][j]) 579 d = pj-pi 580 dist2 = d[0]*d[0]+d[1]*d[1] 581 if dist2<=tol: 582 self.canvas.addCanvasPolygon(((pi[0]-2*flagCloseContactsDist, 583 pi[1]-2*flagCloseContactsDist), 584 (pi[0]+2*flagCloseContactsDist, 585 pi[1]-2*flagCloseContactsDist), 586 (pi[0]+2*flagCloseContactsDist, 587 pi[1]+2*flagCloseContactsDist), 588 (pi[0]-2*flagCloseContactsDist, 589 pi[1]+2*flagCloseContactsDist)), 590 color=(1.,0,0), 591 fill=False,stroke=True)
592