def draw_molecule(m, node2color, dpa, fontsize): mol = Chem.Mol(m.ToBinary()) rdDepictor.Compute2DCoords(mol, bondLength=-1.0) coords = mol.GetConformer(-1).GetPositions() min_p = Geometry.Point2D(*coords.min(0)[:2] - 1) max_p = Geometry.Point2D(*coords.max(0)[:2] + 1) w = int(dpa * (max_p.x - min_p.x)) + 1 h = int(dpa * (max_p.y - min_p.y)) + 1 Chem.Kekulize(mol) mcs_bonds = [] b_col = [] for i in range(0, len(mol.GetBonds())): bond = mol.GetBondWithIdx(i) beg_h, end_h = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx() if beg_h in node2color and end_h in node2color: mcs_bonds.append(i) b_col.append(max(node2color[beg_h], node2color[end_h])) b_col = dict(zip(mcs_bonds, b_col)) drawer = rdMolDraw2D.MolDraw2DSVG(w, h) drawer.SetScale(w, h, min_p, max_p) drawer.SetFontSize(fontsize) drawer.DrawMolecule( mol, highlightAtoms=list(node2color.keys()), highlightAtomColors=node2color, highlightBonds=mcs_bonds, highlightBondColors=b_col, ) drawer.FinishDrawing() png = drawer.GetDrawingText() return png
def _intersection(self, bondA, bondB): """ True if two bonds collide, false otherwise. Note that false is retrieved even in case the bonds share common atom, as this is not a problem case. Cramer's rule is used for the linear equations system. Args: bondA (rdkit.Chem.rdchem.Bond): this bond bondB (rdkit.Chem.rdchem.Bond): other bond Returns: bool: true if bonds share collide, false otherwise. """ atoms = [ bondA.GetBeginAtom(), bondA.GetEndAtom(), bondB.GetBeginAtom(), bondB.GetEndAtom() ] names = [a.GetProp('name') for a in atoms] points = [self.conformer.GetAtomPosition(a.GetIdx()) for a in atoms] vecA = Geometry.Point2D(points[1].x - points[0].x, points[1].y - points[0].y) vecB = Geometry.Point2D(points[3].x - points[2].x, points[3].y - points[2].y) # we need to set up directions of the vectors properly in case # there is a common atom. So we identify angles correctly # e.g. B -> A; B -> C and not A -> B; C -> B. if len(set(names)) == 3: angle = self.__get_angle(names, vecA, vecB) return angle < 10.0 # Cramer's rule to identify intersection det = vecA.x * -vecB.y + vecA.y * vecB.x if round(det, 2) == 0.00: return False a = points[2].x - points[0].x b = points[2].y - points[0].y detP = (a * -vecB.y) - (b * -vecB.x) p = round(detP / det, 3) if (p < 0 or p > 1): return False detR = (vecA.x * b) - (vecA.y * a) r = round(detR / det, 3) if 0 <= r <= 1: return True return False
def testGithub4838(self): m = Chem.MolFromSmiles("CCCC") d2d = Draw.MolDraw2DSVG(300, 300) d2d.DrawMolecule(m) d2d.DrawString("foo1", Geometry.Point2D(1, 0)) d2d.DrawString("foo0", Geometry.Point2D(1, 1), 0) d2d.DrawString("foo2", Geometry.Point2D(1, 2), 1) d2d.DrawString("foo3", Geometry.Point2D(1, 3), 2) with self.assertRaises(ValueError): d2d.DrawString("fail", Geometry.Point2D(1, 4), 3)
def draw_mols(x_list: list, y_list: list, names: list): error_names = [] error = [] for x, y, name in zip(x_list, y_list, names): e = abs(float(x) - float(y)) if e > 10: error_names.append(name) error.append(e) ps = rdFMCS.MCSParameters() ps.AtomCompareParameters.RingMatchesRingOnly = True ps.SetAtomTyper(rdFMCS.AtomCompare.CompareAny) for name in error_names: mol1, mol2 = ( Chem.MolFromSmiles(exp_results[name]["t1-smiles"]), Chem.MolFromSmiles(exp_results[name]["t2-smiles"]), ) mcs = Chem.MolFromSmarts( rdFMCS.FindMCS( [mol1, mol2], bondCompare=Chem.rdFMCS.BondCompare.CompareOrder.CompareAny, ).smartsString) AllChem.Compute2DCoords(mol1) match1 = mol1.GetSubstructMatch(mcs) match2 = mol2.GetSubstructMatch(mcs) coords = [mol1.GetConformer().GetAtomPosition(x) for x in match1] coords2D = [Geometry.Point2D(pt.x, pt.y) for pt in coords] coordDict = {} for i, coord in enumerate(coords2D): coordDict[match2[i]] = coord AllChem.Compute2DCoords(mol2, coordMap=coordDict) Draw.MolsToGridImage([mol1, mol2], subImgSize=(250, 250), molsPerRow=2)
def test2Coords(self): m1 = Chem.MolFromSmiles('C1CCC1CC') coordMap = {0: Geometry.Point2D(0, 0), 1: Geometry.Point2D(1.5, 0), 2: Geometry.Point2D(1.5, 1.5), 3: Geometry.Point2D(0, 1.5)} rdDepictor.Compute2DCoords(m1, coordMap=coordMap) conf = m1.GetConformer(0) for i in range(4): self.assertTrue( ptEq(conf.GetAtomPosition(i), Geometry.Point3D(coordMap[i].x, coordMap[i].y, 0.0))) m1 = Chem.MolFromSmiles('CCC') try: rdDepictor.Compute2DCoords(m1, coordMap=coordMap) ok = 0 except ValueError: ok = 1 self.assertTrue(ok)
def testGetDrawCoords(self): m = Chem.MolFromSmiles('c1ccc(C)c(C)c1C') AllChem.Compute2DCoords(m) d = Draw.MolDraw2DSVG(300, 300) d.DrawMolecule(m) conf = m.GetConformer() for idx in range(m.GetNumAtoms()): pos = conf.GetAtomPosition(idx) pos = Geometry.Point2D(pos.x, pos.y) dpos1 = d.GetDrawCoords(idx) dpos2 = d.GetDrawCoords(pos) self.assertAlmostEqual(dpos1.x, dpos2.x, 6) self.assertAlmostEqual(dpos1.y, dpos2.y, 6)
def testExtraDrawingCommands(self): " this is another test just to make sure that things work " m = Chem.MolFromMolBlock(""" Mrv1810 07271915232D 6 6 0 0 0 0 999 V2000 -1.5 -1.5 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.5 0.0 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 0.0 -1.5 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -1.5 1.5 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1.5 -1.5 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 2 3 1 0 0 0 0 3 4 1 0 0 0 0 4 1 1 0 0 0 0 2 5 1 0 0 0 0 4 6 1 0 0 0 0 M END """) d = Draw.MolDraw2DSVG(300, 300) dm = Draw.PrepareMolForDrawing(m) d.DrawMolecule(dm) conf = dm.GetConformer() ps3 = ( conf.GetAtomPosition(0), conf.GetAtomPosition(1), conf.GetAtomPosition(3), ) ps = [Geometry.Point2D(p.x, p.y) for p in ps3] d.DrawPolygon(ps) d.DrawArrow(Geometry.Point2D(0, 0), Geometry.Point2D(0, 1.5)) d.DrawAttachmentLine(Geometry.Point2D(0, 0), Geometry.Point2D(1.5, 0), (0.5, 0.5, 0.5), len=0.5) d.DrawLine(Geometry.Point2D(0, 0), Geometry.Point2D(1.5, 0)) d.DrawWavyLine(Geometry.Point2D(0, 0), Geometry.Point2D(1.5, 1.5), (0, 0, 0), (1, 0.2, 0.2)) d.FinishDrawing() txt = d.GetDrawingText() with open("extras_1.svg", "w+") as outf: outf.write(txt)
def _colorfill_rings(self, highlights): """Fill the rings in self.rings with the color requested.""" if self.fill_rings and self.rings: # Set the molecule scale self.canvas.DrawMoleculeWithHighlights(self.draw_mol, "", *highlights) self.canvas.ClearDrawing() canvas_options = self.canvas.drawOptions() conf = self.draw_mol.GetConformer() for (ring, color) in self.rings: ps = [Geometry.Point2D(conf.GetAtomPosition(_)) for _ in ring] self.canvas.SetFillPolys(True) self.canvas.SetColour(color) self.canvas.DrawPolygon(ps) canvas_options.clearBackground = False
def __arrange_by_scaffolds__(self, align_by_scaffold=True): self.scaffold2indexes = {} self.scaffold2rdmol = {} self.index2scaffold = {} for index, rdmol in self.index2rdmol.items(): AllChem.Compute2DCoords(rdmol) if align_by_scaffold: scaffold = Scaffolds.MurckoScaffold.GetScaffoldForMol(rdmol) AllChem.Compute2DCoords(scaffold) scaffold_smiles = Chem.MolToSmiles(scaffold) self.scaffold2rdmol[scaffold_smiles] = scaffold matched = rdmol.GetSubstructMatch(scaffold) coords = [rdmol.GetConformer().GetAtomPosition(x) for x in matched] coords2D = [Geometry.Point2D(pt.x,pt.y) for pt in coords] coordDict = {} for i,coord in enumerate(coords2D): coordDict[matched[i]] = coord AllChem.Compute2DCoords(rdmol, coordMap=coordDict) if scaffold_smiles in self.scaffold2indexes: self.scaffold2indexes[scaffold_smiles].append(index) else: self.scaffold2indexes[scaffold_smiles] = [index] self.scaffold2indexes = {scaffold: indexes for scaffold, indexes in self.scaffold2indexes.items() if len(indexes) > 1} for index, scaffold in enumerate(self.scaffold2indexes.keys(), len(self.index_order)): self.index2scaffold[index] = scaffold self.index2rdmol[index] = self.scaffold2rdmol[scaffold] self.index_order.append(index) self.edges = [] self.index2edges = {} for index_1, scaffold in self.index2scaffold.items(): self.index2edges[index_1] = [] for index_2 in self.scaffold2indexes[scaffold]: self.edges.append((index_1, index_2)) self.index2edges[index_1].append(index_2) self.__add_scaffolds_to_chemical_space__()
def test_template1(self): template = Chem.MolFromSmiles('C1OCOCOCOCCCNCCC1') template.SetProp("_Name",'template') mol = Chem.MolFromSmiles('C1OCOCOCOCCCNC(OC(=O)C2CC2)CC1') mol.SetProp("_Name","mol") rdCoordGen.AddCoords(template) rdCoordGen.AddCoords(mol) self.assertFalse(compareConfs(mol.GetConformer(),template.GetConformer(),mol.GetSubstructMatch(template))) match = mol.GetSubstructMatch(template) mapd = dict() for i,aid in enumerate(match): p = template.GetConformer().GetAtomPosition(i) mapd[aid] = Geometry.Point2D(p.x,p.y) ps = rdCoordGen.CoordGenParams() ps.SetCoordMap(mapd) ps.dbg_useFixed = True rdCoordGen.AddCoords(mol,ps) self.assertTrue(compareConfs(mol.GetConformer(),template.GetConformer(),mol.GetSubstructMatch(template)))
def AlignDepict(mol, core, corePattern=None, acceptFailure=False): """ Arguments: - mol: the molecule to be aligned, this will come back with a single conformer. - core: a molecule with the core atoms to align to; this should have a depiction. - corePattern: (optional) an optional molecule to be used to generate the atom mapping between the molecule and the core. """ if core and corePattern: if not core.GetNumAtoms(onlyExplicit=True) == corePattern.GetNumAtoms( onlyExplicit=True): raise ValueError( 'When a pattern is provided, it must have the same number of atoms as the core' ) coreMatch = core.GetSubstructMatch(corePattern) if not coreMatch: raise ValueError("Core does not map to itself") else: coreMatch = range(core.GetNumAtoms(onlyExplicit=True)) if corePattern: match = mol.GetSubstructMatch(corePattern) else: match = mol.GetSubstructMatch(core) if not match: if not acceptFailure: raise ValueError('Substructure match with core not found.') else: coordMap = {} else: conf = core.GetConformer() coordMap = {} for i, idx in enumerate(match): pt3 = conf.GetAtomPosition(coreMatch[i]) pt2 = Geometry.Point2D(pt3.x, pt3.y) coordMap[idx] = pt2 rdDepictor.Compute2DCoords(mol, clearConfs=True, coordMap=coordMap, canonOrient=False)
def testMolContours(self): m = Chem.MolFromSmiles("C1N[C@@H]2OCC12") dm = Draw.PrepareMolForDrawing(m) conf = dm.GetConformer() gs = [] ws = [] hs = [] for i in range(conf.GetNumAtoms()): p = conf.GetAtomPosition(i) p2 = Geometry.Point2D(p.x, p.y) gs.append(p2) hs.append(0.4) if not i % 2: ws.append(-0.5) else: ws.append(1) d = Draw.MolDraw2DSVG(300, 300) d.ClearDrawing() Draw.ContourAndDrawGaussians(d, gs, hs, ws, mol=dm) d.drawOptions().clearBackground = False d.DrawMolecule(dm) d.FinishDrawing() txt = d.GetDrawingText() with open("contour_from_py_1.svg", 'w+') as outf: print(txt, file=outf) d = Draw.MolDraw2DSVG(300, 300) d.ClearDrawing() ps = Draw.ContourParams() ps.fillGrid = True Draw.ContourAndDrawGaussians(d, gs, hs, ws, params=ps, mol=dm) d.drawOptions().clearBackground = False d.DrawMolecule(dm) d.FinishDrawing() txt = d.GetDrawingText() with open("contour_from_py_2.svg", 'w+') as outf: print(txt, file=outf)
def main(self): settings = self.settings SMILESSTRING = settings['SMILESSTRING'] resulting_plots = [] pRList = [] mol_svg, d2d, dm = self.draw_smiles() replace_index = [] for scope_plot in self.plots: # for each scope plot, make a vals list containing empty first items for the wedge with alpha=0 if type(scope_plot) != dict: continue sizes = [ 360 - scope_plot['coverangle_wedges'] ] + [scope_plot['coverangle_wedges'] / scope_plot['no_wedges'] ] * scope_plot['no_wedges'] label_inner_circle, label_outer_circle = [ '' ] + [''] * scope_plot['no_wedges'], [ '' ] + [''] * scope_plot['no_wedges'] if (len(scope_plot['value_inner_circle']) != scope_plot['no_wedges'] or len(scope_plot['value_outer_circle']) != scope_plot['no_wedges']): print('not equal') value_inner_circle, value_outer_circle = scope_plot[ 'value_inner_circle'], scope_plot['value_outer_circle'] rounding_boundary = scope_plot['rounding_boundary'] value_groups = scope_plot['value_groups'] for i in range(scope_plot['no_wedges']): if scope_plot['rounding']: if value_inner_circle[i] >= rounding_boundary: label_inner_circle[i + 1] = ">" + str( value_inner_circle[i]) else: label_inner_circle[i + 1] = str(value_inner_circle[i]) if value_outer_circle[i] >= rounding_boundary: label_outer_circle[i + 1] = ">" + str( value_outer_circle[i]) else: label_outer_circle[i + 1] = str(value_outer_circle[i]) else: label_inner_circle[i + 1] = str(value_inner_circle[i]) label_outer_circle[i + 1] = str(value_outer_circle[i]) j = 0 for i, item in enumerate(value_groups): if item[0] == '~': replace_index.append(('~' + str(j), item[1:])) value_groups[i] = '~' + str(j) j = j + 1 vals = [ sizes, # size of the wedges, the first wedge is transparent and will not be shown [0] + value_inner_circle, # colormap values for the inner circle, maximum value determines intensity, first is for the transparent wedge and should stay 0 [0] + value_outer_circle, # colormap values for the outer circle, maximum value determines intensity, first is for the transparent wedge and should stay 0 label_inner_circle, #labels for the inner circle label_outer_circle, #labels for the outer circle [""] + value_groups, #groups ] resulting_plots.append( self.plot_figure_and_colorbar(scope_plot, vals)) # get the atom id from the settings and save its position rIdx = scope_plot['attach_atom_id'] pRList.append( d2d.GetDrawCoords( Geometry.Point2D(dm.GetConformer().GetAtomPosition(rIdx)))) # take colorbar from first plot #ToDo extension to multiple colorbars colorbar = compose.Panel( strSVG(resulting_plots[0][1]).scale(0.8).move(-350, 400)) panels = [compose.Panel(strSVG('<svg></svg>'))] * len(resulting_plots) for i, plot in enumerate(resulting_plots): panels[i] = strSVG(resulting_plots[i][0]).move( -369, -358).scale(1).move(pRList[i].x, pRList[i].y) #panels[i]=strSVG(resulting_plots[i][0]).move(-369*1,-358*1).scale(0.4).move(pRList[i].x,pRList[i].y) compose.Figure( "600", "600", #720 default` compose.Panel(strSVG(mol_svg).scale(1).move(0, 0)), colorbar, *panels #).move(350,350).scale(self.settings['scalefactor']).save("substrate_scope.svg") ).move(350, 100).scale( self.settings['scalefactor']).save("substrate_scope.svg") new_svg = SVG('substrate_scope.svg')._data for item in replace_index: new_svg = self.replace_label_with_smiles(svg_file=new_svg, smiles=item[1], search_index=item[0]) if settings['use_bold_font']: new_svg.replace('font-weight:normal', 'font-weight:bold') f = open("substrate_scope_replaced.svg", "w") f.write(new_svg) f.close() print('File written to:', os.getcwd() + '/substrate_scope_replaced.svg')
def _draw_superfeatures(mol, highlight_atoms, highlight_bonds, highlight_radius, highlight_linewidth, rings): """ Draw superfeatures on 2D view of ligand. Use only with _get_superfeatures_drawing_data(). Parameters ---------- mol : rdkit.Chem.rdchem.Mol Molecule. highlight_atoms : collections.defaultdict Atoms to be highlighted. highlight_bonds : collections.defaultdict Bonds to be highlighted. highlight_radius : dict Atom highlight radius. highlight_linewidth : Bond hightlight line width. rings : tuple of tuple Rings to be filled/highlighted. Returns ------- IPython.core.display.Image 2D view of ligand with superfeatures. """ legend = "" width = IMAGE_WIDTH height = IMAGE_HEIGHT d2d = rdMolDraw2D.MolDraw2DCairo(width, height) dos = d2d.drawOptions() dos.useBWAtomPalette() # First draw circles to highlight full rings d2d.DrawMoleculeWithHighlights( mol, legend, dict(highlight_atoms), dict(highlight_bonds), highlight_radius, highlight_linewidth, ) d2d.ClearDrawing() conf = mol.GetConformer() for (ring, color) in rings: positions = [] for atom_idx in ring: position = Geometry.Point2D(conf.GetAtomPosition(atom_idx)) positions.append(position) d2d.SetFillPolys(True) d2d.SetColour(color) d2d.DrawPolygon(positions) dos.clearBackground = False # Now draw on top (again) the molecule with highlighted atoms and bonds d2d.DrawMoleculeWithHighlights( mol, legend, dict(highlight_atoms), dict(highlight_bonds), highlight_radius, highlight_linewidth, ) d2d.FinishDrawing() # Show PNG text as image img = Image(d2d.GetDrawingText()) return img
def AlignMolToTemplate2D( mol, template, match=None, clearConfs=False, templateConfId=-1, ): """ Arguments: - mol: the molecule to be aligned - template: the template to align to - match: If provided, this should be a sequence of integers containing the indices of the atoms in mol that match those in template. This is the result of calling: mol.GetSubstructMatch(template) - clearConfs: toggles removing any existing conformers on mol Returns the confId of the conformer containing the depiction >>> patt = Chem.MolFromSmiles('C1CC1') >>> rdDepictor.Compute2DCoords(patt) 0 >>> mol = Chem.MolFromSmiles('OC1CC1CC1CCC1') >>> rdDepictor.Compute2DCoords(mol) 0 >>> pc = patt.GetConformer(0) >>> mc = mol.GetConformer(0) We start out with the molecules not aligned: >>> vs = [abs(pc.GetAtomPosition(i).x-mc.GetAtomPosition(i+1).x) for i in range(pc.GetNumAtoms())] >>> [x<1e-4 for x in vs] [False, False, False] But then we can replace the conformer of mol: >>> AlignMolToTemplate2D(mol,patt,clearConfs=True) 0 >>> mol.GetNumConformers() 1 >>> pc = patt.GetConformer(0) >>> mc = mol.GetConformer(0) >>> vs = [abs(pc.GetAtomPosition(i).x-mc.GetAtomPosition(i+1).x) for i in range(pc.GetNumAtoms())] >>> [x<1e-4 for x in vs] [True, True, True] If we like, we can specify the atom map explicitly in order to align to the second matching ring in the probe molecule: >>> match = (5,6,7) >>> AlignMolToTemplate2D(mol,patt,clearConfs=True,match=match) 0 >>> mol.GetNumConformers() 1 >>> pc = patt.GetConformer(0) >>> mc = mol.GetConformer(0) >>> vs = [abs(pc.GetAtomPosition(i).x-mc.GetAtomPosition(i+1).x) for i in range(pc.GetNumAtoms())] >>> [x<1e-4 for x in vs] [False, False, False] >>> vs = [abs(pc.GetAtomPosition(i).x-mc.GetAtomPosition(i+5).x) for i in range(pc.GetNumAtoms())] >>> [x<1e-4 for x in vs] [True, True, True] """ if not match: match = mol.GetSubstructMatch(template) if not match: raise ValueError, 'no match between mol and template' atomMap = {} templateConf = template.GetConformer(templateConfId) for i, idx in enumerate(match): p = templateConf.GetAtomPosition(i) atomMap[idx] = Geometry.Point2D(p.x, p.y) molConfId = rdDepictor.Compute2DCoords(mol, clearConfs=clearConfs, coordMap=atomMap) return molConfId
def draw_image(ids, smiles, tsmarts, pActs, Acts, qualifiers, nonadd, target, mcss_tot, image_file): """ Draw Nonadditivity Circle to Image file """ cpds = [Chem.MolFromSmiles(i) for i in smiles] ######### # Compute Coordinates of local MCSS, aligned with global MCSS mcss_loc = Chem.MolFromSmarts( rdFMCS.FindMCS(cpds, completeRingsOnly=True, timeout=10).smartsString) if mcss_tot: mcss_tot_coords = [ mcss_tot.GetConformer().GetAtomPosition(x) for x in range(mcss_tot.GetNumAtoms()) ] coords2D_tot = [Geometry.Point2D(pt.x, pt.y) for pt in mcss_tot_coords] mcss_match = mcss_loc.GetSubstructMatch(mcss_tot) coordDict = {} for i, coord in enumerate(coords2D_tot): coordDict[mcss_match[i]] = coord AllChem.Compute2DCoords(mcss_loc, coordMap=coordDict) else: AllChem.Compute2DCoords(mcss_loc) ######### # Align circle compounds to local MCSS matchVs = [x.GetSubstructMatch(mcss_loc) for x in cpds] # compute reference coordinates: mcss_loc_coords = [ mcss_loc.GetConformer().GetAtomPosition(x) for x in range(mcss_loc.GetNumAtoms()) ] coords2D_loc = [Geometry.Point2D(pt.x, pt.y) for pt in mcss_loc_coords] # generate coords for the other molecules using the common substructure for molIdx in range(4): mol = cpds[molIdx] coordDict = {} for i, coord in enumerate(coords2D_loc): coordDict[matchVs[molIdx][i]] = coord AllChem.Compute2DCoords(mol, coordMap=coordDict) ########## # Assemble Image qualifiers_inv = ["" for i in range(4)] for i in range(4): if qualifiers[i] == ">": qualifiers_inv[i] = "<" elif qualifiers[i] == "<": qualifiers_inv[i] = ">" else: continue new_im = Image.new("RGB", size=(650, 670), color=(255, 255, 255, 0)) if Acts[0] != "": new_im.paste( Draw.MolToImage( cpds[0], size=(300, 300), legend=ids[0] + " " + qualifiers_inv[0] + Acts[0] + " (" + qualifiers[0] + pActs[0] + ")", ), (0, 0), ) new_im.paste( Draw.MolToImage( cpds[1], size=(300, 300), legend=ids[1] + " " + qualifiers_inv[1] + Acts[1] + " (" + qualifiers[1] + pActs[1] + ")", ), (350, 0), ) new_im.paste( Draw.MolToImage( cpds[2], size=(300, 300), legend=ids[2] + " " + qualifiers_inv[2] + Acts[2] + " (" + qualifiers[2] + pActs[2] + ")", ), (350, 350), ) new_im.paste( Draw.MolToImage( cpds[3], size=(300, 300), legend=ids[3] + " " + qualifiers_inv[3] + Acts[3] + " (" + qualifiers[3] + pActs[3] + ")", ), (0, 350), ) draw = ImageDraw.Draw(new_im) draw.text((260, 330), "Nonadditivity: " + nonadd, fill=(0, 0, 0, 0)) draw.text( (10, 650), "[uM] (-log10[M]) Activity in Assay: " + target, fill=(0, 0, 0, 0), ) else: new_im.paste( Draw.MolToImage(cpds[0], size=(300, 300), legend=ids[0] + " " + qualifiers[0] + pActs[0]), (0, 0), ) new_im.paste( Draw.MolToImage(cpds[1], size=(300, 300), legend=ids[1] + " " + qualifiers[1] + pActs[1]), (350, 0), ) new_im.paste( Draw.MolToImage(cpds[2], size=(300, 300), legend=ids[2] + " " + qualifiers[2] + pActs[2]), (350, 350), ) new_im.paste( Draw.MolToImage(cpds[3], size=(300, 300), legend=ids[3] + " " + qualifiers[3] + pActs[3]), (0, 350), ) draw = ImageDraw.Draw(new_im) draw.text((260, 330), "Nonadditivity: " + nonadd, fill=(0, 0, 0, 0)) draw.text((10, 650), "Activity in Assay: " + target, fill=(0, 0, 0, 0)) # Draw Arrows draw.line((300, 150, 350, 150), fill=0, width=2) draw.line((340, 145, 350, 150), fill=0, width=2) draw.line((340, 155, 350, 150), fill=0, width=2) draw.line((300, 500, 350, 500), fill=0, width=2) draw.line((340, 495, 350, 500), fill=0, width=2) draw.line((340, 505, 350, 500), fill=0, width=2) draw.line((150, 300, 150, 350), fill=0, width=2) draw.line((145, 340, 150, 350), fill=0, width=2) draw.line((155, 340, 150, 350), fill=0, width=2) draw.line((500, 300, 500, 350), fill=0, width=2) draw.line((495, 340, 500, 350), fill=0, width=2) draw.line((505, 340, 500, 350), fill=0, width=2) # Add Reaction Parts b = Chem.MolFromSmiles(tsmarts[0][:tsmarts[0].index(">")]) new_im.paste(Draw.MolToImage(b, size=(50, 50)), (300, 90)) b = Chem.MolFromSmiles(tsmarts[0][tsmarts[0].index(">") + 2:]) new_im.paste(Draw.MolToImage(b, size=(50, 50)), (300, 160)) b = Chem.MolFromSmiles(tsmarts[0][:tsmarts[0].index(">")]) new_im.paste(Draw.MolToImage(b, size=(50, 50)), (300, 440)) b = Chem.MolFromSmiles(tsmarts[0][tsmarts[0].index(">") + 2:]) new_im.paste(Draw.MolToImage(b, size=(50, 50)), (300, 510)) b = Chem.MolFromSmiles(tsmarts[1][:tsmarts[1].index(">")]) new_im.paste(Draw.MolToImage(b, size=(50, 50)), (80, 300)) b = Chem.MolFromSmiles(tsmarts[1][tsmarts[1].index(">") + 2:]) new_im.paste(Draw.MolToImage(b, size=(50, 50)), (170, 300)) b = Chem.MolFromSmiles(tsmarts[1][:tsmarts[1].index(">")]) new_im.paste(Draw.MolToImage(b, size=(50, 50)), (430, 300)) b = Chem.MolFromSmiles(tsmarts[1][tsmarts[1].index(">") + 2:]) new_im.paste(Draw.MolToImage(b, size=(50, 50)), (520, 300)) new_im.save(image_file)
def GetSimilarityMapFromWeights(mol, weights, colorMap=None, scale=-1, size=(250, 250), sigma=None, coordScale=1.5, step=0.01, colors='k', contourLines=10, alpha=0.5, draw2d=None, **kwargs): """ Generates the similarity map for a molecule given the atomic weights. Parameters: mol -- the molecule of interest colorMap -- the matplotlib color map scheme, default is custom PiWG color map scale -- the scaling: scale < 0 -> the absolute maximum weight is used as maximum scale scale = double -> this is the maximum scale size -- the size of the figure sigma -- the sigma for the Gaussians coordScale -- scaling factor for the coordinates step -- the step for calcAtomGaussian colors -- color of the contour lines contourLines -- if integer number N: N contour lines are drawn if list(numbers): contour lines at these numbers are drawn alpha -- the alpha blending value for the contour lines kwargs -- additional arguments for drawing """ if mol.GetNumAtoms() < 2: raise ValueError("too few atoms") if draw2d is not None: mol = rdMolDraw2D.PrepareMolForDrawing(mol, addChiralHs=False) if not mol.GetNumConformers(): rdDepictor.Compute2DCoords(mol) if sigma is None: if mol.GetNumBonds() > 0: bond = mol.GetBondWithIdx(0) idx1 = bond.GetBeginAtomIdx() idx2 = bond.GetEndAtomIdx() sigma = 0.3 * ( mol.GetConformer().GetAtomPosition(idx1) - mol.GetConformer().GetAtomPosition(idx2)).Length() else: sigma = 0.3 * (mol.GetConformer().GetAtomPosition(0) - mol.GetConformer().GetAtomPosition(1)).Length() sigma = round(sigma, 2) sigmas = [sigma] * mol.GetNumAtoms() locs = [] for i in range(mol.GetNumAtoms()): p = mol.GetConformer().GetAtomPosition(i) locs.append(Geometry.Point2D(p.x, p.y)) draw2d.ClearDrawing() ps = Draw.ContourParams() ps.fillGrid = True ps.gridResolution = 0.1 ps.extraGridPadding = 0.5 Draw.ContourAndDrawGaussians(draw2d, locs, weights, sigmas, nContours=contourLines, params=ps) draw2d.drawOptions().clearBackground = False draw2d.DrawMolecule(mol) return draw2d fig = Draw.MolToMPL(mol, coordScale=coordScale, size=size, **kwargs) if sigma is None: if mol.GetNumBonds() > 0: bond = mol.GetBondWithIdx(0) idx1 = bond.GetBeginAtomIdx() idx2 = bond.GetEndAtomIdx() sigma = 0.3 * math.sqrt( sum([(mol._atomPs[idx1][i] - mol._atomPs[idx2][i])**2 for i in range(2)])) else: sigma = 0.3 * \ math.sqrt(sum([(mol._atomPs[0][i] - mol._atomPs[1][i])**2 for i in range(2)])) sigma = round(sigma, 2) x, y, z = Draw.calcAtomGaussians(mol, sigma, weights=weights, step=step) # scaling if scale <= 0.0: maxScale = max(math.fabs(numpy.min(z)), math.fabs(numpy.max(z))) else: maxScale = scale # coloring if colorMap is None: if cm is None: raise RuntimeError("matplotlib failed to import") PiYG_cmap = cm.get_cmap('PiYG', 2) colorMap = LinearSegmentedColormap.from_list( 'PiWG', [PiYG_cmap(0), (1.0, 1.0, 1.0), PiYG_cmap(1)], N=255) fig.axes[0].imshow(z, cmap=colorMap, interpolation='bilinear', origin='lower', extent=(0, 1, 0, 1), vmin=-maxScale, vmax=maxScale) # contour lines # only draw them when at least one weight is not zero if len([w for w in weights if w != 0.0]): contourset = fig.axes[0].contour(x, y, z, contourLines, colors=colors, alpha=alpha, **kwargs) for j, c in enumerate(contourset.collections): if contourset.levels[j] == 0.0: c.set_linewidth(0.0) elif contourset.levels[j] < 0: c.set_dashes([(0, (3.0, 3.0))]) fig.axes[0].set_axis_off() return fig