-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathgraveyard.py
More file actions
299 lines (220 loc) · 8.24 KB
/
Copy pathgraveyard.py
File metadata and controls
299 lines (220 loc) · 8.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 25 17:16:20 2024
@author: benjaminlear
"""
from rdkit import Chem
from rdkit.Chem import AllChem
from plotly import graph_objects as go
import numpy as np
# Define the SMILES string
smiles = 'CC(=O)NCC(=O)NCC(=O)NCC(=O)NCC(=O)NCC(=O)N' # Ethanol as an example
# Convert the SMILES string to a molecule
mol = Chem.MolFromSmiles(smiles)
# Add hydrogens to the molecule
mol = Chem.AddHs(mol)
# Embed the molecule in 3D space
AllChem.EmbedMolecule(mol, randomSeed=42)
# Optimize the 3D coordinates using force field optimization
AllChem.UFFOptimizeMolecule(mol)
# Get the 3D coordinates
conf = mol.GetConformer()
atoms_colors = dict(
C = "darkgrey",
H = "lightgrey",
N = "blue",
O = "red",
)
atoms_sizes = dict( # these are just van der waals radii
H = 1.2,
C = 1.7,
N = 1.55,
O = 1.52,
)
def draw_mol_3D (mol, resolution = 100):
atoms = mol.GetAtoms()
bonds = mol.GetBonds()
fig = go.Figure()
#add atoms
for i, atom in enumerate(atoms):
asym = atom.GetSymbol()
atom_trace = make_atom_mesh_trace(
[
conf.GetAtomPosition(i).x,
conf.GetAtomPosition(i).y,
conf.GetAtomPosition(i).z
],
color = atoms_colors[asym],
radius = atoms_sizes[atom.GetSymbol()]*0.2, # change this for ball and stick, stick, van der waals, etc.
resolution = resolution,
)
fig.add_trace(atom_trace)
#add bonds
for bond in bonds:
atom1 = bond.GetBeginAtomIdx()
atom2 = bond.GetEndAtomIdx()
a1x = conf.GetAtomPosition(atom1).x
a1y = conf.GetAtomPosition(atom1).y
a1z = conf.GetAtomPosition(atom1).z
a2x = conf.GetAtomPosition(atom2).x
a2y = conf.GetAtomPosition(atom2).y
a2z = conf.GetAtomPosition(atom2).z
midx = (a1x + a2x)/2
midy = (a1y + a2y)/2
midz = (a1z + a2z)/2
bond_trace = make_bond_mesh_trace(
[a1x, a1y, a1z],
[midx, midy, midz],
color = atoms_colors[atoms[atom1].GetSymbol()],
resolution = resolution)
fig.add_trace(bond_trace)
bond_trace = make_bond_mesh_trace(
[midx, midy, midz],
[a2x, a2y, a2z],
color = atoms_colors[atoms[atom2].GetSymbol()],
resolution = resolution)
fig.add_trace(bond_trace)
fig.update_layout(
scene=dict(
xaxis=dict(
visible=False,
showbackground=False,
showgrid=False,
zeroline=False
),
yaxis=dict(
visible=False,
showbackground=False,
showgrid=False,
zeroline=False
),
zaxis=dict(
visible=False,
showbackground=False,
showgrid=False,
zeroline=False
),
#aspectmode='data', # Ensure the aspect ratio is based on the data
),
width=800,
height=600,
margin=dict(l=0, r=0, t=0, b=0) # Reduce margins to focus on the data
)
fig.show("browser")
return fig
fig = draw_mol_3D(mol, resolution = 64)
#%% Old functions that are not needed now.
def generate_surface_cylinder(point1, point2, radius=0.1, resolution=50):
# Vector from point1 to point2
v = np.array(point2) - np.array(point1)
mag = np.linalg.norm(v)
v = v / mag # Normalize vector
# Create orthogonal vectors to v
not_v = np.array([1, 0, 0]) if (v == np.array([0, 1, 0])).all() else np.array([0, 1, 0])
n1 = np.cross(v, not_v)
n1 /= np.linalg.norm(n1)
n2 = np.cross(v, n1)
# Create the circle in 2D
theta = np.linspace(0, 2 * np.pi, resolution)
circle_x = radius * np.cos(theta)
circle_y = radius * np.sin(theta)
# Extrude circle along the vector v
t = np.linspace(0, mag, resolution)
t_grid, theta_grid = np.meshgrid(t, theta)
X = point1[0] + t_grid * v[0] + radius * np.outer(np.cos(theta), n1[0]) + radius * np.outer(np.sin(theta), n2[0])
Y = point1[1] + t_grid * v[1] + radius * np.outer(np.cos(theta), n1[1]) + radius * np.outer(np.sin(theta), n2[1])
Z = point1[2] + t_grid * v[2] + radius * np.outer(np.cos(theta), n1[2]) + radius * np.outer(np.sin(theta), n2[2])
return X, Y, Z
def generate_mesh_cylinder(point1, point2, radius=0.1, resolution=32):
# Ensure point1 and point2 are numpy arrays
point1 = np.array(point1)
point2 = np.array(point2)
# Calculate the vector from point1 to point2
v = point2 - point1
height = np.linalg.norm(v)
v = v / height # Normalize the vector
# Create orthogonal vectors to the cylinder axis
if np.all(v == np.array([0, 0, 1])) or np.all(v == np.array([0, 0, -1])):
# Special case where the axis is along the z direction
not_v = np.array([1, 0, 0])
else:
not_v = np.array([0, 0, 1])
n1 = np.cross(v, not_v)
n1 /= np.linalg.norm(n1)
n2 = np.cross(v, n1)
# Generate the angles for the circular cross-section
theta = np.linspace(0, 2 * np.pi, resolution, endpoint=True)
circle = np.array([np.cos(theta), np.sin(theta)]) * radius
# Generate the points for the bottom and top circles of the cylinder
bottom_circle = point1[:, None] + n1[:, None] * circle[0] + n2[:, None] * circle[1]
top_circle = bottom_circle + v[:, None] * height
# Stack the bottom and top circles
points = np.hstack([bottom_circle, top_circle])
x, y, z = points
return x, y, z
def generate_surface_sphere(center, radius=0.1, resolution=50):
u = np.linspace(0, 2 * np.pi, resolution)
v = np.linspace(0, np.pi, resolution)
x = center[0] + radius * np.outer(np.cos(u), np.sin(v))
y = center[1] + radius * np.outer(np.sin(u), np.sin(v))
z = center[2] + radius * np.outer(np.ones(np.size(u)), np.cos(v))
return x, y, z
def generate_mesh_sphere (center, radius = 0.1, resolution = 32):
d = np.pi/resolution # sets resolution
theta, phi = np.mgrid[0:np.pi+d:d, 0:2*np.pi:d]
# Convert to Cartesian coordinates
x = np.sin(theta) * np.cos(phi) * radius + center[0]
y = np.sin(theta) * np.sin(phi) * radius + center[1]
z = np.cos(theta) * radius + center[2]
# print(x.shape, y.shape, z.shape) # (33, 64) (33, 64) (33, 64)
points = np.vstack([x.ravel(), y.ravel(), z.ravel()])
# print(points.shape) # (3, 2112)
x, y, z = points
return x, y, z
def make_bond_surface_trace(fig, point1, point2, radius = 0.1, resolution = 50, color = "grey"):
x, y, z = generate_surface_cylinder(point1, point2, radius = radius, resolution = resolution)
bond_trace = go.Surface(
x=x,
y=y,
z=z,
surfacecolor=np.full_like(x, 0), # Assign a single value to make the sphere a solid color
colorscale=[[0, color], [1, color]], # Define the colorscale as a single color
lighting=dict(
ambient=0,
diffuse=1,
specular=0,
roughness=1,
fresnel=0
),
lightposition=dict(
x=1000,
y=1000,
z=1000
),
showscale=False # Hide the individual color scales
)
return bond_trace
def make_atom_surface_trace(fig, center, radius = 0.1, resolution = 50, color = "grey" ):
x, y, z = generate_surface_sphere(center, radius = radius, resolution = resolution)
atom_trace = go.Surface(
x=x,
y=y,
z=z,
surfacecolor=np.full_like(x, 0), # Assign a single value to make the sphere a solid color
colorscale=[[0, color], [1, color]], # Define the colorscale as a single color
lighting=dict(
ambient=0,
diffuse=1,
specular=0,
roughness=1,
fresnel=0
),
lightposition=dict(
x=1000,
y=1000,
z=1000
),
showscale=False # Hide the individual color scales
)
return atom_trace