Working with NGLView#
MolSysMT can handle nglview.NGLWidget objects in the same way that it handles other molecular systems: it is a “form” of molecular systems. As such, any MolSysMT tool can accept NGLView views as input systems.
The nglview.NGLWidget as any other molecular system’s form#
Before we show some examples of how MolSysMT works with NGLView native objects, let’s create an nglview.NGLWidget to play with. Let’s work with the demo system from NGLView:
import molsysmt as msm
import nglview as nv
view = nv.demo()
view
Now that we have an nglview.NGLWidget object, let’s see if MolSysMT can get an information summary of the molecular system straight from it as first test:
msm.info(view)
form | n_atoms | n_groups | n_components | n_chains | n_molecules | n_entities | n_proteins | n_structures |
---|---|---|---|---|---|---|---|---|
nglview.NGLWidget | 5547 | 349 | 1 | 1 | 1 | 1 | 1 | 1 |
Attributes such as atom names, number of structures or atom coordinates can be retrieved with the function molsysmt.basic.get()
:
msm.get(view, element='group', selection=[81, 82, 83], name=True)
['VAL', 'ALA', 'ASH']
msm.get(view, element='system', n_structures=True)
1
msm.get(view, element='atom', selection='atom_name=="CA"', coordinates=True)
Magnitude | [[[3.7219999999999995 4.478 1.1199999999999999] [3.9679999999999995 4.531 1.4119999999999997] [3.8679999999999994 4.228 1.6149999999999998] ... [3.5289999999999995 3.638 8.024] [3.324 3.9369999999999994 7.933999999999999] [3.147 4.02 8.261]]] |
---|---|
Units | nanometer |
Element’s selections can also be made on NGLView native objects with MolSysMT:
msm.select(view, selection='atom_name=="CA" and group_name=="LYS"')
[226, 1053, 1075, 2235, 3652, 3851, 3898, 4965, 5214, 5405]
And in addition, MolSysMT can help you to get selection strings to be used in NGLView:
msm.select(view, selection='atom_name=="CA" and group_name=="LYS"', to_syntax='nglview')
'@226,1053,1075,2235,3652,3851,3898,4965,5214,5405'
msm.select(view, element='group', selection='group_name=="LYS"', to_syntax='nglview')
'16:A 66:A 67:A 141:A 231:A 245:A 248:A 311:A 325:A 339:A'
Finally we can wonder, can MolSysMT convert an nglview.NGLWidget to other molecular system forms? Have a look to this couple of examples:
msm.convert(view, to_form='string:amino_acids_3')
'AceMetAsnGlyThrGluGlyProAsnPheTyrValProPheSerAsnLysThrGlyValValArgSerProPheGluAlaProGlnTyrTyrLeuAlaGluProTrpGlnPheSerMetLeuAlaAlaTyrMetPheLeuLeuIleMetLeuGlyPheProIleAsnPheLeuThrLeuTyrValThrValGlnHisLysLysLeuArgThrProLeuAsnTyrIleLeuLeuAsnLeuAlaValAlaAshLeuPheMetValPheGlyGlyPheThrThrThrLeuTyrThrSerLeuHisGlyTyrPheValPheGlyProThrGlyCysAsnLeuGluGlyPhePheAlaThrLeuGlyGlyGlhIleAlaLeuTrpSerLeuValValLeuAlaIleGluArgTyrValValValCysLysProMetSerAsnPheArgPheGlyGluAsnHisAlaIleMetGlyValAlaPheThrTrpValMetAlaLeuAlaCysAlaAlaProProLeuValGlyTrpSerArgTyrIleProGluGlyMetGlnCysSerCysGlyIleAspTyrTyrThrProHisGluGluThrAsnAsnGluSerPheValIleTyrMetPheValValHisPheIleIleProLeuIleValIlePhePheCysTyrGlyGlnLeuValPheThrValLysGluAlaAlaAlaGlnGlnGlnGluSerAlaThrThrGlnLysAlaGluLysGluValThrArgMetValIleIleMetValIleAlaPheLeuIleCysTrpLeuProTyrAlaGlyValAlaPheTyrIlePheThrHisGlnGlySerAspPheGlyProIlePheMetThrIleProAlaPhePheAlaLrtThrSerAlaValTyrAsnProValIleTyrIleMetMetAsnLysGlnPheArgAsnCysMetValThrThrLeuYplYplGlyLysAsnProLeuGlyAspAspGluAlaSerThrThrValSerLysThrGluThrSerGlnValAlaProAla'
openmm_Topology = msm.convert(view, to_form='openmm.Topology')
msm.info(openmm_Topology)
form | n_atoms | n_groups | n_components | n_chains | n_molecules | n_entities | n_small_molecules | n_proteins | n_structures |
---|---|---|---|---|---|---|---|---|---|
openmm.Topology | 5547 | 349 | 123 | 1 | 123 | 123 | 3 | 1 | None |
Now that it has been demonstrated that MolSysMT recognizes nglview.NGLWidget objects as any other molecular form. Let’s show a couple of examples more appealing than the previous cells.
Example 1: Getting contact maps from a trajectory view#
Given the visualization of a molecular dynamics trajectory, let’s compute the contact maps between all alpha carbons from all frames.
First, the view needs to be produced by NGLView. This let’s do it straight with MolSysMT:
import molsysmt as msm
import nglview as nv
view = msm.convert([nv.datafiles.GRO, nv.datafiles.XTC], to_form='nglview.NGLWidget')
Note
We could have used the function :func:molsysmt.basic.view
instead also. Have a look to User guide > Tools > Basic > View.
msm.info(view)
form | n_atoms | n_groups | n_components | n_chains | n_molecules | n_entities | n_proteins | n_structures |
---|---|---|---|---|---|---|---|---|
nglview.NGLWidget | 5547 | 349 | 1 | 1 | 1 | 1 | 1 | 51 |
view
Let’s get the contact maps from the 51 structures with a 12 angstroms threshold:
contact_map = msm.structure.get_contacts(view, selection='molecule_type=="protein" and atom_name=="CA"',
threshold='12 angstroms')
Each contact map is a boolean matrix:
contact_map[10]
array([[ True, True, True, ..., False, False, False],
[ True, True, True, ..., False, False, False],
[ True, True, True, ..., False, False, False],
...,
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True],
[False, False, False, ..., True, True, True]])
We can make with Plotly an animated representation of these contact maps. But before, let’s get the x and y ticks labels for our contacts:
CA_labels = msm.get_label(view, selection='molecule_type=="protein" and atom_name=="CA"',
string='{group_name}-{group_id}')
CA_labels[10]
'VAL-11'
Time to show how the CA contacts evolves:
import plotly.express as px
fig = px.imshow(~contact_map, animation_frame=0, binary_string=True, height=600, origin='lower')
fig.update_layout(
xaxis = dict(
tickmode = 'array',
tickvals = list(range(0,contact_map.shape[1],25)),
ticktext = CA_labels[::25],
tickangle = 45
),
yaxis = dict(
tickmode = 'array',
tickvals = list(range(0,contact_map.shape[1],25)),
ticktext = CA_labels[::25],
tickangle = 45
)
)
fig.show()
Example 2: Getting distances between geometric centers of different views#
As second example let’s suppose we have two peptides:
import molsysmt as msm
import nglview as nv
molsys_A = msm.build.build_peptide('AceAlaNME')
molsys_A = msm.structure.center(molsys_A)
molsys_B = msm.build.build_peptide('AceProNME')
molsys_B = msm.structure.center(molsys_B)
molsys_B = msm.structure.translate(molsys_B, translation='[1.0, 0.0, 0.0] nm')
But each peptide has its own visualization. Notice that this time the views are produced with a different approach than before:
view1 = nv.show_molsysmt(molsys_A)
view2 = nv.show_molsysmt(molsys_B)
msm.info(view1)
form | n_atoms | n_groups | n_components | n_chains | n_molecules | n_entities | n_peptides | n_structures |
---|---|---|---|---|---|---|---|---|
nglview.NGLWidget | 22 | 3 | 1 | 1 | 1 | 1 | 1 | 1 |
msm.info(view2)
form | n_atoms | n_groups | n_components | n_chains | n_molecules | n_entities | n_peptides | n_structures |
---|---|---|---|---|---|---|---|---|
nglview.NGLWidget | 26 | 3 | 1 | 1 | 1 | 1 | 1 | 1 |
If we are interested in the distance between the geometrical center of each peptide, we can merge the views in a new one to extract the observable from a unique molecular system:
view = msm.merge([view1, view2])
view.clear()
view.add_licorice()
view
msm.structure.get_distances(view, selection='molecule_index==0', center_of_atoms=True,
selection_2='molecule_index==1', center_of_atoms_2=True)
Magnitude | [[[1.0]]] |
---|---|
Units | nanometer |
It can be proved looking at the geometric centers that the distance is correct:
msm.structure.get_center(view, selection='molecule_index==0')
Magnitude | [[[-5.551115123125783e-17 2.5232341468753557e-17 -1.8924256101565167e-18]]] |
---|---|
Units | nanometer |
msm.structure.get_center(view, selection='molecule_index==1')
Magnitude | [[[1.0 4.5369690910162646e-17 6.4051328343759035e-18]]] |
---|---|
Units | nanometer |
Or we can do it from both views, without merging them in a new one:
msm.structure.get_distances(view1, center_of_atoms=True,
molecular_system_2=view2, center_of_atoms_2=True)
Magnitude | [[[1.0]]] |
---|---|
Units | nanometer |
Example 3: Coloring atoms or residues based on scalar values from a list#
In this example, we will see how to easily color the residues of a protein according to their charge values using MolSysMT. With just a few lines of code, we can map any list of scalar values—such as partial charges—onto a molecular representation, enabling intuitive visual analysis of physicochemical properties.
molecular_system = msm.basic.convert('181L', selection='molecule_type=="protein"')
charge_groups = msm.physchem.get_charge(molecular_system, element='group', definition='physical_pH7')
charge_groups
Magnitude | [0.0 0.0 0.0 0.0 -1.0 0.0 0.0 1.0 0.0 -1.0 -1.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0 1.0 -1.0 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.1 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 -1.0 0.0 -1.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 -1.0 -1.0 0.0 -1.0 1.0 0.0 0.0 0.0 0.0 -1.0 0.0 -1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 -1.0 0.0 0.0 -1.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 -1.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 1.0] |
---|---|
Units | elementary_charge |
view = msm.view(molecular_system, viewer='NGLView')
msm.thirds.nglview.set_color_by_value(view, values=charge_groups, cmap='bwr_r')
view
See also
User guide > Tools > Basic > Info: Printing out summary information of a molecular system.
User guide > Tools > Basic > Get:
User guide > Tools > Basic > Select:
User guide > Tools > Basic > View: Showing a molecular system.
User guide > Tools > Basic > Merge: Merging the elements of different molecular systems.
User guide > Tools > Build > Build peptide:
User guide > Tools > Structure > Translate:
User guide > Tools > Structure > Get distances:
User guide > Tools > Structure > Get geometric center: