mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
* Configurable legend position (Top/Left/Right/Bottom) and vertical text (GitHub #9023) - Add LegendPosition enum and legendPosition, legendVerticalText to MolDrawOptions - Support legend at Top, Left, Right, Bottom; vertical text for Left/Right - Python: MolDrawOptions.legendPosition, .legendVerticalText; LegendPosition enum - Python: MolToSVG() wrapper with legend/drawOptions; doc updates for MolToImage - JSON: legendPosition (string), legendVerticalText (bool) in draw options - C++ and Python tests; release note and Cartridge.md docs * MolDraw2D: legend gutter for horizontal side legends; vertical side height fit - Reserve horizontal gap between molecule and left/right horizontal legends (scale mol to molWidth-gutter, align toward legend strip). - Position horizontal side legend by measured text width from partition edge. - Vertical side legends: iterative scale so n*max_h+(n-1)*gap fits panel. - Catch: long vertical side legend section. * Update legend-position tests and review-driven cleanup Use enum/default wording for legendPosition docs, move the lightweight Python test to Wrap, add regex-based placement checks (including horizontal side and vertical stacking), and refactor extractLegend helpers per style guidance. * Fix MolDraw2D legend edge cases * MolDraw2D: review follow-up (legend tests, bounds, DRY Top/Bottom) * Update no-FT legend test coords * Address PR review: document constants, remove release-note text, and simplify extra-padding logic
1004 lines
35 KiB
Python
1004 lines
35 KiB
Python
import random
|
|
import re
|
|
import unittest
|
|
from os import environ
|
|
|
|
import numpy as np
|
|
|
|
from rdkit import Chem, Geometry, RDConfig
|
|
from rdkit.Chem import AllChem, Draw, rdDepictor
|
|
from rdkit.Chem.Draw import rdMolDraw2D
|
|
|
|
|
|
class TestCase(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
pass
|
|
|
|
def test1(self):
|
|
m = Chem.MolFromSmiles('c1ccc(C)c(C)c1C')
|
|
AllChem.Compute2DCoords(m)
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.DrawMolecule(m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("<svg") != -1)
|
|
self.assertTrue(txt.find("</svg>") != -1)
|
|
|
|
def test2(self):
|
|
m = Chem.MolFromSmiles('c1ccc(C)c(C)c1C')
|
|
AllChem.Compute2DCoords(m)
|
|
d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
do = d.drawOptions()
|
|
do.atomLabels[3] = 'foolabel'
|
|
d.DrawMolecule(m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find(">f</text>") != -1)
|
|
self.assertTrue(txt.find(">o</text>") != -1)
|
|
self.assertTrue(txt.find(">l</text>") != -1)
|
|
self.assertTrue(txt.find(">a</text>") != -1)
|
|
|
|
@unittest.skipUnless(hasattr(Draw, 'MolDraw2DCairo'), 'Cairo support not enabled')
|
|
def testGithubIssue571(self):
|
|
m = Chem.MolFromSmiles('c1ccc(C)c(C)c1C')
|
|
AllChem.Compute2DCoords(m)
|
|
d = Draw.MolDraw2DCairo(300, 300)
|
|
d.DrawMolecule(m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
|
|
def testPrepareForDrawing(self):
|
|
m = Chem.MolFromSmiles('c1ccccc1[C@H](F)Cl')
|
|
nm = rdMolDraw2D.PrepareMolForDrawing(m)
|
|
self.assertEqual(nm.GetNumAtoms(), 9)
|
|
self.assertEqual(nm.GetNumConformers(), 1)
|
|
m = Chem.MolFromSmiles('C1CC[C@H]2NCCCC2C1')
|
|
nm = rdMolDraw2D.PrepareMolForDrawing(m)
|
|
self.assertEqual(nm.GetNumAtoms(), 11)
|
|
self.assertEqual(nm.GetNumConformers(), 1)
|
|
nm = rdMolDraw2D.PrepareMolForDrawing(m, addChiralHs=False)
|
|
self.assertEqual(nm.GetNumAtoms(), 10)
|
|
self.assertEqual(nm.GetNumConformers(), 1)
|
|
|
|
m = Chem.MolFromSmiles('CC=CC')
|
|
m.GetBondWithIdx(1).SetStereo(Chem.BondStereo.STEREOANY)
|
|
nm = rdMolDraw2D.PrepareMolForDrawing(m)
|
|
self.assertEqual(nm.GetBondWithIdx(1).GetStereo(), Chem.BondStereo.STEREOANY)
|
|
self.assertEqual(nm.GetBondWithIdx(0).GetBondDir(), Chem.BondDir.NONE)
|
|
nm = rdMolDraw2D.PrepareMolForDrawing(m, wavyBonds=True)
|
|
self.assertEqual(nm.GetBondWithIdx(1).GetStereo(), Chem.BondStereo.STEREONONE)
|
|
self.assertEqual(nm.GetBondWithIdx(0).GetBondDir(), Chem.BondDir.UNKNOWN)
|
|
|
|
def testRepeatedPrepareForDrawingCalls(self):
|
|
m = Chem.MolFromMolBlock("""
|
|
11280715312D 1 1.00000 0.00000 0
|
|
|
|
33 36 0 1 0 999 V2000
|
|
7.6125 -5.7917 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
7.0917 -6.0917 0.0000 C 0 0 1 0 0 0 0 0 0
|
|
6.4792 -6.8917 0.0000 C 0 0 2 0 0 0 0 0 0
|
|
8.1292 -6.0792 0.0000 N 0 0 0 0 0 0 0 0 0
|
|
5.5042 -6.8917 0.0000 C 0 0 3 0 0 0 0 0 0
|
|
11.2375 -4.8542 0.0000 N 0 0 0 0 0 0 0 0 0
|
|
9.6792 -5.1667 0.0000 N 0 0 3 0 0 0 0 0 0
|
|
5.9917 -6.5417 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
7.6042 -5.1917 0.0000 O 0 0 0 0 0 0 0 0 0
|
|
10.7167 -5.1625 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
6.2917 -7.4667 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
6.5750 -5.7917 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
10.2000 -4.8667 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
8.6500 -5.7792 0.0000 C 0 0 3 0 0 0 0 0 0
|
|
8.6417 -5.1792 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
9.1667 -6.0750 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
9.6875 -5.7667 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
9.1542 -4.8750 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
5.6917 -7.4667 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
5.2042 -7.4042 0.0000 F 0 0 0 0 0 0 0 0 0
|
|
4.9875 -6.5917 0.0000 F 0 0 0 0 0 0 0 0 0
|
|
7.5167 -6.5167 0.0000 O 0 0 0 0 0 0 0 0 0
|
|
11.7542 -5.1500 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
11.2417 -6.0542 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
10.7250 -5.7625 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
6.5750 -5.1917 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
6.0542 -6.0917 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
11.7667 -5.7542 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
12.2750 -4.8417 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
6.0542 -4.8917 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
5.5375 -5.7917 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
5.5375 -5.1917 0.0000 C 0 0 0 0 0 0 0 0 0
|
|
6.3167 -6.3042 0.0000 H 0 0 0 0 0 0 0 0 0
|
|
2 1 1 0 0 0
|
|
3 2 1 0 0 0
|
|
4 1 1 0 0 0
|
|
5 8 1 0 0 0
|
|
6 10 1 0 0 0
|
|
7 17 1 0 0 0
|
|
8 3 1 0 0 0
|
|
9 1 2 0 0 0
|
|
10 13 1 0 0 0
|
|
11 3 1 0 0 0
|
|
12 2 1 0 0 0
|
|
13 7 1 0 0 0
|
|
14 4 1 0 0 0
|
|
15 14 1 0 0 0
|
|
16 14 1 0 0 0
|
|
17 16 1 0 0 0
|
|
18 15 1 0 0 0
|
|
19 11 1 0 0 0
|
|
20 5 1 0 0 0
|
|
21 5 1 0 0 0
|
|
2 22 1 6 0 0
|
|
23 6 2 0 0 0
|
|
24 25 1 0 0 0
|
|
25 10 2 0 0 0
|
|
26 12 1 0 0 0
|
|
27 12 2 0 0 0
|
|
28 24 2 0 0 0
|
|
29 23 1 0 0 0
|
|
30 26 2 0 0 0
|
|
31 27 1 0 0 0
|
|
32 31 2 0 0 0
|
|
3 33 1 6 0 0
|
|
7 18 1 0 0 0
|
|
19 5 1 0 0 0
|
|
32 30 1 0 0 0
|
|
28 23 1 0 0 0
|
|
M END""")
|
|
nm = Draw.PrepareMolForDrawing(m)
|
|
self.assertEqual(nm.GetBondBetweenAtoms(2, 1).GetBondType(), Chem.BondType.SINGLE)
|
|
self.assertEqual(nm.GetBondBetweenAtoms(2, 1).GetBondDir(), Chem.BondDir.NONE)
|
|
self.assertEqual(nm.GetBondBetweenAtoms(2, 7).GetBondType(), Chem.BondType.SINGLE)
|
|
self.assertEqual(nm.GetBondBetweenAtoms(2, 7).GetBondDir(), Chem.BondDir.BEGINWEDGE)
|
|
nm = Draw.PrepareMolForDrawing(nm)
|
|
self.assertEqual(nm.GetBondBetweenAtoms(2, 1).GetBondType(), Chem.BondType.SINGLE)
|
|
self.assertEqual(nm.GetBondBetweenAtoms(2, 1).GetBondDir(), Chem.BondDir.NONE)
|
|
self.assertEqual(nm.GetBondBetweenAtoms(2, 7).GetBondType(), Chem.BondType.SINGLE)
|
|
self.assertEqual(nm.GetBondBetweenAtoms(2, 7).GetBondDir(), Chem.BondDir.BEGINWEDGE)
|
|
|
|
def testDrawMoleculesArgs(self):
|
|
smis = [
|
|
'O=C1c2cccc3c(N4CCCCC4)ccc(c23)C(=O)N1c1ccccn1', 'Cc1ccc[n+](C2=Nc3ccccc3[N-]C2=C(C#N)C#N)c1',
|
|
'CC(=O)NC1=NN(C(C)=O)C(c2ccccn2)S1', 'COc1cc(Cc2nccc3cc(OC)c(OC)cc23)c(S(=O)(=O)O)cc1OC'
|
|
]
|
|
tms = [Chem.MolFromSmiles(x) for x in smis]
|
|
[rdMolDraw2D.PrepareMolForDrawing(x) for x in tms]
|
|
drawer = rdMolDraw2D.MolDraw2DSVG(600, 600, 300, 300)
|
|
p = Chem.MolFromSmarts('c1ccccn1')
|
|
matches = [x.GetSubstructMatch(p) for x in tms]
|
|
acolors = []
|
|
for mv in matches:
|
|
clrs = {}
|
|
random.seed(0xf00d)
|
|
for idx in mv:
|
|
clrs[idx] = (random.random(), random.random(), random.random())
|
|
acolors.append(clrs)
|
|
# the bonds between the matching atoms too
|
|
bnds = []
|
|
for mol, mv in zip(tms, matches):
|
|
tmp = []
|
|
for bnd in p.GetBonds():
|
|
tmp.append(
|
|
mol.GetBondBetweenAtoms(mv[bnd.GetBeginAtomIdx()], mv[bnd.GetEndAtomIdx()]).GetIdx())
|
|
bnds.append(tmp)
|
|
drawer.DrawMolecules(tms, highlightAtoms=matches, highlightBonds=bnds,
|
|
highlightAtomColors=acolors)
|
|
drawer.FinishDrawing()
|
|
svg = drawer.GetDrawingText()
|
|
# 4 molecules, 6 bonds each:
|
|
re_str = r"path class='bond-\d+ atom-\d+ atom-\d+' d='M \d+.\d+,\d+.\d+ L \d+.\d+,\d+.\d+ L \d+.\d+,\d+.\d+ L \d+.\d+,\d+.\d+ Z' style='fill:"
|
|
patt = re.compile(re_str)
|
|
self.assertEqual(len(patt.findall(svg)), 24)
|
|
# 4 molecules, one atom each:
|
|
self.assertEqual(svg.count('fill:#DB2D2B;fill-rule:evenodd;stroke:#DB2D2B'), 4)
|
|
|
|
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 testReaction1(self):
|
|
rxn = AllChem.ReactionFromSmarts(
|
|
'[CH3:1][C:2](=[O:3])[OH:4].[CH3:5][NH2:6]>CC(O)C.[Pt]>[CH3:1][C:2](=[O:3])[NH:6][CH3:5].[OH2:4]',
|
|
useSmiles=True)
|
|
d = Draw.MolDraw2DSVG(900, 300)
|
|
d.DrawReaction(rxn)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("<svg") != -1)
|
|
self.assertTrue(txt.find("</svg>") != -1)
|
|
# print(txt,file=open('blah1.svg','w+'))
|
|
|
|
def testReaction2(self):
|
|
rxn = AllChem.ReactionFromSmarts(
|
|
'[CH3:1][C:2](=[O:3])[OH:4].[CH3:5][NH2:6]>CC(O)C.[Pt]>[CH3:1][C:2](=[O:3])[NH:6][CH3:5].[OH2:4]',
|
|
useSmiles=True)
|
|
d = Draw.MolDraw2DSVG(900, 300)
|
|
d.DrawReaction(rxn, highlightByReactant=True)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("<svg") != -1)
|
|
self.assertTrue(txt.find("</svg>") != -1)
|
|
# print(txt,file=open('blah2.svg','w+'))
|
|
|
|
def testReaction3(self):
|
|
rxn = AllChem.ReactionFromSmarts(
|
|
'[CH3:1][C:2](=[O:3])[OH:4].[CH3:5][NH2:6]>CC(O)C.[Pt]>[CH3:1][C:2](=[O:3])[NH:6][CH3:5].[OH2:4]',
|
|
useSmiles=True)
|
|
colors = [(0.3, 0.7, 0.9), (0.9, 0.7, 0.9), (0.6, 0.9, 0.3), (0.9, 0.9, 0.1)]
|
|
d = Draw.MolDraw2DSVG(900, 300)
|
|
d.DrawReaction(rxn, highlightByReactant=True, highlightColorsReactants=colors)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("<svg") != -1)
|
|
self.assertTrue(txt.find("</svg>") != -1)
|
|
|
|
def testReaction4(self):
|
|
rxn = AllChem.ReactionFromSmarts(
|
|
'[CH3:1][C:2](=[O:3])[OH:4].[CH3:5][NH2:6]>CC(O)C.[Pt]>[CH3:1][C:2](=[O:3])[NH:6][CH3:5].[OH2:4]',
|
|
useSmiles=True)
|
|
colors = [(100, 155, 245), (0, 45, 155)]
|
|
d = Draw.MolDraw2DSVG(900, 300)
|
|
self.assertRaises(ValueError, d.DrawReaction, rxn, True, colors)
|
|
|
|
def testBWDrawing(self):
|
|
m = Chem.MolFromSmiles('CCOCNCCl')
|
|
dm = Draw.PrepareMolForDrawing(m)
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke:#000000") >= 0)
|
|
self.assertTrue(txt.find("stroke:#00CC00") >= 0)
|
|
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.drawOptions().useBWAtomPalette()
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke:#000000") >= 0)
|
|
self.assertTrue(txt.find("stroke:#00CC00") == -1)
|
|
|
|
def testUpdatePalette(self):
|
|
m = Chem.MolFromSmiles('CCOCNCCl')
|
|
dm = Draw.PrepareMolForDrawing(m)
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke:#000000") >= 0)
|
|
self.assertTrue(txt.find("stroke:#00CC00") >= 0)
|
|
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.drawOptions().updateAtomPalette({6: (1, 1, 0)})
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke:#000000") == -1)
|
|
self.assertTrue(txt.find("stroke:#00CC00") >= 0)
|
|
self.assertTrue(txt.find("stroke:#FFFF00") >= 0)
|
|
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
plt = d.drawOptions().getAtomPalette()
|
|
plt[6] = (1, 1, 0)
|
|
d.drawOptions().setAtomPalette(plt)
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke:#000000") == -1)
|
|
self.assertTrue(txt.find("stroke:#00CC00") >= 0)
|
|
self.assertTrue(txt.find("stroke:#FFFF00") >= 0)
|
|
|
|
def testSetPalette(self):
|
|
m = Chem.MolFromSmiles('CCOCNCCl')
|
|
dm = Draw.PrepareMolForDrawing(m)
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke:#000000") >= 0)
|
|
self.assertTrue(txt.find("stroke:#00CC00") >= 0)
|
|
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.drawOptions().setAtomPalette({-1: (1, 1, 0)})
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke:#000000") == -1)
|
|
self.assertTrue(txt.find("stroke:#00CC00") == -1)
|
|
self.assertTrue(txt.find("stroke:#FFFF00") >= 0)
|
|
|
|
# try a palette that doesn't have a default:
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.drawOptions().setAtomPalette({0: (1, 1, 0)})
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke:#000000") >= 0)
|
|
self.assertTrue(txt.find("stroke:#00CC00") == -1)
|
|
self.assertTrue(txt.find("stroke:#FFFF00") == -1)
|
|
|
|
def testGithub1829(self):
|
|
d = Draw.MolDraw2DSVG(300, 300, 100, 100)
|
|
d.DrawMolecules(tuple())
|
|
d.FinishDrawing()
|
|
d.GetDrawingText()
|
|
|
|
def testSetLineWidth(self):
|
|
" this was github #2149 "
|
|
m = Chem.MolFromSmiles('CC')
|
|
dm = Draw.PrepareMolForDrawing(m)
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke-width:2.0px") >= 0)
|
|
self.assertTrue(txt.find("stroke-width:4.0px") == -1)
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.SetLineWidth(4)
|
|
d.DrawMolecule(dm)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("stroke-width:2.0px") == -1)
|
|
self.assertTrue(txt.find("stroke-width:4.0px") >= 0)
|
|
|
|
def testPrepareAndDrawMolecule(self):
|
|
m = Chem.MolFromSmiles("C1N[C@@H]2OCC12")
|
|
d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find(">H</text>") > 0)
|
|
|
|
m = Chem.MolFromSmiles("c1ccccc1")
|
|
d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertLess(txt.find("stroke-dasharray"), 0)
|
|
d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m, kekulize=False)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertGreater(txt.find("stroke-dasharray"), 0)
|
|
|
|
def testAtomTagging(self):
|
|
m = Chem.MolFromSmiles("C1N[C@@H]2OCC12")
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
dm = Draw.PrepareMolForDrawing(m)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, dm)
|
|
d.TagAtoms(dm, events={'onclick': 'alert'})
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertTrue(txt.find("<circle") > 0)
|
|
self.assertTrue(txt.find("onclick=") > 0)
|
|
|
|
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)
|
|
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.ClearDrawing()
|
|
ps = Draw.ContourParams()
|
|
ps.contourColour = (0.1, 0.2, 0.3, 0.4)
|
|
hexc = ''.join('%02X' % int(x * 255) for x in ps.contourColour)
|
|
ps.colourMap = [
|
|
(1, 1, 1),
|
|
(0.5, 1, 0.5),
|
|
(0, 1, 0),
|
|
]
|
|
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()
|
|
self.assertIn(hexc, txt)
|
|
self.assertIn('#42FF42', txt)
|
|
with open("contour_from_py_3.svg", 'w+') as outf:
|
|
print(txt, file=outf)
|
|
|
|
def testGridContours(self):
|
|
grid = np.zeros((50, 100), np.double)
|
|
ycoords = list(np.arange(0, 5, 0.1))
|
|
xcoords = list(np.arange(0, 10, 0.1))
|
|
for i in range(grid.shape[1]):
|
|
gxp = xcoords[i]
|
|
for j in range(grid.shape[0]):
|
|
gyp = ycoords[j]
|
|
for v in range(1, 4):
|
|
dvx = 2 * v - gxp
|
|
dvy = v - gyp
|
|
d2 = dvx * dvx + dvy * dvy
|
|
if d2 > 0:
|
|
grid[j, i] += 1 / np.sqrt(d2)
|
|
|
|
# sg = 255 * grid / np.max(grid)
|
|
# from PIL import Image
|
|
# img = Image.fromarray(sg.astype(np.uint8))
|
|
# img.save('img.png')
|
|
|
|
d = Draw.MolDraw2DSVG(300, 300)
|
|
d.ClearDrawing()
|
|
Draw.ContourAndDrawGrid(d, np.transpose(grid), xcoords, ycoords)
|
|
d.drawOptions().clearBackground = False
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
with open("contour_from_py_3.svg", 'w+') as outf:
|
|
print(txt, file=outf)
|
|
|
|
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 testSetDrawOptions(self):
|
|
m = Chem.MolFromSmiles('CCNC(=O)O')
|
|
d = rdMolDraw2D.MolDraw2DSVG(250, 200, -1, -1, True)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertNotEqual(txt.find("fill:#0000FF' >N</text>"), -1)
|
|
self.assertEqual(txt.find("fill:#000000' >N</text>"), -1)
|
|
|
|
d = rdMolDraw2D.MolDraw2DSVG(250, 200, -1, -1, True)
|
|
do = rdMolDraw2D.MolDrawOptions()
|
|
do.useBWAtomPalette()
|
|
d.SetDrawOptions(do)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertEqual(txt.find("fill:#0000FF' >N</text>"), -1)
|
|
self.assertNotEqual(txt.find("fill:#000000' >N</text>"), -1)
|
|
|
|
def testAlternativeFreetypeFont(self):
|
|
# this one, you have to look at the pictures
|
|
m = Chem.MolFromSmiles('S(=O)(=O)(O)c1c(Cl)c(Br)c(I)c(F)c(N)1')
|
|
d = rdMolDraw2D.MolDraw2DSVG(250, 200)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
with open('test_ff.svg', 'w') as f:
|
|
f.write(txt)
|
|
|
|
d = rdMolDraw2D.MolDraw2DSVG(250, 200)
|
|
do = rdMolDraw2D.MolDrawOptions()
|
|
rdbase = environ['RDBASE']
|
|
if rdbase:
|
|
do.fontFile = '{}/Code/GraphMol/MolDraw2D/Amadeus.ttf'.format(rdbase)
|
|
d.SetDrawOptions(do)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
with open('test_aff.svg', 'w') as f:
|
|
f.write(txt)
|
|
else:
|
|
pass
|
|
|
|
def testExplictMethyl(self):
|
|
m = Chem.MolFromSmiles('CC')
|
|
d = rdMolDraw2D.MolDraw2DSVG(250, 200)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertEqual(txt.find("class='atom-"), -1)
|
|
|
|
d = rdMolDraw2D.MolDraw2DSVG(250, 200)
|
|
do = rdMolDraw2D.MolDrawOptions()
|
|
do.explicitMethyl = True
|
|
d.SetDrawOptions(do)
|
|
rdMolDraw2D.PrepareAndDrawMolecule(d, m)
|
|
d.FinishDrawing()
|
|
txt = d.GetDrawingText()
|
|
self.assertNotEqual(txt.find("class='atom-"), -1)
|
|
|
|
def testDrawMoleculeWithHighlights(self):
|
|
COLS = [(1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), (1.0, 0.55, 0.0)]
|
|
|
|
def get_hit_atoms_and_bonds(mol, smt):
|
|
alist = []
|
|
blist = []
|
|
q = Chem.MolFromSmarts(smt)
|
|
for match in mol.GetSubstructMatches(q):
|
|
alist.extend(match)
|
|
|
|
for ha1 in alist:
|
|
for ha2 in alist:
|
|
if ha1 > ha2:
|
|
b = mol.GetBondBetweenAtoms(ha1, ha2)
|
|
if b:
|
|
blist.append(b.GetIdx())
|
|
|
|
return alist, blist
|
|
|
|
def add_colours_to_map(els, cols, col_num):
|
|
for el in els:
|
|
if el not in cols:
|
|
cols[el] = []
|
|
if COLS[col_num] not in cols[el]:
|
|
cols[el].append(COLS[col_num])
|
|
|
|
def do_a_picture(smi, smarts, label, lasso=None):
|
|
|
|
rdDepictor.SetPreferCoordGen(False)
|
|
mol = Chem.MolFromSmiles(smi)
|
|
mol = Draw.PrepareMolForDrawing(mol)
|
|
|
|
acols = {}
|
|
bcols = {}
|
|
h_rads = {}
|
|
h_lw_mult = {}
|
|
|
|
for i, smt in enumerate(smarts):
|
|
alist, blist = get_hit_atoms_and_bonds(mol, smt)
|
|
h_rads[alist[0]] = 0.4
|
|
h_lw_mult[blist[0]] = 2
|
|
col = i % 4
|
|
add_colours_to_map(alist, acols, col)
|
|
add_colours_to_map(blist, bcols, col)
|
|
|
|
d = rdMolDraw2D.MolDraw2DSVG(500, 500)
|
|
d.drawOptions().fillHighlights = False
|
|
if lasso is not None:
|
|
if lasso == "Direct":
|
|
d.drawOptions().multiColourHighlightStyle = Draw.MultiColourHighlightStyle.Lasso
|
|
elif lasso == "ViaJSON":
|
|
print('json lasso')
|
|
Draw.UpdateDrawerParamsFromJSON(d, '{"multiColourHighlightStyle": "Lasso"}')
|
|
d.DrawMoleculeWithHighlights(mol, label, acols, bcols, h_rads, h_lw_mult, -1)
|
|
|
|
d.FinishDrawing()
|
|
return d.GetDrawingText()
|
|
|
|
smi = 'CO[C@@H](O)C1=C(O[C@H](F)Cl)C(C#N)=C1ONNC[NH3+]'
|
|
smarts = ['CONN', 'N#CC~CO', 'C=CON', 'CONNCN']
|
|
txt = do_a_picture(smi, smarts, 'pyTest2')
|
|
self.assertGreater(txt.find('stroke:#FF8C00;stroke-width:8.0'), -1)
|
|
self.assertEqual(
|
|
txt.find("ellipse cx='244.253' cy='386.518'"
|
|
" rx='11.9872' ry='12.8346'"
|
|
" style='fill:none;stroke:#00FF00'"), -1)
|
|
txt = do_a_picture(smi, smarts, 'pyTest4', lasso="Direct")
|
|
# the lasso mode puts paths, not ellipses.
|
|
self.assertGreater(txt.find("<path class='atom-5'"), -1)
|
|
self.assertEqual(txt.find("ellipse"), -1)
|
|
|
|
txt = do_a_picture(smi, smarts, 'pyTest4', lasso="ViaJSON")
|
|
# the lasso mode puts paths, not ellipses.
|
|
self.assertGreater(txt.find("<path class='atom-5'"), -1)
|
|
self.assertEqual(txt.find("ellipse"), -1)
|
|
|
|
# test for no-longer-mysterious OSX crash.
|
|
smi = 'c1ccccc1Cl'
|
|
smarts = []
|
|
do_a_picture(smi, smarts, 'pyTest3')
|
|
|
|
@unittest.skipUnless(hasattr(Draw, 'MolDraw2DCairo'), 'Cairo support not enabled')
|
|
@unittest.skipUnless(hasattr(Chem, 'MolFromPNGString'), "RDKit not built with iostreams support")
|
|
def testPNGMetadata(self):
|
|
m = Chem.MolFromMolBlock('''
|
|
Mrv2014 08172015242D
|
|
|
|
0 0 0 0 0 999 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 3 2 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 C 2.31 -1.3337 0 0
|
|
M V30 2 C 3.6437 -2.1037 0 0
|
|
M V30 3 O 4.9774 -1.3337 0 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 1 1 2
|
|
M V30 2 1 2 3
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END''')
|
|
d = Draw.MolDraw2DCairo(200, 200)
|
|
d.DrawMolecule(m)
|
|
txt = d.GetDrawingText()
|
|
nm = Chem.MolFromPNGString(txt)
|
|
self.assertEqual(Chem.MolToSmiles(m), Chem.MolToSmiles(nm))
|
|
|
|
def testUpdateMolDrawOptionsAndDrawerParamsFromJSON(self):
|
|
m = Chem.MolFromSmiles('c1ccccc1NC(=O)C1COC1')
|
|
d2d = Draw.MolDraw2DSVG(250, 200, -1, -1, True)
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
txt = d2d.GetDrawingText()
|
|
self.assertFalse('>8</text>' in txt)
|
|
|
|
drawOptions = rdMolDraw2D.MolDrawOptions()
|
|
Draw.UpdateMolDrawOptionsFromJSON(drawOptions, '{"addAtomIndices": 1}')
|
|
self.assertTrue(drawOptions.addAtomIndices)
|
|
d2d = Draw.MolDraw2DSVG(250, 200, -1, -1, True)
|
|
d2d.SetDrawOptions(drawOptions)
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
txt = d2d.GetDrawingText()
|
|
self.assertTrue('>8</text>' in txt)
|
|
|
|
d2d = Draw.MolDraw2DSVG(250, 200, -1, -1, True)
|
|
Draw.UpdateDrawerParamsFromJSON(d2d, '{"addAtomIndices": 1}')
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
txt = d2d.GetDrawingText()
|
|
self.assertTrue('>8</text>' in txt)
|
|
|
|
def testIsotopeLabels(self):
|
|
m = Chem.MolFromSmiles("[1*]c1cc([2*])c([3*])c[14c]1")
|
|
regex = re.compile(r"<text\s+.*>\d</text>")
|
|
self.assertIsNotNone(m)
|
|
|
|
d2d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
textIsoDummyIso = d2d.GetDrawingText()
|
|
nIsoDummyIso = len(regex.findall(textIsoDummyIso))
|
|
self.assertEqual(nIsoDummyIso, 5)
|
|
|
|
d2d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
d2d.drawOptions().isotopeLabels = False
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
textNoIsoDummyIso = d2d.GetDrawingText()
|
|
nNoIsoDummyIso = len(regex.findall(textNoIsoDummyIso))
|
|
self.assertEqual(nNoIsoDummyIso, 3)
|
|
|
|
d2d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
d2d.drawOptions().dummyIsotopeLabels = False
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
textIsoNoDummyIso = d2d.GetDrawingText()
|
|
nIsoNoDummyIso = len(regex.findall(textIsoNoDummyIso))
|
|
self.assertEqual(nIsoNoDummyIso, 2)
|
|
|
|
d2d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
d2d.drawOptions().isotopeLabels = False
|
|
d2d.drawOptions().dummyIsotopeLabels = False
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
textNoIsoNoDummyIso = d2d.GetDrawingText()
|
|
nNoIsoNoDummyIso = len(regex.findall(textNoIsoNoDummyIso))
|
|
self.assertEqual(nNoIsoNoDummyIso, 0)
|
|
|
|
m = Chem.MolFromSmiles("C([1H])([2H])([3H])[H]")
|
|
deuteriumTritiumRegex = re.compile(r"<text\s+.*>[DT]</text>")
|
|
d2d = Draw.MolDraw2DSVG(300, 300, -1, -1, True)
|
|
d2d.drawOptions().isotopeLabels = False
|
|
d2d.drawOptions().dummyIsotopeLabels = False
|
|
d2d.drawOptions().atomLabelDeuteriumTritium = True
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
textDeuteriumTritium = d2d.GetDrawingText()
|
|
nDeuteriumTritium = len(deuteriumTritiumRegex.findall(textDeuteriumTritium))
|
|
self.assertEqual(nDeuteriumTritium, 2)
|
|
|
|
def testNewDrawingModes(self):
|
|
m = Chem.MolFromSmiles("CS(=O)(=O)COC(=N)c1cc(Cl)cnc1[NH3+] |SgD:7:note:some extra text:=:::|")
|
|
|
|
d2d = Draw.MolDraw2DSVG(300, 300)
|
|
rdMolDraw2D.SetDarkMode(d2d)
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
self.assertIn("<rect style='opacity:1.0;fill:#000000;stroke:none'", text)
|
|
|
|
d2d = Draw.MolDraw2DSVG(300, 300)
|
|
rdMolDraw2D.SetMonochromeMode(d2d, (1, 1, 1), (.5, .5, .5))
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
self.assertIn("<rect style='opacity:1.0;fill:#7F7F7F;stroke:none'", text)
|
|
self.assertIn("stroke:#FFFFFF;stroke-width:2", text)
|
|
|
|
d2d = Draw.MolDraw2DSVG(300, 300)
|
|
d2d.drawOptions().useAvalonAtomPalette()
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
self.assertIn("<rect style='opacity:1.0;fill:#FFFFFF;stroke:none'", text)
|
|
self.assertIn("stroke:#007E00;stroke-width:2", text)
|
|
|
|
d2d = Draw.MolDraw2DSVG(300, 300)
|
|
d2d.drawOptions().useCDKAtomPalette()
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
self.assertIn("<rect style='opacity:1.0;fill:#FFFFFF;stroke:none'", text)
|
|
self.assertIn("stroke:#2F50F7;stroke-width:2", text)
|
|
|
|
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 testGithub5298(self):
|
|
with self.assertRaises(RuntimeError):
|
|
rdMolDraw2D.PrepareMolForDrawing(None)
|
|
|
|
def testACS1996Mode(self):
|
|
m = Chem.MolFromSmiles("CS(=O)(=O)COC(=N)c1cc(Cl)cnc1[NH3+]")
|
|
AllChem.Compute2DCoords(m)
|
|
rdMolDraw2D.PrepareMolForDrawing(m)
|
|
svg = rdMolDraw2D.MolToACS1996SVG(m, "ACS Mode")
|
|
with open("testACSMode_1.svg", 'w') as f:
|
|
f.write(svg)
|
|
|
|
highlight_atoms = [0, 2, 4, 6, 8]
|
|
highlight_bonds = [1, 3, 5, 7, 9]
|
|
highlight_atom_cols = {
|
|
0: (1.0, 1.0, 0.0),
|
|
8: (1.0, 0.0, 1.0),
|
|
}
|
|
highlight_bond_cols = {
|
|
0: (0.0, 1.0, 1.0),
|
|
8: (0.0, 0.0, 1.0),
|
|
}
|
|
|
|
svg = rdMolDraw2D.MolToACS1996SVG(m, "Highlights", highlight_atoms, highlight_bonds,
|
|
highlight_atom_cols, highlight_bond_cols)
|
|
with open("testACSMode_2.svg", 'w') as f:
|
|
f.write(svg)
|
|
if hasattr(Draw, 'MolDraw2DCairo'):
|
|
drawer = rdMolDraw2D.MolDraw2DCairo(-1, -1)
|
|
rdMolDraw2D.DrawMoleculeACS1996(drawer, m)
|
|
drawer.FinishDrawing()
|
|
drawer.WriteDrawingText('testACSMode_1.png')
|
|
|
|
def testMolSize(self):
|
|
m = Chem.MolFromSmiles("CS(=O)(=O)COC(=N)c1cc(Cl)cnc1[NH3+]")
|
|
AllChem.Compute2DCoords(m)
|
|
rdMolDraw2D.PrepareMolForDrawing(m)
|
|
d2d = rdMolDraw2D.MolDraw2DSVG(-1, -1)
|
|
d2d.DrawMolecule(m)
|
|
sz = d2d.Width(), d2d.Height()
|
|
|
|
d2d = rdMolDraw2D.MolDraw2DSVG(-1, -1)
|
|
sz2 = d2d.GetMolSize(m)
|
|
self.assertEqual(sz, sz2)
|
|
|
|
def testQueryColour(self):
|
|
m = Chem.MolFromSmarts("c1ccc2nc([*:1])nc([*:2])c2c1")
|
|
self.assertIsNotNone(m)
|
|
# Check that default queryColour is #7F7F7F.
|
|
d2d = rdMolDraw2D.MolDraw2DSVG(-1, -1)
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
self.assertTrue("#7F7F7F" in text)
|
|
|
|
# Check that queryColour can be set to black.
|
|
query_colour = (0.0, 0.0, 0.0)
|
|
d2d = rdMolDraw2D.MolDraw2DSVG(-1, -1)
|
|
d2d.drawOptions().setQueryColour(query_colour)
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
self.assertTrue("#7F7F7F" not in text)
|
|
|
|
query_colour = (0.0, 0.0, 0.0)
|
|
d2d = rdMolDraw2D.MolDraw2DSVG(-1, -1)
|
|
d2d.drawOptions().queryColour = query_colour
|
|
query_colour_out = (0.0, 0.0, 0.0, 1.0)
|
|
self.assertEqual(d2d.drawOptions().queryColour, query_colour_out)
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
self.assertTrue("#7F7F7F" not in text)
|
|
|
|
def testColourProperties(self):
|
|
m = Chem.MolFromSmiles("c1ncccc1.*[C@H](F)Cl |m:6:0.1.2|")
|
|
m.SetProp('molNote', 'foo')
|
|
tpls = [
|
|
('backgroundColour', (0.4, 0.2, 0.4, 0.8)),
|
|
('highlightColour', (0.2, 0.4, 0.2, 0.8)),
|
|
('legendColour', (0.2, 0.2, 0.4, 0.8)),
|
|
('atomNoteColour', (0.4, 0.4, 0.2, 0.8)),
|
|
('bondNoteColour', (0.4, 0.2, 0.2, 0.8)),
|
|
('variableAttachmentColour', (0.2, 0.4, 0.4, 0.8)),
|
|
('annotationColour', (0.1, 0.5, 0.8, 0.8)),
|
|
('symbolColour', (0.8, 0.5, 0.1, 0.8)),
|
|
]
|
|
for attr, val in tpls:
|
|
hexc = ''.join('%02X' % int(x * 255) for x in val)
|
|
d2d = rdMolDraw2D.MolDraw2DSVG(-1, -1)
|
|
d2d.drawOptions().addAtomIndices = True
|
|
d2d.drawOptions().addBondIndices = True
|
|
d2d.drawOptions().singleColourWedgeBonds = True # test symbolColour
|
|
setattr(d2d.drawOptions(), attr, val)
|
|
aval = getattr(d2d.drawOptions(), attr)
|
|
for idx in range(4):
|
|
self.assertAlmostEqual(aval[idx], val[idx])
|
|
d2d.DrawMolecule(m, highlightAtoms=[4, 5], legend='foo')
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
self.assertTrue(hexc in text)
|
|
|
|
@unittest.skipUnless(hasattr(Draw, 'MolDraw2DCairo'), 'Cairo support not enabled')
|
|
def testGithub7409(self):
|
|
m = Chem.MolFromSmiles('CC |(-0.75,0,;0.75,0,)|')
|
|
m.GetConformer().SetId(5)
|
|
d2d = rdMolDraw2D.MolDraw2DCairo(200, 200)
|
|
# it's enough to check that this doesn't throw an exception
|
|
d2d.DrawMolecule(m)
|
|
|
|
def testProtectedAttributes(self):
|
|
do = rdMolDraw2D.MolDrawOptions()
|
|
with self.assertRaises(AttributeError):
|
|
do.rhubarb = True
|
|
|
|
def testShowAllCIPCodes(self):
|
|
m = Chem.MolFromSmiles("Cc1cccc(F)c1-c1c(C)cc([C@H](C)O)cc1Cl |wU:7.7,o1:7,&1:13|")
|
|
self.assertIsNotNone(m)
|
|
d2d = rdMolDraw2D.MolDraw2DSVG(-1, -1)
|
|
opts = d2d.drawOptions()
|
|
opts.addStereoAnnotation = True
|
|
opts.showAllCIPCodes = True
|
|
d2d.DrawMolecule(m)
|
|
d2d.FinishDrawing()
|
|
text = d2d.GetDrawingText()
|
|
#confirm that at least one CIP code is present
|
|
self.assertTrue("class='CIP_Code'" in text)
|
|
|
|
def testDrawingExtentsInclude(self):
|
|
coordRegex = re.compile(
|
|
"<path class='bond-\\d atom-\\d atom-\\d' d='M (\\d+\\.\\d+),(\\d+\\.\\d+) L (\\d+\\.\\d+),(\\d+\\.\\d+)'"
|
|
)
|
|
|
|
def getDrawer():
|
|
drawer = rdMolDraw2D.MolDraw2DSVG(300, 200, -1, -1, False)
|
|
drawer.drawOptions().padding = 0.2
|
|
return drawer
|
|
|
|
def extractCoords(text):
|
|
return [[float(cg) for cg in captureGroups] for captureGroups in coordRegex.findall(text)]
|
|
|
|
def checkCoords(referenceCoords, highlightCoords):
|
|
self.assertEqual(len(referenceCoords), len(highlightCoords))
|
|
for i in range(len(referenceCoords)):
|
|
self.assertEqual(len(referenceCoords[i]), len(highlightCoords[i]))
|
|
for j in range(len(referenceCoords[i])):
|
|
if abs(highlightCoords[i][j] - referenceCoords[i][j]) > 0.1:
|
|
return False
|
|
return True
|
|
|
|
m = Chem.MolFromMolBlock("""
|
|
RDKit 2D
|
|
|
|
3 3 0 0 0 0 0 0 0 0999 V2000
|
|
0.0000 0.8930 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.7734 -0.4465 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.7734 -0.4465 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 1 0
|
|
2 3 1 0
|
|
1 3 1 0
|
|
M END
|
|
""")
|
|
highlightAtoms = [0]
|
|
self.assertIsNotNone(m)
|
|
# default:
|
|
drawer = getDrawer()
|
|
drawer.DrawMolecule(m)
|
|
drawer.FinishDrawing()
|
|
text = drawer.GetDrawingText()
|
|
referenceCoords = extractCoords(text)
|
|
drawer = getDrawer()
|
|
drawer.DrawMolecule(m, highlightAtoms=highlightAtoms)
|
|
drawer.FinishDrawing()
|
|
text = drawer.GetDrawingText()
|
|
highlightCoords = extractCoords(text)
|
|
self.assertFalse(checkCoords(referenceCoords, highlightCoords))
|
|
# allButHighlights
|
|
drawer = getDrawer()
|
|
drawer.DrawMolecule(m)
|
|
drawer.FinishDrawing()
|
|
text = drawer.GetDrawingText()
|
|
referenceCoords = extractCoords(text)
|
|
drawer = getDrawer()
|
|
drawer.drawOptions(
|
|
).drawingExtentsInclude = rdMolDraw2D.DrawElement.ALL ^ rdMolDraw2D.DrawElement.HIGHLIGHTS
|
|
drawer.DrawMolecule(m, highlightAtoms=highlightAtoms)
|
|
drawer.FinishDrawing()
|
|
text = drawer.GetDrawingText()
|
|
highlightCoords = extractCoords(text)
|
|
self.assertTrue(checkCoords(referenceCoords, highlightCoords))
|
|
|
|
def testLegendPosition(self):
|
|
mol = Chem.MolFromSmiles('CCO')
|
|
self.assertIsNotNone(mol)
|
|
opts = rdMolDraw2D.MolDrawOptions()
|
|
self.assertEqual(opts.legendPosition, rdMolDraw2D.LegendPosition.Bottom)
|
|
opts.legendPosition = rdMolDraw2D.LegendPosition.Top
|
|
svg = Draw.MolToSVG(mol, legend='Ethanol', drawOptions=opts)
|
|
self.assertIn("class='legend'", svg)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|