Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding module support for NGLView backend #11

Merged
merged 51 commits into from
Jun 17, 2022
Merged

Adding module support for NGLView backend #11

merged 51 commits into from
Jun 17, 2022

Conversation

klimaj
Copy link
Member

@klimaj klimaj commented Jun 16, 2022

The goal of this PR is to address:

  • Simple display of pose does not seem to work in master #10
  • Where to put rosetta output when showing widgets #9
  • How to show two poses overlapped? #8
  • Add a preset exposing LayerSelector methods as widgets, for dynamic layer selector coloring upon parameter changes.
  • Refactor core.py and base.py to allow for overlaying multiple poses using the view.add_pose(pose, index=0) method. Also available are the view.update_pose and view.remove_pose methods (and corresponding methods with PDB strings). Poses were previously appended to the view.poses instance attribute which was of type list, but the view.poses instance attribute is now refactored into a dictionary with int-type keys specifying the index to be displayed and list-type values containing Pose objects to be overlaid in the display. This refactor leverages the multiple model support of py3Dmol and nglview.
  • Set PDB strings to None if Pose objects are input parameters - previously the Viewer was converting Pose objects to PDB str objects anyway and shuttling them around. The Viewer feels faster to display Pose objects after this change.
  • Support nglview with all of the existing modules.
  • Update the makeBundle preset logging and coloring (i.e. darkred for the core layer because red made oxygen atoms indistinguishable).
  • Automatically run the setZoomTo module to orient the pose before view.show() is called (otherwise the protein can end up outside the field of view, depending on the 3D coordinates).

@klimaj
Copy link
Member Author

klimaj commented Jun 17, 2022

@ajasja Please try this to add a pose. Upon running the add_pose method, the viewer is automatically updated with models:

v = viewer3d.init()
v += viewer3d.setStyle(colorscheme='redCarbon')
v += viewer3d.setSurface()
v.add_pose(pose1) # Automatically updates the viewer with the currently set modules
v.reinit() # Subtract all modules
v += viewer3d.setStyle(colorscheme='blueCarbon')
v.add_pose(pose2)

@klimaj
Copy link
Member Author

klimaj commented Jun 17, 2022

Here are some newly available methods:

view.add_pose(pose, index=None, update_viewer=True)
view.add_pdbstring(pdbstring, index=None, update_viewer=True)
view.remove_pose(index=None, model=None, update_viewer=True)
view.remove_pdbstring(index=None, model=None, update_viewer=True)
view.update_pose(pose, index=None, model=None, update_viewer=True)
view.update_pdbstring(pdbstring, index=None, model=None, update_viewer=True)
view.update_poses(poses, index=None, update_viewer=True)
view.update_pdbstrings(pdbstrings, index=None, update_viewer=True)

The index keyword argument specifies the index of the bucket of Pose/str objects to which to add/remove/update/visualize, and the model keyword argument specifies the index of the Pose/str object in the bucket to remove/update/visualize. To programmatically setup the viewer, one can set update_viewer=False, otherwise the viewer will be updated upon calling one of these methods. Interestingly, the Pose objects passed in don't have to be cloned since the viewer only holds lists of pointers to Pose objects in memory, so snapshots of simulation trajectories can be visualized with the add_pose method.

@klimaj
Copy link
Member Author

klimaj commented Jun 17, 2022

For example, one can visualize the residue 1 psi-space of a 20-residue poly-valine linear peptide as follows:

from bokeh.palettes import Viridis
n = 256
v = viewer3d.init()
pose = pyrosetta.io.pose_from_sequence("V" * 20)
for i, hex_str in enumerate(Viridis[n]):
    hex_num = hex(int(hex_str.replace("#", ""), 16) + int("0x200", 16))
    v.set_modules(viewer3d.setStyle(cartoon_color=hex_num, radius=0))
    pose.set_psi(1, i * 360 / n)
    v.add_pose(pose)

Screen Shot 2022-06-17 at 1 32 28 AM

if index in self.poses.keys():
self.update_objects(self.poses[index], self.pdbstrings[index])

def _maybe_setup_colab(self):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ajasja _maybe_setup_colab runs upon instantiation of the viewer - hopefully this helps show the viewer in Google Colab!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Nglview now displays!

@klimaj
Copy link
Member Author

klimaj commented Jun 17, 2022

@ajasja Thanks for your review. Additional updates now include:

  • surface_cutoff and core_cutoff widgets in the coreBoundarySurface preset.
  • Layer selector colors updated to reflect FoldIt coloring!
  • A viewer3d.init(auto_show=True) option to automatically show the viewer (the show method is also automatically called if any of the add/update/remove_pose/poses/pdbstring/pdbstrings/ methods are called, since at least in py3Dmol the viewer has to be instantiated (i.e. viewer.show() called) in order for the viewer to be updated. Poses can also be added/removed/updated without updating the viewer with using update_viewer=False.
  • A viewer3d.init(gui=True) option to show the GUI for nglview backend.
  • The Decoys widget works with presets.
  • A view.get_widgets_dict() method to return a dictionary of the current Widget descriptions and values for downstream applications.
  • Automatically run viewer3d.setZoomTo on the objects to be visualized if view.show has not yet been called (allowing viewer updates without changing the camera angle).
  • Ability to set the backend with integers, i.e., viewer3d.init(backend=1)

@klimaj
Copy link
Member Author

klimaj commented Jun 17, 2022

Otherwise I think poses are looking great! Particularly in full-screen in the Jupyter notebook using nglview to visualize PyRosetta-interpreted hydrogen bonds, disulfide bonds, etc:
Screen Shot 2022-06-17 at 12 46 11 PM

@ajasja
Copy link
Member

ajasja commented Jun 17, 2022

@klimaj Nice! I think it looks really great:)
Nglview still has some bugs at least in colabfold
Decoys_nglview

py3dmol works beautifuly and is very responsive.
image

Everything else is working well.

@klimaj
Copy link
Member Author

klimaj commented Jun 17, 2022

I agree, py3Dmol feels much faster now - I think it's lighter than nglview already, but especially after setting PDB strings to None if poses are passed in I think sped it up.

@klimaj klimaj merged commit 14aa8d0 into main Jun 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants