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
158
159
166
174
175
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
244