The 2015.03 release of the RDKit will contain a new set of C++-based functionality for drawing molecules. This code, based on a contribution from Dave Cosgrove, is much faster than the current python-based drawing code and provides much more flexibility and higher drawing quality than the current C++ code (which is used in Knime).
This post demonstrates some of the new functionality, which is currently available in the RDKit github repo.
The new code supports rendering to SVG, PNGs (using cairo), Qt, and wx (thanks to a contribution from Igor Filippov). It's pretty easy to add support for other backends as well. Here I'll show the SVG rendering.
from __future__ import print_function
from rdkit import Chem
from rdkit.Chem.Draw import IPythonConsole
from IPython.display import SVG
import time
print(time.asctime())
m = Chem.MolFromSmiles('c1cccnc1O')
from rdkit.Chem import rdDepictor
from rdkit.Chem.Draw import rdMolDraw2D
def moltosvg(mol,molSize=(450,150),kekulize=True):
mc = Chem.Mol(mol.ToBinary())
if kekulize:
try:
Chem.Kekulize(mc)
except:
mc = Chem.Mol(mol.ToBinary())
if not mc.GetNumConformers():
rdDepictor.Compute2DCoords(mc)
drawer = rdMolDraw2D.MolDraw2DSVG(molSize[0],molSize[1])
drawer.DrawMolecule(mc)
drawer.FinishDrawing()
svg = drawer.GetDrawingText()
# It seems that the svg renderer used doesn't quite hit the spec.
# Here are some fixes to make it work in the notebook, although I think
# the underlying issue needs to be resolved at the generation step
return svg.replace('svg:','')
SVG(moltosvg(m))
import glob
pkls = glob.glob('/home/glandrum/Code/benchmarking_platform/compounds/ChEMBL_II/*.pkl')
from rdkit.six.moves import cPickle
sets = cPickle.load(file(pkls[0]))
smis=sets.values()[0]
ms = [Chem.MolFromSmiles(y) for x,y in smis]
SVG(moltosvg(ms[1]))
Look at controlling that in more detail.
m = ms[1]
rdDepictor.Compute2DCoords(m)
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
drawer.DrawMolecule(m)
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
Highlight a substructure:
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
drawer.DrawMolecule(m,highlightAtoms=m.GetSubstructMatch(Chem.MolFromSmarts('c1ncoc1')))
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
Individiual atoms can also be highlighted:
highlight=list(m.GetSubstructMatch(Chem.MolFromSmarts('c1ncoc1'))) + [10,1]
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
drawer.DrawMolecule(m,highlightAtoms=highlight)
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
The highlighting color can be changed:
highlight=[10,1,4,13]
colors={1:(1,0,0), 4:(0,1,0), 13:(0,0,1), 10:(1,0,1)}
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
drawer.DrawMolecule(m,highlightAtoms=highlight,highlightAtomColors=colors)
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
As we saw above, the bonds between adjacent atoms will be highlighted:
highlight=[10,1,4,5,6]
colors={1:(1,0,0), 4:(0,1,0), 5:(0,0,1), 10:(1,0,1)}
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
drawer.DrawMolecule(m,highlightAtoms=highlight,highlightAtomColors=colors)
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
But this can be turned off:
highlight=[10,1,4,5,6]
colors={1:(1,0,0), 4:(0,1,0), 5:(0,0,1), 10:(1,0,1)}
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
drawer.DrawMolecule(m,highlightAtoms=highlight,highlightBonds=[],highlightAtomColors=colors)
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
We can also highlight just bonds:
highlight=[1,5,6]
colors={1:(1,0,0), 4:(0,1,0), 5:(0,0,1), 10:(1,0,1)}
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
drawer.DrawMolecule(m,highlightAtoms=[],highlightBonds=highlight,highlightBondColors=colors)
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
Customizing atom labels:
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
opts = drawer.drawOptions()
opts.atomLabels[15]='a16'
opts.atomLabels[4]='a5'
opts.atomLabels[20]='a21'
drawer.DrawMolecule(m,highlightAtoms=[4,15,20])
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
Taking that to an extreme:
drawer = rdMolDraw2D.MolDraw2DSVG(400,200)
opts = drawer.drawOptions()
for i in range(m.GetNumAtoms()):
opts.atomLabels[i] = m.GetAtomWithIdx(i).GetSymbol()+str(i)
drawer.DrawMolecule(m)
drawer.FinishDrawing()
svg = drawer.GetDrawingText().replace('svg:','')
SVG(svg)
More to come!
One final note on performance.
Here's a quick comparison of the current Python-based renderer with the new C++ renderer for generating SVG:
from rdkit.six.moves import cStringIO
from rdkit.Chem import Draw
def moltosvg_old(mol,molSize=(450,150),kekulize=True):
mc = Chem.Mol(mol.ToBinary())
if kekulize:
try:
Chem.Kekulize(mc)
except:
mc = Chem.Mol(mol.ToBinary())
if not mc.GetNumConformers():
rdDepictor.Compute2DCoords(mc)
sio = cStringIO()
Draw.MolToFile(mc, sio, size=molSize, imageType="svg",
kekulize=False)
svg = sio.getvalue()
# It seems that the svg renderer used doesn't quite hit the spec.
# Here are some fixes to make it work in the notebook, although I think
# the underlying issue needs to be resolved at the generation step
return svg.replace('svg:','')
%timeit [moltosvg_old(x) for x in ms]
%timeit [moltosvg(x) for x in ms]
Factors of 10 in performance should never be sneered at. :-)
6 comments:
I'm trying to generate SVG images from MOL objects and this method could work for me but I have a trusty distribution and only python-rdkit 201309-1 is available (http://packages.ubuntu.com/trusty/python-rdkit). Is it safe to build latest one on trusty? Can you make the latest build available through Ubuntu repos?
Hi, does it save in png as well? or we need to convert svg files externally with another library (cairo-based?) ?
There is cairo integration that allows you to generate PNGs. The GetText() method on the MolDraw2DCairo drawer returns PNG data.
You need to have the RDKit built with cairo support. Recent anaconda builds (should) have this enabled.
Hi all
I am trying to generate image file with a legend. But the legend parameter is not working.
How to do that.
Draw.MolToFile(nol, 'cdk2_mol1.pdf' , size=(300, 300), legends="Test", imageType="pdf")
Greg, the code on this blog has become a little outdated as the code here unfortunately doesn't depict the stereochemistry of the molecule. And this is the 5th google result for me when googling 'rdkit notebook svg'. I found the following will do the same as moltosvg, but maintain my stereochemistry in the rendering:
def moltosvg(rdkit_mol, size_x=450, size_y=150):
AllChem.Compute2DCoords(rdkit_mol)
try:
rdkit_mol.GetAtomWithIdx(0).GetExplicitValence()
except RuntimeError:
rdkit_mol.UpdatePropertyCache(False)
try:
mc_mol = rdMolDraw2D.PrepareMolForDrawing(rdkit_mol, kekulize=True)
except ValueError: # <- can happen on a kekulization failure
mc_mol = rdMolDraw2D.PrepareMolForDrawing(rdkit_mol, kekulize=False)
drawer = rdMolDraw2D.MolDraw2DSVG(size_x, size_y)
drawer.DrawMolecule(mc_mol)
drawer.FinishDrawing()
svg = drawer.GetDrawingText()
# It seems that the svg renderer used doesn't quite hit the spec.
# Here are some fixes to make it work in the notebook, although I think
# the underlying issue needs to be resolved at the generation step
return svg.replace('svg:','')
The Smiles string of this molecule is 'CN1[C@@H]2CCC[C@H]1CC(C2)NC(=O)C3=C4C(=CC=C3)N=C(O4)N5CCOCC5'
what is the molecules?
Post a Comment