Skip to content

Instantly share code, notes, and snippets.

@matteoferla
Created February 2, 2021 14:53
Show Gist options
  • Save matteoferla/a241001c033b89bc69c1d1317bc59dda to your computer and use it in GitHub Desktop.
Save matteoferla/a241001c033b89bc69c1d1317bc59dda to your computer and use it in GitHub Desktop.
For Fragmenstein. A draft of a potential way to remove atoms from a 3D embedded set of molecules, when 2D is too misleading and overlap is key.
# NGLView is a great way to see a set of rdkit.Chem molecules in 3D.
# Right clicking gives green spheres by default. Right clicking on a sphere removes it. So nice way to keep track
# the `ModNGL` object contains the dynamic property `picked_atoms` which lists the atoms that were clicked.
# Clicked twice is removed. However, there is no way to determine the button integer (left, middle, wheel, right).
# Before loading the mols from rdkit it would be nice to fill the PDB info.
# As seen in https://blog.matteoferla.com/2020/03/atom-names-purely-in-rdkit.html
# once one has the atom names one can delete the atoms off a ``rdkit.Chem.RWMol`` making it nice and clear for Fragmenstein.
import nglview as nv
from io import StringIO
from typing import *
import json
from IPython.display import display
from collections import defaultdict
class ModNGL(nv.NGLWidget):
picked_atoms = []
@observe('picked')
def my_picked(self, change):
"""
This does not override the `_on_picked` method, that when initialised by
`view.player._make_widget_picked` fills `view.player.widget_picked.value`.
It however is strongly influenced by it!
Unfortunately, there's no way to tell in Python if left or right was clicked.
Technically in JS, the `buttons` integer passed to `clicked` controls this,
but it is not stored.
"picked" is a trait and is configured on both Python and JS.
So I doubt a pure Python solution is possible.
"""
print(buttons)
if change['new']:
self.picked_atoms.append(change['new'])
@property
def picked_atoms(self) -> Dict[List[str]]:
"""
Returns a dict with keys component indices and values a list of atom names sensu NGL
``[LIG]1:A.O1`` So [residue name] residue index : chain . atom name
"""
compontent_atoms = defaultdict(list)
for atom in self.picked_atoms:
name = atom['atom1']['name']
comp = compontent_atoms[atom['component']]
if name in comp:
del comp[comp.index(name)]
else:
comp.append(name)
return compontent_atoms
# ------------------------------------------------------------------------------------------------------------------------
def show_mols(*mols: Chem.Mol) -> nv.NGLWidget:
view = ModNGL()
for mol in (acetyl, ethylamine):
fh = StringIO(Chem.MolToPDBBlock(mol))
view.add_component(fh, ext='pdb')
#view.player._make_widget_picked()
return view
view = show_mols(acetyl, ethylamine)
view
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment