Comments (20)
Using rdkit
version 2019.09.1
and jupyter
version 1.0.0
this one works like a charm:
with open('grid.svg', 'w') as f:
f.write(grid.data)
Note: You might need to set useSVG=True
when calling MolsToGridImage
.
from rdkit-tutorials.
@greglandrum Now that we have tutorial here:
006_save_rdkit_mol_as_image.ipynb, can we close this issue?
from rdkit-tutorials.
MolToFile()
is still using the old drawing code as far as I can tell.
Agreed that a general cleanup of the contents of the rdkit.Chem.Draw module is necessary. And should probably be done before a tutorial is written.
from rdkit-tutorials.
The key attribute of the proper <svg>
open tag seems to be the namespace declaration.
https://developer.mozilla.org/en-US/docs/Web/SVG/Namespaces_Crash_Course
I can edit down the <svg >
open tag from the "successful" foo.svg I described above to this, @samoturk's images of methane, ethanol, and ethyl amine will render:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" >
rdkit's native svg-like output does have many xmlns
declarations, but none of them seem to do the job:
xmlns:rdkit="http://www.rdkit.org/xml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
Further experimentation reveals that just changing the xmlns:svg="http://www.w3.org/2000/svg"
to xmlns="http://www.w3.org/2000/svg"
in the native rdkit svg code allows Chrome to render it successfully. (I'll leave it to those wiser than me to determine if this is a bug in rdkit, in Chrome, in the w3c consortium's definition of the SVG namespace, or something else entirely.)
from rdkit-tutorials.
Q.v. also this recent message from Hongbing Yang to the rdkit-discuss mailing list:
Hi, everyone, I want to draw two molecules in a svg file with rdMolDraw2D. When I executed the following code, the jupyter cracked without any error or warning. ``` drawer = rdMolDraw2D.MolDraw2DSVG(400,400) i=0 for mol in mols: if mol.HasSubstructMatch(smarts): rdDepictor.Compute2DCoords(mol) #if i == 1: # continue drawer.DrawMolecule(mol,highlightAtoms=mol.GetSubstructMatch(smarts)) i+=1 if i > 1: break drawer.FinishDrawing() svg = drawer.GetDrawingText().replace('svg:','') SVG(svg) ```It seems that we cannot directly draw two molecules with the same drawer? So how can I draw as I wanted?
By the way, I've no idea why it cracked. From the experiment of the commented code, I can conclude it was caused by the drawer. So is it possible to fix the bug, adding error or warning instead of "KernelRestarter: restarting kernel" in console.
from rdkit-tutorials.
It looks like MolToFile()
is fixed on GitHub. So I know I can wait until the next release for easy ways to create .svgs of single molecules. I'm still not sure about grid images. I'd love to be able to export .svgs where molecule legend text comes through as text, for example.
from rdkit-tutorials.
MolsToGridImage by default produces SVG:
img = Draw.MolsToGridImage([Chem.MolFromSmiles(x) for x in ['C', 'CO', 'CN']])
print(type(img))
<class 'IPython.core.display.SVG'>
You can easily get the SVG data and save the text in a file:
print(img.data)
<svg baseProfile="full" height="200px" version="1.1" width="600px" xml:space="preserve" xmlns:rdkit="http://www.rdkit.org/xml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(0,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#000000" x="84.4958" y="108.25"><tspan>CH</tspan><tspan style="baseline-shift:sub;font-size:11.25px;">4</tspan><tspan/></text>
</g>
<g transform="translate(200,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<path d="M 9.09091,100 59.1479,100" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<path d="M 59.1479,100 109.205,100" style="fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#FF0000" x="109.205" y="107.5"><tspan>OH</tspan></text>
</g>
<g transform="translate(400,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<path d="M 9.09091,100 55.1606,100" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<path d="M 55.1606,100 101.23,100" style="fill:none;fill-rule:evenodd;stroke:#0000FF;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#0000FF" x="101.23" y="108.25"><tspan>NH</tspan><tspan style="baseline-shift:sub;font-size:11.25px;">2</tspan><tspan/></text>
</g></svg>
from rdkit-tutorials.
Thanks @samoturk. That's very useful.
However, a couple of caveats: When I copy that text into a file and name it foo.svg
, my browser [Chrome 56.0.2924.87 (64-bit)] cannot open it. Instead it displays This XML file does not appear to have any style information associated with it. The document tree is shown below.
That said, when I rename the file foo.html
, my browser can render images from the svg-like information.
However, properly formatted *.svg
files can be opened by Chrome and rendered into images even when they have the proper *.svg
extension. An example of such a file is at https://upload.wikimedia.org/wikipedia/commons/0/0c/Anecortave_acetate.svg
This may seem like a minor issue but I can assure you it has created very large amounts of confusion, for me for sure, and probably for others, judging by the mailing list archive. It also makes it harder to import rdkit "svg" files into applications.
from rdkit-tutorials.
Add in fact, if I replace the rdkit-generated svg open tag (i.e. <svg [STUFF]>
) with the svg open tag from the Wikipedia file, Chrome can render the document, even when it is called foo.svg
.
That is, this version renders:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="485.926px" height="448.539px" viewBox="0 0 485.926 448.539" enable-background="new 0 0 485.926 448.539"
xml:space="preserve">
<g transform="translate(0,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#000000" x="84.4958" y="108.25"><tspan>CH</tspan><tspan style="baseline-shift:sub;font-size:11.25px;">4</tspan><tspan/></text>
</g>
<g transform="translate(200,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<path d="M 9.09091,100 59.1479,100" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<path d="M 59.1479,100 109.205,100" style="fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#FF0000" x="109.205" y="107.5"><tspan>OH</tspan></text>
</g>
<g transform="translate(400,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<path d="M 9.09091,100 55.1606,100" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<path d="M 55.1606,100 101.23,100" style="fill:none;fill-rule:evenodd;stroke:#0000FF;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#0000FF" x="101.23" y="108.25"><tspan>NH</tspan><tspan style="baseline-shift:sub;font-size:11.25px;">2</tspan><tspan/></text>
</g></svg>
but this one does not:
<svg baseProfile="full" height="200px" version="1.1" width="600px" xml:space="preserve" xmlns:rdkit="http://www.rdkit.org/xml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(0,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#000000" x="84.4958" y="108.25"><tspan>CH</tspan><tspan style="baseline-shift:sub;font-size:11.25px;">4</tspan><tspan/></text>
</g>
<g transform="translate(200,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<path d="M 9.09091,100 59.1479,100" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<path d="M 59.1479,100 109.205,100" style="fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#FF0000" x="109.205" y="107.5"><tspan>OH</tspan></text>
</g>
<g transform="translate(400,0)"><rect height="200" style="opacity:1.0;fill:#FFFFFF;stroke:none" width="200" x="0" y="0"> </rect>
<path d="M 9.09091,100 55.1606,100" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<path d="M 55.1606,100 101.23,100" style="fill:none;fill-rule:evenodd;stroke:#0000FF;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
<text style="font-size:15px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;font-family:sans-serif;text-anchor:start;fill:#0000FF" x="101.23" y="108.25"><tspan>NH</tspan><tspan style="baseline-shift:sub;font-size:11.25px;">2</tspan><tspan/></text>
</g></svg>
from rdkit-tutorials.
I only ever used svg data to embed it in html as a part of web services, where it works. I never used it to store actual svg files so I never noticed this problem.
You are right, it seems that RDKit is not declaring the name space correctly. Replacing:
xmlns:svg="http://www.w3.org/2000/svg"
with xmlns="http://www.w3.org/2000/svg"
fixes the rendering also in Firefox. Both versions of the file work in default Gnome image viewer.
Bug @greglandrum ?
from rdkit-tutorials.
For relatively large grids, f.write(img.data) stops writing after about 1099 lines. Any ideas?
from rdkit-tutorials.
That's unexpected. What if you write line by line?
from rdkit-tutorials.
I managed to miss this issue when it originally came in.
On the namespaces thing: the svg generation code actually prefixes all svg elements with svg:
. This seems to work when storing the svg files, but fails when used with the jupyter integration. So the jupyter code tends to remove the prefix.
I can try setting the generic namespace (or whatever the xmlns
thing is) as part of the next release cycle and we can see if that helps.
from rdkit-tutorials.
@samoturk turns out I forgot to close the file :)
from rdkit-tutorials.
This is an integrated example:
def draw_multiple_mol(smiles_list, mols_per_row=4, file_path=None):
mols = []
for i in smiles_list:
mols.append(Chem.MolFromSmiles(i))
mols_per_row = min(len(smiles_list), mols_per_row)
img=Draw.MolsToGridImage(mols, molsPerRow=mols_per_row, subImgSize=(300, 160), useSVG=True)
if file_path:
with open(file_path, 'w') as f_handle:
f_handle.write(img.data)
return img
smiles = ['CCCS(=O)c1ccc2[nH]c(=NC(=O)OC)[nH]c2c1', 'CCOC(=O)c1cncn1C1CCCc2ccccc21']
draw_multiple_mol(smiles, file_path='two_mols.svg')
from rdkit-tutorials.
You could use an external package and not depend on rdkit releases. Like cairosvg for example:
from cairosvg import svg2png
m = Chem.MolFromSmiles(molecule)
AllChem.Compute2DCoords(m)
dr = rdMolDraw2D.MolDraw2DSVG(1080, 1080)
dr.DrawMolecule(m)
dr.FinishDrawing()
svg = dr.GetDrawingText()
# Using cairosvg
svg2png(bytestring=svg, write_to="smiles.png")
from rdkit-tutorials.
As of rdkit version 2022.9.4 , here is a fully reproducible example to get an SVG file.
from rdkit.Chem.Draw import rdMolDraw2D
from rdkit.Chem import MolFromSmiles
canvas_width_pixels = 300
canvas_height_pixels = 300
input_smiles = 'CCCC'
mol = MolFromSmiles(input_smiles)
mol = rdMolDraw2D.PrepareMolForDrawing(mol)
drawer = rdMolDraw2D.MolDraw2DSVG(canvas_width_pixels,canvas_height_pixels)
drawer.DrawMolecule(mol)
drawer.FinishDrawing()
svg = drawer.GetDrawingText()
with open('output.svg', 'w') as f:
f.write(svg)
The output.svg file looks like this:
from rdkit-tutorials.
I wanted to save svg generated by MolsToGridImage().
eg. svg = Draw.MolsToGridImage(ms, legends=legends, subImgSize=(250, 250), molsPerRow=3, useSVG=True)
This is what worked for me - the svg is being saved to a png file.
from cairosvg import svg2png
svg2png(bytestring=svg.data, write_to=output_png)
the svg.data is the important part.
from rdkit-tutorials.
@Rdk0, you're doing a lot of extra work here. You can get PNG directly from the RDKit like this:
In [13]: png = Draw.MolsToGridImage(ms,returnPNG=True)
In [14]: type(png)
Out[14]: bytes
You can then write that to a file.
If you want to work with the image in Python, you can have the code give you a pillow image instead:
In [8]: png = Draw.MolsToGridImage(ms,useSVG=False)
In [9]: type(png)
Out[9]: PIL.PngImagePlugin.PngImageFile
In [10]: png.save('/tmp/img.png')
from rdkit-tutorials.
Thank you Greg,
In my current jupyter nb (rdkit 2021.09.4, win10, jupyterlab 3.6.1) the returned types are different:
png = Draw.MolsToGridImage(ms,returnPNG=True)
type(png)
png = Draw.MolsToGridImage(ms,useSVG=False)
type(png)
In all these cases type(png)=IPython.core.display.Image
rather than PIL.PngImagePlugin.PngImageFile or bytes
I don't know why that is.
from rdkit-tutorials.
Related Issues (4)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rdkit-tutorials.