1

When drawing structures with RDKit, the atom label font size and the ring size are not in a good proportion. The labels are either too small or too large or misaligned.

Unfortunately, the documentation about this is meager. I found this: https://rdkit.org/docs/source/rdkit.Chem.Draw.MolDrawing.html But I don't know whether this is related and how I would have to put it together. I'm missing simple practical code examples.

I tried also Draw.MolToQPixmap, but there I experienced that of the atom labels are misaligned and so far I learnt that the reason is the difficulty to make this cross-platform consistent and furthermore Draw.MolToPixmap uses old drawing code. I should use e.g. Draw.MolToImage instead. But there similar like with Draw.MolToFile the font size is simply too small. I'm not sure whether this is a cross-platform issue as well (I'm on Win10). So, the solution would be to simply set the fontsize, but how?

I know that there is a RDKit mailing list where I asked this question already without an answer so far. Here on SO, there is maybe a broader audience and I can attach images for illustration.

Code:

from rdkit import Chem
from rdkit.Chem import Draw

smiles = ' FC1OC2N3C4[Si]5=C6B7C(C=CC6=CC4=CC2=CC1)C=CC=C7C=C5C=C3'
mol = Chem.MolFromSmiles(smiles)
img = Draw.MolToFile(mol,"Test.png",size=(300,150))

Result: (using Draw.MolToFile, alignment ok, but too small atom labels)

enter image description here

Result: (using Draw.MolToQPixmap, misaligned and/or font too large for small pictures)

enter image description here

enter image description here

Edit: (with the suggestion of @Oliver Scott)

I get 3 times the same output with the same fontsize. I must be a stupid mistake or misunderstanding somewhere.

Code:

from rdkit.Chem.Draw import rdMolDraw2D
from rdkit import Chem

smiles = 'FC1OC2N3C4[Si]5=C6B7C(C=CC6=CC4=CC2=CC1)C=CC=C7C=C5C=C3'
mol = Chem.MolFromSmiles(smiles)
    
def drawMyMol(fname, myFontSize):
    d = rdMolDraw2D.MolDraw2DCairo(350, 300)
    d.SetFontSize(myFontSize)
    print(d.FontSize())
    d.DrawMolecule(mol)
    d.FinishDrawing()
    d.WriteDrawingText(fname)
    
drawMyMol("Test1.png", 6)
drawMyMol("Test2.png", 12)
drawMyMol("Test3.png", 24)

Result:

6.0
12.0
24.0

enter image description here

theozh
  • 22,244
  • 5
  • 28
  • 72

3 Answers3

2

The newer RDKit drawing code is more flexible than these older functions. Try using the rdMolDraw2D drawing code. You can set the options for drawing as below. The documentation has a list of the available options:

from rdkit.Chem.Draw import rdMolDraw2D
from rdkit import Chem

smiles = 'FC1OC2N3C4[Si]5=C6B7C(C=CC6=CC4=CC2=CC1)C=CC=C7C=C5C=C3'
mol = Chem.MolFromSmiles(smiles)

# Do the drawing.
d = rdMolDraw2D.MolDraw2DCairo(350, 300)
d.drawOptions().minFontSize = 22
d.DrawMolecule(mol)
d.FinishDrawing()
d.WriteDrawingText('test.png') 

The default minimum font size is 12 and the max is 40.

Result:

RDKit molecule PNG

To get into a PIL image you could do it like this:

from PIL import Image
import io

# Change the last line of the above to get a byte string.
png = d.GetDrawingText() 

# Now read into PIL.
img = Image.open(io.BytesIO(png))

