nglviewer / nglview

Jupyter widget to interactively view molecular structures and trajectories
http://nglviewer.org/nglview/latest/
Other
820 stars 135 forks source link

MDAnalysis.Universe wrapper? #18

Closed dotsdl closed 8 years ago

dotsdl commented 8 years ago

It would be awesome to be able to pass an MDAnalysis.Universe object into a wrapper object similar to nglview.MDTrajTrajectory, with the wrapper pulling coordinate information through that object. Haven't looked in detail at the library to see the best way to go about it, but it I imagine there could be pretty wild and wonderful ways to take advantage of MDAnalysis' feature set, including perhaps making selections using AtomGroup objects.

hainm commented 8 years ago

@dotsdl

for your curiosity, you can check my fork (different API with @arose repo):

https://github.com/hainm/nglview

import nglview as nv
from MDAnalysis import Universe
import numpy as np

u = Universe('tz2.parm7', 'tz2.nc')
all_atoms = u.select_atoms('all')

# load coordinates to memory
xyz = np.asarray([all_atoms.coordinates() for frame in u.trajectory], dtype='f8')

# create nv.Structure
with open('tz2_0.pdb') as fh:
    text = fh.read()

structure = nv.Structure(text)

traj = nv.Trajectory(xyz=xyz, topology=structure)
view = nv.TrajectoryViewer(traj)
view.add_representation('licorice')
view

Per atom selection, ngl has its own one, so I am not sure if It can use mdanalysis. But what I have in mind (for mdanalysis users) is to get atom indices (np array) from AtomGroup and pass to nglview.

hainm commented 8 years ago

picture1

dotsdl commented 8 years ago

@hainm Yeah, I know there are ways of using it as-is, but I was curious whether there was interest in tightening up integration in a less clunky way with MDAnalysis on this end. We could always build wrapper functions/classes as an MDAnalysis.visualization submodule if this project doesn't want to do it.

hainm commented 8 years ago

but I was curious whether there was interest in tightening up integration in a less clunky way with MDAnalysis on this end.

yes, @arose and I think so.

What's in my mind

import nglview as nv

traj = nv.io.from_pytraj(its_object)
traj = nv.io.from_mdanalysis(its_object)
traj = nv.io.from_mdtraj(its_object)

@arose has different approach (more object-oriented than mine).

arose commented 8 years ago

Hi, cool to see more interest in this! My goal with the API is to provide a way to pass the data as raw/flat (numpy) arrays into the viewer and then have some convenience functions or objects to get data from various libraries.

Currently the NGL viewer can handle raw coordinate data but needs the topology as a pdb, gro or mmcif file. However I am refactoring the NGL viewer so that it can handle the topology in a binary format (private branch so far). As to atom selections, in another refactoring effort I am introducing bit-sets to NGL which will allow very efficient transfer of atom selections from libraries to the viewer. My opinion is that the libraries should use their own selection language (though I would very much like to see a common shared language eventually).

I hope to find some time this weekend to cleanup the API and integrate support for MDAnalysis. For the time being I wont be doing MD simulations or analysis myself. But I am very actively developing the NGL Viewer itself and will ensure support for MD data. Also, I am more then willing to share and discuss my ideas on how to push the Jupyter integration forward! In particular, efficient data transfer between kernel and browser will help (https://github.com/arose/nglview/issues/3). Feel free to contact me!

@hainm I will definitely have a look on what you have done, esp. API wise and will discuss it with you. I certainly like the addition of ready-to-use notebook examples!

arose commented 8 years ago

@dotsdl Is MDAnalysis Python 2 only for now? I get an error with Python 3 and MDAnalysis 0.13.0

File "/home/arose/miniconda3/lib/python3.4/site-packages/MDAnalysis/lib/mdamath.py", line 161
    A, B, C = [norm(v) for v in x, y, z]
                                 ^
SyntaxError: invalid syntax
arose commented 8 years ago

@dotsdl Is there a way in MDAnalysis to get a specific frame with iterating over all previous?

for ts in universe.trajectory:
    print ts.frame

Or is iterating fast and the data is only gather when attributes of the frame are accessed? Otherwise I would follow @hainm example and load everything into a numpy array.

dotsdl commented 8 years ago

@arose All of this sounds great, though I'll admit digging through the plumbing of the Jupyter notebook is not something I'm familiar with.

MDAnalysis is still Python 2-only, though we're almost fully Python 3 compatible. Is this library Python 3 only?

Getting to a specific frame can be done by indexing:

import MDAnalysis as mda
from MDAnalysisTests.datafiles import GRO, XTC

u = mda.Universe(GRO, XTC)

# go to frame 3 (0-based)
u.trajectory[3]

# positions reflect coordinates at the current frame
u.atoms.positions

So I imagine the viewer could display whatever the current frame is, and changing the frame could change the viewer, and vice-versa?

arose commented 8 years ago

MDAnalysis is still Python 2-only, though we're almost fully Python 3 compatible. Is this library Python 3 only?

It should work on both Python 2 and 3. However the machine I currently have has only Python 3, so, just an annoyance for me.

So I imagine the viewer could display whatever the current frame is, and changing the frame could change the viewer, and vice-versa?

The frame can be changed from the Python and the Browser side. When you create the viewer in the notebook you get a widget object back that has a synced frame attribute. The widget object in turn would be linked to the Universe.

Two more question, then I can quickly add a mda.Universe wrapper.

dotsdl commented 8 years ago

@arose the frame count can be gotten from Universe.trajectory.n_frames or equivalently len(Universe.trajectory). Getting the topology as a string is possible using MDAnalysis.lib.util.NamedStream, perhaps like so:

import MDAnalysis as mda
from MDAnalysisTests.datafiles import GRO, XTC
import cStringIO

u = mda.Universe(GRO, XTC)

f = mda.lib.util.NamedStream(cStringIO.StringIO(), 'lol.pdb')

# add PDB output to the named stream
with mda.Writer(f, u.atoms.n_atoms, multiframe=False) as W:
    W.write(u.atoms)

# extract from the stream
f.readlines()

Does that help? Let me know if there's anything else you need, or if you want me to have a look at some prototypes. Excited for this!

arose commented 8 years ago

@dotsdl Yes this helps. I just pushed an untested implementation. You can check the master branch out, install it (python setup.py develop) and run the following in a notebook -- hopefully it works...

import nglview as nv
import MDAnalysis as mda
from MDAnalysisTests.datafiles import GRO, XTC
u = mda.Universe(GRO, XTC)
w = nv.show_mdanalysis(u)
w
dotsdl commented 8 years ago

@arose hmmm...the widget shows up, and I can push play and watch the slider move, and moving the slider is reflected by a change in the active frame of the trajectory reader. However, I don't see any molecule representation displayed. Any ideas for troubleshooting this?

arose commented 8 years ago
dotsdl commented 8 years ago

I do get a DeprecationWarning:

/home/alter/.local/lib/python2.7/site-packages/ipywidgets/widgets/widget.py:513: DeprecationWarning: on_trait_change is deprecated: use observe instead
  self.on_trait_change(_validate_border, ['border_width', 'border_style', 'border_color'])

w.count gives 10

Doing w.add_representation("line", "*") didn't change the situation.

dotsdl commented 8 years ago

Cleaning out my .local/lib/python2.7/site-packages; it's a bit crufty. If that doesn't work I'll do the smart thing and use a virtualenv.

arose commented 8 years ago

Does the pdbid example work?

import nglview
struc = nglview.PdbIdStructure( "3pqr" )  # load file from RCSB PDB
w = nglview.NGLWidget( struc )            # create widget
w                                         # display widget
dotsdl commented 8 years ago

It does. :D

arose commented 8 years ago

Then I suspect the code to get the pdb string does not... Would you mind trying the following in https://github.com/arose/nglview/blob/master/nglview/__init__.py#L223

    def get_structure_string(self):
        import MDAnalysis as mda
        u = self.universe
        u.trajectory[0]
        fd, fname = tempfile.mkstemp(suffix=".pdb")
        # add PDB output to the named stream
        with mda.Writer(fd, u.atoms.n_atoms, multiframe=False) as W:
            W.write(u.atoms)
        # extract from the stream
        pdb_string = os.fdopen(fd).read()
        return pdb_string
dotsdl commented 8 years ago

Played with this a bit on the plane, and still couldn't get it to work. Perhaps something's wrong with the PDB files MDAnalysis writes with respect to what nglview expects? Something related to this issue?

arose commented 8 years ago

Back at my desktop machine with Python 2 set up. Fixed it in 724c64c567917f6a15e601b115503dbf45fbbb54.

screenshot from 2016-02-03 21 20 56

arose commented 8 years ago

Played with this a bit on the plane, and still couldn't get it to work. Perhaps something's wrong with the PDB files MDAnalysis writes with respect to what nglview expects? Something related to this issue?

NGL does not care about the atomname alignment.

hainm commented 8 years ago

why is there long bond?

arose commented 8 years ago

why is there long bond?

These are just the coordinates and bonds from mda. I suspect they are not centered respecting PBC by default in mda. Right @dotsdl?

I am not sure if nglview should be opinionated about it or just display what it is given. I lean to the latter.

hainm commented 8 years ago

I lean to the latter.

yeah, VMD does not care too, it's up to user.

dotsdl commented 8 years ago

@arose

Correct. This is the result I expect. I made some modifications in #30 so that the wrapper can also just take an AtomGroup, since for large systems there's no need to dump the whole thing in.

Quick question while I'm playing with one of my big membrane protein systems: what's the best way to get nglview to render non-protein molecules? Like ions and lipids or even waters?

hainm commented 8 years ago

for ions and waters, I normally use 'licorice'

view.add_representation('licorice', color='red')

not sure about lipid (but I am interested in @arose's answer too).

dotsdl commented 8 years ago

Ah...got it. Had to look closely at the selection language and the representations available. I can view everything I want to see in my system now. This is too cool!

arose commented 8 years ago

licorice/ball+stick and spacefill are but there are also line and point representation types which are not as demanding.

hainm commented 8 years ago

Ah...got it. Had to look closely at the selection language and the representations available. I can view everything I want to see in my system now. This is too cool!

do you mind sharing your image? curious about lipid representation in your case.

arose commented 8 years ago

:-)