Vaishnav14220 commited on
Commit
7357bca
·
1 Parent(s): e2cbfc6

Add proper orbital shapes: s (sphere), p (dumbbell), d (cloverleaf) with better checkbox visibility

Browse files
Files changed (1) hide show
  1. app.py +136 -23
app.py CHANGED
@@ -167,35 +167,141 @@ def name_to_3d_molecule(name: str, show_orbitals: bool = False) -> tuple:
167
 
168
  if show_orbitals:
169
  import numpy as np
170
- # Add semi-transparent spheres around atoms to represent electron orbitals
 
171
  orbital_radius = {
172
  'H': 0.6, 'C': 0.9, 'N': 0.8, 'O': 0.75,
173
  'F': 0.7, 'Cl': 1.0, 'Br': 1.15, 'I': 1.4,
174
  'P': 1.1, 'S': 1.05, 'B': 0.95, 'Si': 1.2
175
  }
176
 
177
- # Create mesh for each atom's orbital
178
- for i, (x, y, z, elem) in enumerate(zip(x_coords, y_coords, z_coords, elements)):
179
- radius = orbital_radius.get(elem, 0.8)
180
-
181
- # Create sphere mesh
182
- u = np.linspace(0, 2 * np.pi, 20)
183
- v = np.linspace(0, np.pi, 15)
184
- sphere_x = x + radius * np.outer(np.cos(u), np.sin(v))
185
- sphere_y = y + radius * np.outer(np.sin(u), np.sin(v))
186
- sphere_z = z + radius * np.outer(np.ones(np.size(u)), np.cos(v))
 
 
 
 
 
 
 
 
 
 
 
 
187
 
 
 
188
  color = color_map.get(elem, '#FF1493')
189
 
190
- orbital_trace = go.Surface(
191
- x=sphere_x, y=sphere_y, z=sphere_z,
192
- colorscale=[[0, color], [1, color]],
193
- showscale=False,
194
- opacity=0.15,
195
- name=f'{elem} orbital',
196
- hoverinfo='skip'
197
- )
198
- data_traces.append(orbital_trace)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
  # Create figure
201
  fig = go.Figure(data=data_traces)
@@ -273,7 +379,7 @@ molecule_3d_interface = gr.Interface(
273
  fn=name_to_3d_molecule,
274
  inputs=[
275
  gr.Textbox(label="Chemical Name", placeholder="e.g., benzene, aspirin, caffeine, glucose"),
276
- gr.Checkbox(label="Show Electron Orbitals", value=False)
277
  ],
278
  outputs=[
279
  gr.HTML(label="2D Structure"),
@@ -281,9 +387,16 @@ molecule_3d_interface = gr.Interface(
281
  gr.Textbox(label="3D SDF Content (Optional - for external viewers)", lines=10, max_lines=20, visible=False)
282
  ],
283
  api_name="name_to_molecule",
284
- description="View 2D structure and interactive 3D molecule with atom labels. Click and drag to rotate, scroll to zoom! Toggle 'Show Electron Orbitals' to visualize electron clouds around atoms.",
285
  cache_examples=False,
286
- examples=[["benzene", False], ["aspirin", False], ["caffeine", True], ["glucose", False]],
 
 
 
 
 
 
 
287
  )
288
 
289
 
 
167
 
168
  if show_orbitals:
169
  import numpy as np
170
+
171
+ # Orbital size reference
172
  orbital_radius = {
173
  'H': 0.6, 'C': 0.9, 'N': 0.8, 'O': 0.75,
174
  'F': 0.7, 'Cl': 1.0, 'Br': 1.15, 'I': 1.4,
175
  'P': 1.1, 'S': 1.05, 'B': 0.95, 'Si': 1.2
176
  }
177
 
178
+ # Get electron configuration for each atom to determine orbital types
179
+ def get_orbitals(atomic_num):
180
+ """Return list of orbitals for an atom based on electron configuration"""
181
+ # Simplified orbital visualization - show valence orbitals
182
+ if atomic_num == 1: # H: 1s
183
+ return ['s']
184
+ elif atomic_num <= 2: # He: 1s
185
+ return ['s']
186
+ elif atomic_num <= 10: # Li-Ne: has s and p
187
+ return ['s', 'p']
188
+ elif atomic_num <= 18: # Na-Ar: has s and p
189
+ return ['s', 'p']
190
+ elif atomic_num <= 36: # K-Kr: has s, p, d
191
+ return ['s', 'p', 'd']
192
+ else: # Rb onwards: has s, p, d, f
193
+ return ['s', 'p', 'd', 'f']
194
+
195
+ # Create orbital shapes around each atom
196
+ for idx, (x, y, z, elem) in enumerate(zip(x_coords, y_coords, z_coords, elements)):
197
+ atom = atoms[idx]
198
+ atomic_num = atom.GetAtomicNum()
199
+ orbitals = get_orbitals(atomic_num)
200
 
201
+ # Base radius for orbitals
202
+ base_radius = orbital_radius.get(elem, 0.8)
203
  color = color_map.get(elem, '#FF1493')
204
 
205
+ # S orbital (spherical)
206
+ if 's' in orbitals:
207
+ u = np.linspace(0, 2 * np.pi, 25)
208
+ v = np.linspace(0, np.pi, 20)
209
+ s_radius = base_radius * 0.6
210
+ sphere_x = x + s_radius * np.outer(np.cos(u), np.sin(v))
211
+ sphere_y = y + s_radius * np.outer(np.sin(u), np.sin(v))
212
+ sphere_z = z + s_radius * np.outer(np.ones(np.size(u)), np.cos(v))
213
+
214
+ s_orbital = go.Surface(
215
+ x=sphere_x, y=sphere_y, z=sphere_z,
216
+ colorscale=[[0, color], [1, color]],
217
+ showscale=False,
218
+ opacity=0.2,
219
+ name=f'{elem}-s',
220
+ hoverinfo='skip'
221
+ )
222
+ data_traces.append(s_orbital)
223
+
224
+ # P orbitals (dumbbell shaped - 3 orientations: px, py, pz)
225
+ if 'p' in orbitals:
226
+ p_radius = base_radius * 1.0
227
+ p_length = base_radius * 1.5
228
+
229
+ # Create dumbbell shape for p orbitals
230
+ u = np.linspace(0, 2 * np.pi, 20)
231
+ v = np.linspace(-1, 1, 15)
232
+
233
+ # Pz orbital (along z-axis)
234
+ pz_r = p_radius * np.sqrt(1 - v**2)
235
+ pz_z_vals = z + p_length * v
236
+ pz_x = x + np.outer(pz_r, np.cos(u))
237
+ pz_y = y + np.outer(pz_r, np.sin(u))
238
+ pz_z = np.outer(pz_z_vals, np.ones(len(u)))
239
+
240
+ pz_orbital = go.Surface(
241
+ x=pz_x, y=pz_y, z=pz_z,
242
+ colorscale=[[0, color], [0.5, color], [1, color]],
243
+ showscale=False,
244
+ opacity=0.15,
245
+ name=f'{elem}-pz',
246
+ hoverinfo='skip'
247
+ )
248
+ data_traces.append(pz_orbital)
249
+
250
+ # Px orbital (along x-axis)
251
+ px_r = p_radius * np.sqrt(1 - v**2)
252
+ px_x_vals = x + p_length * v
253
+ px_x = np.outer(px_x_vals, np.ones(len(u)))
254
+ px_y = y + np.outer(px_r, np.cos(u))
255
+ px_z = z + np.outer(px_r, np.sin(u))
256
+
257
+ px_orbital = go.Surface(
258
+ x=px_x, y=px_y, z=px_z,
259
+ colorscale=[[0, color], [0.5, color], [1, color]],
260
+ showscale=False,
261
+ opacity=0.15,
262
+ name=f'{elem}-px',
263
+ hoverinfo='skip'
264
+ )
265
+ data_traces.append(px_orbital)
266
+
267
+ # Py orbital (along y-axis)
268
+ py_r = p_radius * np.sqrt(1 - v**2)
269
+ py_y_vals = y + p_length * v
270
+ py_x = x + np.outer(py_r, np.cos(u))
271
+ py_y = np.outer(py_y_vals, np.ones(len(u)))
272
+ py_z = z + np.outer(py_r, np.sin(u))
273
+
274
+ py_orbital = go.Surface(
275
+ x=py_x, y=py_y, z=py_z,
276
+ colorscale=[[0, color], [0.5, color], [1, color]],
277
+ showscale=False,
278
+ opacity=0.15,
279
+ name=f'{elem}-py',
280
+ hoverinfo='skip'
281
+ )
282
+ data_traces.append(py_orbital)
283
+
284
+ # D orbitals (for transition metals) - simplified cloverleaf shape
285
+ if 'd' in orbitals and elem not in ['H', 'C', 'N', 'O', 'F', 'S', 'P', 'Cl']:
286
+ d_radius = base_radius * 1.2
287
+ theta = np.linspace(0, 2 * np.pi, 25)
288
+ phi = np.linspace(0, np.pi, 15)
289
+
290
+ # Simplified d-orbital (four-lobed)
291
+ r = d_radius * np.abs(np.outer(np.sin(2 * phi), np.cos(2 * theta)))
292
+ d_x = x + r * np.outer(np.sin(phi), np.cos(theta))
293
+ d_y = y + r * np.outer(np.sin(phi), np.sin(theta))
294
+ d_z = z + r * np.outer(np.cos(phi), np.ones(len(theta)))
295
+
296
+ d_orbital = go.Surface(
297
+ x=d_x, y=d_y, z=d_z,
298
+ colorscale=[[0, color], [1, color]],
299
+ showscale=False,
300
+ opacity=0.12,
301
+ name=f'{elem}-d',
302
+ hoverinfo='skip'
303
+ )
304
+ data_traces.append(d_orbital)
305
 
306
  # Create figure
307
  fig = go.Figure(data=data_traces)
 
379
  fn=name_to_3d_molecule,
380
  inputs=[
381
  gr.Textbox(label="Chemical Name", placeholder="e.g., benzene, aspirin, caffeine, glucose"),
382
+ gr.Checkbox(label="Show Electron Orbitals (s, p, d shapes)", value=False, info="Toggle to see s-orbitals (spheres), p-orbitals (dumbbells), and d-orbitals (cloverleaf) around atoms")
383
  ],
384
  outputs=[
385
  gr.HTML(label="2D Structure"),
 
387
  gr.Textbox(label="3D SDF Content (Optional - for external viewers)", lines=10, max_lines=20, visible=False)
388
  ],
389
  api_name="name_to_molecule",
390
+ description="🔬 View 2D structure and interactive 3D molecule with atom labels. Click and drag to rotate, scroll to zoom! Enable 'Show Electron Orbitals' to see s-orbitals (spheres), p-orbitals (dumbbells), and d-orbitals (cloverleaf shapes).",
391
  cache_examples=False,
392
+ examples=[
393
+ ["benzene", False],
394
+ ["benzene", True],
395
+ ["water", True],
396
+ ["aspirin", False],
397
+ ["caffeine", True],
398
+ ["glucose", False]
399
+ ],
400
  )
401
 
402