# Now you can do whatever you need to do with the PIL image.
Oliver Scott
  • 1,673
  • 8
  • 17
  • Thank you for your example! Actually, I need a QPixmap image for a PyQt QTableWidget.... If I have a PIL image (via Draw.MolToImage) I could convert it to QPixmap. So, any ideas how to get the PNG into PIL or QPixmap? Actually, in the end I don't want to save images to disk but just display it in a table. – theozh Nov 13 '20 at 10:49
  • See above edits, does this work? This way you avoid writing anything to disk. – Oliver Scott Nov 13 '20 at 11:00
  • for some reason `d.drawOptions().minFontSize = 22` does not result in an increase of the fontsize, whereas `d.SetFontSize(22)` does. Thank you for the PNG to PIL routine, I wouldn't have found this by my own. – theozh Nov 13 '20 at 11:33
  • Ah strange maybe we are using different RDKit versions. I didn't notice the `SetFontSize` functions, this is probably a cleaner solution for changing the font size. I would be grateful if you could mark the answer as accepted if it helped you at all. Thanks! – Oliver Scott Nov 13 '20 at 12:08
  • hmmm, unfortunately, problem not yet solved. I'm using RDKit 2020.03 I don't get it reproduceable: the first time I run the script it might be a larger font size, but when running a second time, setting a different font size, the size will stay the same... I must still be doing something wrong. – theozh Nov 13 '20 at 12:09
  • hmmm, I am using RDKit 2020.09.1 is it possible to share a snippet of your script? – Oliver Scott Nov 13 '20 at 12:17
  • could it be a version issue? I couldn't find 2020.03 documentation to check. On the RDKit page I only see 2020.09.01 documentation... no link to 2020.03 documentation. – theozh Nov 13 '20 at 12:35
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/224525/discussion-between-oliver-scott-and-theozh). – Oliver Scott Nov 13 '20 at 12:49
  • I guess I found it. If you add the line `print(d.FontSize())` before you actually set it, I got `0.5` as result. I guess fontsize is a relative size or kind of scaling factor but not absolute size in points. If you set fontsize in the range of 0.5 to 1.5 I get a change. If you type 12 or 22 it will probably exceed the maximum... pretty strange, and badly documented. – theozh Nov 13 '20 at 12:53
  • The font size is supposedly in pixels, so I guess relative to the image size? Although the docs says roughly.... – Oliver Scott Nov 13 '20 at 15:37
1

Thanks to the help of @Oliver Scott, I finally got what I was looking for: Apparently, the font size is relative (default 0.5), not absolute in points, at least in RDKit 2020.03, which I am using. Maybe this has changed in RDKit 2020.09?

Code: (to get PNGs files)

from rdkit.Chem.Draw import rdMolDraw2D
from rdkit import Chem

smiles = 'FC1OC2N3C4[Si]5=C6B7C(C=CC6=CC4=CC2=CC1)C=CC=C7C=C5C=C3'
mol = Chem.MolFromSmiles(smiles)

def myMolToPNG(fname, myFontSize):
    d = rdMolDraw2D.MolDraw2DCairo(350, 300)
    d.SetFontSize(myFontSize)
    d.DrawMolecule(mol)
    d.FinishDrawing()
    d.WriteDrawingText(fname)

myMolToPNG("Test1.png", 0.5)
myMolToPNG("Test2.png", 1.0)
myMolToPNG("Test3.png", 1.5)

Result:

enter image description here

Code: (to get a QPixmap, e.g for a PyQt QTableWidget)

from rdkit.Chem.Draw import rdMolDraw2D
from rdkit import Chem
from PyQt5.QtGui import QPixmap

smiles = 'FC1OC2N3C4[Si]5=C6B7C(C=CC6=CC4=CC2=CC1)C=CC=C7C=C5C=C3'
mol = Chem.MolFromSmiles(smiles)

def myMolToQPixmap(myFontSize):
    d = rdMolDraw2D.MolDraw2DCairo(350, 300)
    d.SetFontSize(myFontSize)
    d.DrawMolecule(mol)
    d.FinishDrawing()
    png = d.GetDrawingText()
    pixmap = QPixmap()
    pixmap.loadFromData(png)
    return pixmap
theozh
  • 22,244
  • 5
  • 28
  • 72
1

You can use SetPreferCoordGen and Compute2DCoords.

from rdkit import Chem
from rdkit.Chem import Draw
from rdkit.Chem import rdDepictor
rdDepictor.SetPreferCoordGen(True)

smiles = 'FC1OC2N3C4[Si]5=C6B7C(C=CC6=CC4=CC2=CC1)C=CC=C7C=C5C=C3'
mol = Chem.MolFromSmiles(smiles)
rdDepictor.Compute2DCoords(mol)
PILmol = Draw.MolToImage(mol, size=(300,150))

You get this PIL Image

img

Works in 2020.09, but I did not test it in 2020.03.

rapelpy
  • 1,684
  • 1
  • 11
  • 14
  • Thank you. What does your example show? Adjustment to a p referred orientation of the structure and hence better alignment of the atom labels? But what about changing the font size using `Draw.MolToImage()`? – theozh Nov 13 '20 at 17:49
  • @theozh It is just the RDKit way to get nicer images in a good proportion. I just thought, this is what you wanted. `MolToImage()` has no option for changing font size. – rapelpy Nov 13 '20 at 18:26
  • thank you @rapelpy, this is also helpful. Actually, I meant the alignment of the atom label relative to the rings (in the `Draw.MolToQPixmap()` case), not the alignment of the structure on the canvas. I hope your suggestion also works together with `rdMolDraw2D.MolDraw2DCairo()`. Your oriented structure actually looks nicer. – theozh Nov 13 '20 at 18:30