1 import sys
2 import IPython
3
4 if IPython.release.version < '0.11':
5 raise ImportError('this module requires at least v0.11 of IPython')
6 elif IPython.release.version < '2.0':
7 install_nbextension=None
8 _canUse3D=False
9 else:
10 try:
11 try:
12 from notebook.nbextensions import install_nbextension
13 _canUse3D=True
14 except ImportError:
15
16 from IPython.html.nbextensions import install_nbextension
17 _canUse3D=True
18 except ImportError:
19
20
21 _canUse3D=False
22 sys.stderr.write("*"*44)
23 sys.stderr.write("\nCannot import nbextensions\n")
24 sys.stderr.write("Current IPython/Jupyter version is %s\n"%
25 IPython.release.version)
26 sys.stderr.write("Disabling 3D rendering\n")
27 sys.stderr.write("*"*44)
28 sys.stderr.write("\n")
29 import traceback
30 traceback.print_exc()
31
32 from rdkit import Chem
33 from rdkit.Chem import rdchem, rdChemReactions
34 from rdkit.Chem import Draw
35 from rdkit.Chem.Draw import rdMolDraw2D
36 from rdkit.six import BytesIO,StringIO
37 import copy
38 import os
39 import json
40 import uuid
41 import numpy
42 try:
43 import Image
44 except ImportError:
45 from PIL import Image
46
47 from IPython.display import SVG
48
49 molSize = (450, 150)
50 highlightSubstructs = True
51 kekulizeStructures = True
52
53 ipython_useSVG = False
54 ipython_3d = False
55 molSize_3d = (450, 450)
56 drawing_type_3d = "ball and stick"
57 camera_type_3d = "perspective"
58 shader_3d = "lambert"
59
60
61
62 Chem.WrapLogs()
63
65 """For IPython notebook, renders 3D webGL objects."""
66
67 if not ipython_3d or not mol.GetNumConformers():
68 return None
69
70 try:
71 import imolecule
72 except ImportError:
73 raise ImportError("Cannot import 3D rendering. Please install "
74 "with `pip install imolecule`.")
75
76 conf = mol.GetConformer()
77 if not conf.Is3D():
78 return None
79
80 mol = Chem.Mol(mol)
81 try:
82 Chem.Kekulize(mol)
83 except Exception:
84 mol = Chem.Mol(mol)
85 size = molSize_3d
86
87
88 atomps = numpy.array([list(conf.GetAtomPosition(x))
89 for x in range(mol.GetNumAtoms())])
90 avgP = numpy.average(atomps, 0)
91 atomps -= avgP
92
93
94 atoms = [{"element": atom.GetSymbol(),
95 "location": list(atomps[atom.GetIdx()])}
96 for atom in mol.GetAtoms()]
97 bonds = [{"atoms": [bond.GetBeginAtomIdx(),
98 bond.GetEndAtomIdx()],
99 "order": int(bond.GetBondTypeAsDouble())}
100 for bond in mol.GetBonds()]
101 mol = {"atoms": atoms, "bonds": bonds}
102 return imolecule.draw({"atoms": atoms, "bonds": bonds}, format="json",
103 size=molSize_3d, drawing_type=drawing_type_3d,
104 camera_type=camera_type_3d, shader=shader_3d,
105 display_html=False)
106
107
109 if hasattr(mol,'__sssAtoms'):
110 highlightAtoms=mol.__sssAtoms
111 else:
112 highlightAtoms=[]
113 try:
114 mol.GetAtomWithIdx(0).GetExplicitValence()
115 except RuntimeError:
116 mol.UpdatePropertyCache(False)
117
118 if not hasattr(rdMolDraw2D,'MolDraw2DCairo'):
119 mc = copy.deepcopy(mol)
120 try:
121 img = Draw.MolToImage(mc,size=molSize,kekulize=kekulizeStructures,
122 highlightAtoms=highlightAtoms)
123 except ValueError:
124 mc = copy.deepcopy(mol)
125 img = Draw.MolToImage(mc,size=molSize,kekulize=False,
126 highlightAtoms=highlightAtoms)
127 bio = BytesIO()
128 img.save(bio,format='PNG')
129 return bio.getvalue()
130 else:
131 nmol = rdMolDraw2D.PrepareMolForDrawing(mol,kekulize=kekulizeStructures)
132 d2d = rdMolDraw2D.MolDraw2DCairo(molSize[0],molSize[1])
133 d2d.DrawMolecule(nmol,highlightAtoms=highlightAtoms)
134 d2d.FinishDrawing()
135 return d2d.GetDrawingText()
136
138 if not ipython_useSVG:
139 return None
140 if hasattr(mol, '__sssAtoms'):
141 highlightAtoms = mol.__sssAtoms
142 else:
143 highlightAtoms = []
144 try:
145 mol.GetAtomWithIdx(0).GetExplicitValence()
146 except RuntimeError:
147 mol.UpdatePropertyCache(False)
148
149 try:
150 mc = rdMolDraw2D.PrepareMolForDrawing(mol,kekulize=kekulizeStructures)
151 except ValueError:
152 mc = rdMolDraw2D.PrepareMolForDrawing(mol,kekulize=False)
153 d2d = rdMolDraw2D.MolDraw2DSVG(molSize[0],molSize[1])
154 d2d.DrawMolecule(mc,highlightAtoms=highlightAtoms)
155 d2d.FinishDrawing()
156 svg = d2d.GetDrawingText()
157 return svg.replace("svg:","")
158
159
166
168 res = mol.__GetSubstructMatch(query, **kwargs)
169 if highlightSubstructs:
170 mol.__sssAtoms = list(res)
171 else:
172 mol.__sssAtoms = []
173 return res
174
175
177 res = mol.__GetSubstructMatches(query, **kwargs)
178 mol.__sssAtoms = []
179 if highlightSubstructs:
180 for entry in res:
181 mol.__sssAtoms.extend(list(entry))
182 return res
183
184
185
187 """displayhook function for PIL Images, rendered as PNG"""
188 bio = BytesIO()
189 img.save(bio,format='PNG')
190 return bio.getvalue()
191
192 _MolsToGridImageSaved = None
207
224
225 InstallIPythonRenderer()
226
227
229 global _MolsToGridImageSaved
230 del rdchem.Mol._repr_svg_
231 del rdchem.Mol._repr_png_
232 if _canUse3D:
233 del rdchem.Mol._repr_html_
234 del rdChemReactions.ChemicalReaction._repr_png_
235 if hasattr(rdchem.Mol, '__GetSubstructMatch'):
236 rdchem.Mol.GetSubstructMatch = rdchem.Mol.__GetSubstructMatch
237 del rdchem.Mol.__GetSubstructMatch
238 if hasattr(rdchem.Mol, '__GetSubstructMatches'):
239 rdchem.Mol.GetSubstructMatches = rdchem.Mol.__GetSubstructMatches
240 del rdchem.Mol.__GetSubstructMatches
241 del Image.Image._repr_png_
242 if _MolsToGridImageSaved is not None:
243 Draw.MolsToGridImage = _MolsToGridImageSaved
244