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

Question: Initializing py3DMol GL's buffers from arrays #530

Closed
benjha opened this issue Aug 19, 2021 · 6 comments
Closed

Question: Initializing py3DMol GL's buffers from arrays #530

benjha opened this issue Aug 19, 2021 · 6 comments

Comments

@benjha
Copy link

benjha commented Aug 19, 2021

Hi 3Dmol team,

I am looking for a way to create a molecule from arrays (positions, atom ids, etc.) coming from a simulation. Is it possible to initlize py3Dmol's GL buffers from these arrays ? What I want to avoid as much as possible is the serialization/deserialization of these arrays.

On the other hand, I am trying to replicate this 3Dmol.js sample in py3Dmol:

var atoms = [{elem: 'C', x: 0, y: 0, z: 0, bonds: [1,2], bondOrder: [1,2]}, {elem: 'O', x: -1.5, y: 0, z: 0, bonds: [0]},{elem: 'O', x: 1.5, y: 0, z: 0, bonds: [0], bondOrder: [2]}];
           
            viewer.setBackgroundColor(0xffffffff);
            var m = viewer.addModel();
            m.addAtoms(atoms);
            m.setStyle({},{stick:{}});
            viewer.zoomTo();
            viewer.render();

using the next code:

import py3Dmol
view=py3Dmol.view(width=400,height=400)
model = view.addModel()
atoms = [{'elem': 'C', 'x': 0, 'y': 0, 'z': 0, 'bonds': [1,2], 'bondOrder': [1,2]}, {'elem': 'O', 'x': -1.5, 'y': 0, 'z': 0, 'bonds': [0]},{'elem': 'O', 'x': 1.5, 'y': 0, 'z': 0, 'bonds': [0], 'bondOrder': [2]}]
model.addAtoms(atoms)
model.setStyle({},{'stick':{}})
view.zoomTo()
view.show()

and only I can see the empty canvas. Is there something I am missing ?

Thanks

@benjha benjha added the bug label Aug 19, 2021
@benjha benjha changed the title Initializing py3DMol GL's buffers from arrays Question: Initializing py3DMol GL's buffers from arrays Aug 19, 2021
@dkoes
Copy link
Contributor

dkoes commented Aug 20, 2021

You need to call view.render() to render the scene.

If you are loading simulation data, most likely the atoms (and bonds) are all the same and all you need to update are the coordinates. You can use setCoordinates (https://3dmol.org/doc/$3Dmol.GLModel.html#setCoordinates) to do this using the supported trajectory formats (mdcrd, inpcrd, pdb, netcdf). It wouldn't be very difficult at all to add support for a raw float array. What exactly is the format the coordinates are in?

@benjha
Copy link
Author

benjha commented Aug 21, 2021

Adding view.render() still shows a blank canvas, I think the problem is in another place. When looked at the console I got this error message:

Uncaught (in promise) TypeError: viewer_16295025962144551.addAtoms is not a function

On the other hand, we use RedisAI for in-memory storage, simulation push time steps while vis/and analysis pull them for processing in different nodes. In particular, arrays are tensors, we have a tensor for X, another for Y, and so on...

@dkoes
Copy link
Contributor

dkoes commented Aug 22, 2021

addAtoms is a method of a model, not the viewer. Try this:

import py3Dmol
v = py3Dmol.view()
v.addModel()  #create an empty model
v.getModel().addAtoms([{'x':0,'y':0,'z':0,'elem':'C'}]) #provide a list of dictionaries representing the atoms
v.setStyle({'sphere':{}})
v.zoomTo()

@benjha
Copy link
Author

benjha commented Aug 28, 2021

Great, it works.

Is there another option to this solution ?

#267 (comment)

i.e. not to put all the frames in one string. In my case I'll be receiving frames from the simulation and putting together the frames in one string imply to rebuild the py3Dmol's related objects every time a new frame is ready.

On the other hand, I think setCoordinates will overwrite the model so the user can't inspect previous time steps.

thanks for your advise.

@dkoes
Copy link
Contributor

dkoes commented Sep 8, 2021

Support for arrays in setCoordinates is now implemented.
b7bc1d7

Example py3Dmol code:

import py3Dmol
import torch

coords = torch.zeros(10,2,3)
coords[:,1,0] = torch.linspace(2,10,10)

v = py3Dmol.view()

v.addModel()  #create an empty model
v.getModel().addAtoms([{'x':0,'y':0,'z':0,'elem':'C'},{'x':2,'y':0,'z':0,'elem':'C'}]) #provide a list of dictionaries representing the atoms
v.setStyle({'sphere':{}})
v.getModel().setCoordinates(coords.numpy(),'array')
v.animate()
v.zoomTo()

I've got one more feature request I want to address before making a release. Hopefully that will happen soon.

@dkoes dkoes added enhancement and removed bug labels Sep 9, 2021
@benjha
Copy link
Author

benjha commented Sep 9, 2021

Great, thank you!

This is very useful.

@dkoes dkoes closed this as completed Sep 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants