Skip to content

Commit

Permalink
Merge pull request #5 from everburstSun/develop
Browse files Browse the repository at this point in the history
1.1.0 release
  • Loading branch information
everburstSun authored Sep 16, 2023
2 parents 7097d67 + 1d22567 commit 7e3b4b8
Show file tree
Hide file tree
Showing 25 changed files with 10,682 additions and 6,636 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# dash-molstar Changelog

## [1.1.0] - 2023-09-16
### Added
- Adding custom html class names for the molstar container
- Drawing bounding boxes
- Selecting residues with insertion code
- Selecting residues and chains using the authentic numbers or names when working with CIF files
- Loading structures from remote urls

### Bug fixes
- Fixed the problem when the user toggles full-screen mode, molstar would be possibly hidden by other elements.

## [1.0.1] - 2023-05-09
### Bug fixes
- Fixed installation issue with pip

## [1.0.0] - 2023-05-04
### Initial release
6 changes: 3 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
Package: dashMolstar
Title: The molstar plugin for plotly dash framework
Version: 0.1.0
Version: 1.1.0
Description: The molstar plugin for plotly dash framework
Depends: R (>= 3.0.2)
Imports:
Suggests:
License: LGPL-2.1 + file LICENSE
URL: https://github.com/SSSSSimon/dash-molstar
BugReports: https://github.com/SSSSSimon/dash-molstar/issues
URL: https://github.com/everburstSun/dash-molstar
BugReports: https://github.com/everburstSun/dash-molstar/issues
Encoding: UTF-8
LazyData: true
KeepSource: true
306 changes: 306 additions & 0 deletions DOCUMENTATION.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

name = "DashMolstar"
uuid = "1b08a953-4be3-4667-9a23-14ed597df146"
authors = ["SimonSun <simonsun132@hotmail.com>"]
version = "1.0.0"
authors = ["SimonSun <simonhrsun@gmail.com>"]
version = "1.1.0"

[deps]
Dash = "1b08a953-4be3-4667-9a23-3db579824955"
Expand Down
6 changes: 3 additions & 3 deletions R/internal.R
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
.dashMolstar_js_metadata <- function() {
deps_metadata <- list(`dash_molstar` = structure(list(name = "dash_molstar",
version = "0.1.0", src = list(href = NULL,
version = "1.1.0", src = list(href = NULL,
file = "deps"), meta = NULL,
script = 'rcsb-molstar.js',
stylesheet = NULL, head = NULL, attachment = NULL, package = "dashMolstar",
all_files = FALSE), class = "html_dependency"),
`dash_molstar` = structure(list(name = "dash_molstar",
version = "0.1.0", src = list(href = NULL,
version = "1.1.0", src = list(href = NULL,
file = "deps"), meta = NULL,
script = 'dash_molstar.min.js',
stylesheet = NULL, head = NULL, attachment = NULL, package = "dashMolstar",
all_files = FALSE), class = "html_dependency"),
`dash_molstar` = structure(list(name = "dash_molstar",
version = "0.1.0", src = list(href = NULL,
version = "1.1.0", src = list(href = NULL,
file = "deps"), meta = NULL,
script = 'dash_molstar.min.js.map',
stylesheet = NULL, head = NULL, attachment = NULL, package = "dashMolstar",
Expand Down
6 changes: 3 additions & 3 deletions R/molstarViewer.R
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# AUTO GENERATED FILE - DO NOT EDIT

#' @export
molstarViewer <- function(id=NULL, data=NULL, focus=NULL, layout=NULL, selection=NULL, style=NULL) {
molstarViewer <- function(id=NULL, className=NULL, data=NULL, focus=NULL, layout=NULL, selection=NULL, style=NULL) {

props <- list(id=id, data=data, focus=focus, layout=layout, selection=selection, style=style)
props <- list(id=id, className=className, data=data, focus=focus, layout=layout, selection=selection, style=style)
if (length(props) > 0) {
props <- props[!vapply(props, is.null, logical(1))]
}
component <- list(
props = props,
type = 'MolstarViewer',
namespace = 'dash_molstar',
propNames = c('id', 'data', 'focus', 'layout', 'selection', 'style'),
propNames = c('id', 'className', 'data', 'focus', 'layout', 'selection', 'style'),
package = 'dashMolstar'
)

Expand Down
256 changes: 1 addition & 255 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,258 +36,4 @@ Clone the repository to your local directory and run the following command to se
python usage.py
```

## Parameters

Parameters for `MolstarViewer` include `id`, `data`, `focus`, `layout`, `selection` and `style`.

- `id` is the id for the html container of molstar, and should be unique in `app.layout`.

- `data` is the molecule to be loaded into molstar viewer. It is a `dict` or list of dicts, each containing a molecule to be loaded. With helper function `parse_molecule`, one can easily generate correct data for this parameter. `data` can include additional components to be shown in the viewer. The component data should be generated by the helper function `create_component`.

- `focus` is the component that the camera is currently focused on. It can also analyze the non-covalent interactions within 5 angstroms of the target. This can be controlled by the helper function `get_focus`, which takes a target selection and an optional boolean `analyse` parameter. If `analyse` is set to `True`, the function will analyze the non-covalent interactions within 5 angstroms of the target. If not specified, the default value of `analyse` is `False`.

- `layout` is the initial appearance of molstar viewer. It has some default settings. If you wish to specify some of the options, indicate them with a `dict`. The avaliable options are:

| Keys | Optional Values | Default Value |
| --- | --- | --- |
|"showImportControls"|`True`, `False`|`False`|
|"showSessionControls"|`True`, `False`|`True`|
|"showStructureSourceControls"|`True`, `False`|`True`|
|"showMeasurementsControls"|`True`, `False`|`True`|
|"showStrucmotifSubmitControls"|`True`, `False`|`True`|
|"showSuperpositionControls"|`True`, `False`|`True`|
|"showQuickStylesControls"|`True`, `False`|`True`|
|"showStructureComponentControls"|`True`, `False`|`True`|
|"showVolumeStreamingControls"|`True`, `False`|`False`|
|"showAssemblySymmetryControls"|`True`, `False`|`False`|
|"showValidationReportControls"|`True`, `False`|`False`|
|"showMembraneOrientationPreset"|`True`, `False`|`False`|
|"showNakbColorTheme"|`True`, `False`|`False`|
|"detachedFromSierra"|`True`, `False`|`True`|
|"layoutIsExpanded"|`True`, `False`|`False`|
|"layoutShowControls"|`True`, `False`|`False`|
|"layoutControlsDisplay"|`'outside'`, `'portrait'`, `'landscape'` and `'reactive'`|`'reactive'`|
|"layoutShowSequence"|`True`, `False`|`True`|
|"layoutShowLog"|`True`, `False`|`False`|
|"viewportShowExpand"|`True`, `False`|`True`|
|"viewportShowSelectionMode"|`True`, `False`|`True`|
|"showWelcomeToast"|`True`, `False`|`False`|

Note: layout of viewer should not be changed via callbacks.

- `selection` is the partition being selected in the viewer. The data for selection can be generated by the helper function `get_selection`. It has two modes: `select` and `hover`. In `select` mode, the target will be actually selected. In `hover` mode, the target will only be highlighted. If `None` was passed to the `targets` parameter of `get_selection`, the selection on corresponding mode will be deselected.

- `style` is the html style that will be add to the container for molstar viewer. `width` and `height` can be specified here.

## Helper Functions

### `parse_molecule(inp, fmt=None, component=None)`
This function takes in the path to a file or the contents of a file-like object as input, along with the format of the molecule (if not automatically determined from the file path) and an optional dictionary or list of dictionaries containing information about the components of the molecule to be created in molstar. The function returns a dictionary containing the parsed data that can be passed to molstar. If the format of the input file is not supported by molstar, a RuntimeError is raised.

### `get_targets(chain, residue=None)`
This function returns a dictionary containing information about the residues to be selected from the specified chain in molstar. If no residue is specified, the entire chain will be selected.

### `create_component(label, targets, representation='cartoon')`
This function generates the component information for the specified targets in molstar. The function takes in the name of the component, a dictionary or list of dictionaries containing the targets (whose value should be generated using the `get_targets` function), and an optional string specifying the default representation for the component (defaulting to 'cartoon'). The function returns a dictionary containing the component information that can be passed to the `parse_molecule` function. If an invalid representation is specified, a RuntimeError is raised.

### `get_selection(targets, select=True, add=False)`
This function selects the specified targets in molstar. The function takes in a dictionary or list of dictionaries containing the targets (whose value should be generated using the `get_targets` function), and two optional boolean arguments (`select` and `add`) which specify whether the selection should replace the current selection or be added to it (defaulting to True and False, respectively).

### `get_focus(targets, analyse=False)`
This function generates focus data for callbacks to let the camera focus on the specified targets. It takes two parameters: `targets` and `analyse`. `targets` is a dictionary or list of dictionaries containing information about the targets to focus on, which is generated using the `get_targets` helper function. analyse is an optional boolean parameter that is set to `False` by default, and if set to `True`, it enables the analysis of non-covalent interactions within a 5 Angstrom radius of the targets.

## Callbacks

The MolstarViewer component allows the `data`, `focus`, and `selection` parameters to be controlled by callbacks.

Assuming that you have already created a `MolstarViewer` with `id='viewer'` and a button with `id='load_protein'`:
```py
import dash_molstar
from dash import Dash, callback, html, Input, Output
from dash_molstar.utils import molstar_helper

app = Dash(__name__)
app.layout = html.Div(
dash_molstar.MolstarViewer(
id='viewer', style={'width': '500px', 'height':'500px'}
),
html.Button(id='load_protein', children="Load Protein"),
)
```
### Parameter `data`
The `data` parameter is used to set the data displayed in the viewer. Now let's link the button to molstar with a callback function to load protein into the viewer:

```py
# You can either use @app.callback or @Dash.callback for the decorator here.
@callback(Output('viewer', 'data'),
Input('load_protein', 'n_clicks'),
prevent_initial_call=True)
def display_output(yes):
data = molstar_helper.parse_molecule('3u7y.pdb')
return data
```

If you wish to load multiple structures, simply return a list of data object:

```py
from rdkit.Chem import AllChem

@callback(Output('viewer', 'data'),
Input('load_protein', 'n_clicks'),
prevent_initial_call=True)
def display_output(yes):
data = []
# append "3u7y.pdb" into data
data.append(molstar_helper.parse_molecule('3u7y.pdb'))
# append a new molecule Acetophenone to data
mol = AllChem.MolFromSmiles("CC(C1=CC=CC=C1)=O")
AllChem.Compute2DCoords(mol)
PDBBlock = AllChem.MolToPDBBlock(mol)
# Without a filename to infer format, the format has to be specified manually
data.append(molstar_helper.parse_molecule(PDBBlock, fmt='pdb'))
return data
```

By default, molstar will create a "polymer" component with cartoon representation for all standard residues. If you wish to create additional components, you can pass them to the `parse_molecule` function. For example, let's create a component with `molecular-surface` representation for the antigen chain (chain G) in 3U7Y:

```py
@callback(Output('viewer', 'data'),
Input('load_protein', 'n_clicks'),
prevent_initial_call=True)
def display_output(yes):
targetAg = molstar_helper.get_targets(chain="G")
ag = molstar_helper.create_component("Antigen", targetAg, 'molecular-surface')
data = molstar_helper.parse_molecule('3u7y.pdb',component=ag)
return data
```

You can also create multiple components with multiple targets by simply pass a list of objects.

```py
@callback(Output('viewer', 'data'),
Input('load_protein', 'n_clicks'),
prevent_initial_call=True)
def display_output(yes):
CDRs = [
# CDRs on heavy chain
molstar_helper.get_targets(chain="H", residue=[24,25,26,27,28,29,30,31,49,50,51,52,53,54,55,56,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109]),
# CDRs on light chain
molstar_helper.get_targets(chain="L", residue=[24,25,26,27,45,46,47,84,85,86,87,88])
]
ag = molstar_helper.create_component("Antigen", molstar_helper.get_targets(chain="G"), 'molecular-surface')
cdrs = molstar_helper.create_component("CDRs", CDRs, 'orientation')

data = molstar_helper.parse_molecule('3u7y.pdb',component=[ag,cdrs])

return data
```

### Parameter `focus`

The `focus` parameter allows you to focus the camera on a specific target. This equivalent to right-clicking on a residue in the molstar viewer.

```py
@callback(Output('viewer', 'focus'),
Input('focus-cdr', 'n_clicks'),
prevent_initial_call=True)
def focus_CDR(yes):
CDR = molstar_helper.get_targets(chain="L", residue=[24,25,26,27])
cdr = molstar_helper.get_focus(CDR)

return cdr
```

You can choose to analyze the non-covalent interactions around the target by specifing `analyse=True`, which is equivalent to left-clicking on a residue in the molstar viewer.

```py
@callback(Output('viewer', 'focus'),
Input('focus-cdr', 'n_clicks'),
prevent_initial_call=True)
def focus_CDR(yes):
CDR = molstar_helper.get_targets(chain="L", residue=[24,25,26,27])
cdr = molstar_helper.get_focus(CDR, analyse=True)

return cdr
```

### Parameter `selection`

This parameter can select the specified targets. It has two mode: the "select" mode and "hover" mode. Switching between the two modes by specifing `select=True`.

Remember to add corresponding buttons to the layout if you are trying the following code.

```py
@callback(Output('viewer', 'selection'),
Input('select-cdr', 'n_clicks'),
prevent_initial_call=True)
def select_CDR(yes):
CDR = molstar_helper.get_targets(chain="L", residue=[24,25,26,27])
# select by default
cdr = molstar_helper.get_selection(CDR)

return cdr
```

```py
@callback(Output('viewer', 'selection'),
Input('highlight-cdr', 'n_clicks'),
prevent_initial_call=True)
def highlight_CDR(yes):
CDR = molstar_helper.get_targets(chain="L", residue=[24,25,26,27])
# hover mode
cdr = molstar_helper.get_selection(CDR, select=False)

return cdr
```

Furthermore, you can combine `selection` and `focus` together. Assuming that we have a `fcc.Graph` object, it has a hover parameter and a click parameter. We can link the `hoverData` of the graph to the `selection` of viewer, and `clickData` to `focus`.

```py
import dash_molstar
from dash import Dash, callback, html, Input, Output, dcc, ctx
from dash_molstar.utils import molstar_helper
import dash
import pandas as pd
import plotly.express as px

app = Dash(__name__)
df = pd.read_json("H_G_interaction.json")
app.layout = html.Div(
dash_molstar.MolstarViewer(
id='viewer', style={'width': '500px', 'height':'500px'}
),
html.Button(id='load_protein', children="Load Protein"),
dcc.Graph(id='figure', clear_on_unhover=True, figure=px.imshow(df, labels=dict(color="energy"), color_continuous_scale='Blues_r',range_color=[-80, 0], text_auto=True)),
)

@callback(Output('viewer', 'data'),
Input('load_protein', 'n_clicks'),
prevent_initial_call=True)
def display_output(yes):
data = molstar_helper.parse_molecule('3u7y.pdb')
return data

@callback(Output('viewer', 'selection'),
Output('viewer', 'focus'),
Input('figure', 'hoverData'),
Input('figure', 'clickData'),
prevent_initial_call=True)
def mouse_event(hoverData, clickData):
focusdata = dash.no_update
if ctx.triggered_prop_ids.get('figure.hoverData'):
data = hoverData
select = False
focus = False
else:
data = clickData
select = True
focus = True
if not data: return molstar_helper.get_selection(None, select=select, add=False), focusdata
residue1 = data['points'][0]['x']
residue1 = molstar_helper.get_targets(residue1[0], residue1[1:])
residue2 = data['points'][0]['y']
residue2 = molstar_helper.get_targets(residue2[0], residue2[1:])
seldata = molstar_helper.get_selection([residue1, residue2], select=select, add=False)
if focus: focusdata = molstar_helper.get_focus([residue1, residue2], analyse=True)
return seldata, focusdata
```
To see the detailed introduction of parameters and callbacks, check out the [Documentation](https://github.com/everburstSun/dash-molstar/blob/main/DOCUMENTATION.md).
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
10 changes: 7 additions & 3 deletions dash_molstar/MolstarViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ class MolstarViewer(Component):
- id (string; optional):
The ID used to identify this component in Dash callbacks.
- className (string; optional):
The HTML property `class` for additional class names of the
container of molstar viewer.
- data (boolean | number | string | dict | list; optional):
Data containing the structure info that should be loaded into
molstar viewer, as well as some control flags. The data can be
Expand All @@ -37,10 +41,10 @@ class MolstarViewer(Component):
_namespace = 'dash_molstar'
_type = 'MolstarViewer'
@_explicitize_args
def __init__(self, id=Component.UNDEFINED, style=Component.UNDEFINED, data=Component.UNDEFINED, layout=Component.UNDEFINED, selection=Component.UNDEFINED, focus=Component.UNDEFINED, **kwargs):
self._prop_names = ['id', 'data', 'focus', 'layout', 'selection', 'style']
def __init__(self, id=Component.UNDEFINED, style=Component.UNDEFINED, className=Component.UNDEFINED, data=Component.UNDEFINED, layout=Component.UNDEFINED, selection=Component.UNDEFINED, focus=Component.UNDEFINED, **kwargs):
self._prop_names = ['id', 'className', 'data', 'focus', 'layout', 'selection', 'style']
self._valid_wildcard_attributes = []
self.available_properties = ['id', 'data', 'focus', 'layout', 'selection', 'style']
self.available_properties = ['id', 'className', 'data', 'focus', 'layout', 'selection', 'style']
self.available_wildcard_properties = []
_explicit_args = kwargs.pop('_explicit_args')
_locals = locals()
Expand Down
2 changes: 1 addition & 1 deletion dash_molstar/dash_molstar.min.js

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions dash_molstar/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@
"required": false,
"description": "The HTML property `style` to control the appearence of the container of molstar viewer."
},
"className": {
"type": {
"name": "string"
},
"required": false,
"description": "The HTML property `class` for additional class names of the container of molstar viewer."
},
"data": {
"type": {
"name": "any"
Expand Down
Loading

0 comments on commit 7e3b4b8

Please sign in to comment.