Callbacks

Open In Colab

Callbacks are functions that are executed when you click on a cell’s callback button. They can be written in JavaScript or Python.

This functionality can be used to display some additional information on the molecule or run some more complex code such as database queries, docking or machine-learning predictions.

[1]:
# uncomment and run if you're on Google Colab
# !pip install rdkit mols2grid py3Dmol
# !wget https://raw.githubusercontent.com/rdkit/rdkit/master/Docs/Book/data/solubility.test.sdf
[2]:
import urllib.parse
import urllib.request
from pathlib import Path
from urllib.error import HTTPError

import py3Dmol
from IPython.display import display
from ipywidgets import widgets
from rdkit import RDConfig

import mols2grid


SDF_FILE = (
    f"{RDConfig.RDDocsDir}/Book/data/solubility.test.sdf"
    if Path(RDConfig.RDDocsDir).is_dir()
    else "solubility.test.sdf"
)
# Optional: read SDF file and sample 50 mols from it (to keep this notebook light)
df = mols2grid.sdf_to_dataframe(SDF_FILE).sample(50, random_state=0xac1d1c)

Python

Note: if you are reading this from the documentation web page, clicking on the images will not trigger anything. Try running the notebook on Google Colab instead (see link at the top of the page).

For Python callbacks, you need to declare a function that takes a dictionnary as first argument. This dictionnary contains all the data related to the molecule you’ve just clicked on. All the data fields are parsed as strings, except for the index, “mols2grid-id”, which is always parsed as an integer.

For example, the SMILES of the molecule will be available as data["SMILES"]. If the field contains spaces, they will be converted to hyphens, i.e. a field called mol weight will be available as data["mol-weight"].

Also, using print or any other “output” functions inside the callback will not display anything by default. You need to use ipywidgets’s Output widget to capture what the function is trying to display, and then show it.

Basic print example

In this simple example, we’ll just show the content of the data dictionnary.

[3]:
output = widgets.Output()


# the Output widget let's us capture the output generated by the callback function
# its presence is mandatory if you want to print/display some info with your callback
@output.capture(clear_output=True, wait=True)
def show_data(data):
    data.pop("img")
    for key, value in data.items():
        print(key, value)


view = mols2grid.display(
    df,
    callback=show_data,
)
display(view)
output

We can also make more complex operations with callbacks.

Displaying the 3D structure with py3Dmol

Here, we’ll query PubChem for the molecule based on its SMILES, then fetch the 3D structure and display it with py3Dmol.

[4]:
output = widgets.Output()


@output.capture(clear_output=True, wait=True)
def show_3d(data):
    """Query PubChem to download the SDFile with 3D coordinates and
    display the molecule with py3Dmol
    """
    url = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/smiles/{}/SDF?record_type=3d"
    smi = urllib.parse.quote(data["SMILES"])
    try:
        response = urllib.request.urlopen(url.format(smi))
    except HTTPError:
        print(f"Could not find corresponding match on PubChem")
        print(data["SMILES"])
    else:
        sdf = response.read().decode()
        view = py3Dmol.view(height=300, width=800)
        view.addModel(sdf, "sdf")
        view.setStyle({"stick": {}})
        view.zoomTo()
        view.show()


view = mols2grid.display(
    df,
    callback=show_3d,
)
display(view)
output

JavaScript

We can also write JavaScript callbacks, which have the advantage to be able to run on almost any platform.

JS callbacks don’t require to declare a function, and you can directly access and use the data object similarly to Python in your callback script.

Basic JS example

[5]:
js_callback = """
// remove image from data
delete data["img"];
// convert data object to text
txt = JSON.stringify(data);
// show data in alert window
alert(txt);
"""

mols2grid.display(
    df,
    callback=js_callback,
)
[5]:

To display fancy popup windows on click, a helper function is available: mols2grid.make_popup_callback.

It requires a title as well as some html code to format and display the information that you’d like to show. All of the values inside the data object can be inserted in the title and html arguments using ${data["field_name"]}. Additionally, you can execute a prerequisite JavaScript snippet to create variables that are then also accessible in the html code.

Display a popup containing descriptors

In the following exemple, we create an RDKit molecule using the SMILES of the molecule (the SMILES field is always present in the data object, no matter your input when creating the grid).

We then create a larger SVG image of the molecule, and calculate some descriptors.

Finally, we inject these variables inside the HTML code. You can also style the popup window through the style argument.

[6]:
js_callback = mols2grid.make_popup_callback(
    title="${data['NAME']}",
    subtitle="${data['SMILES']}",
    svg="${svg}",
    js="""
        var mol = RDKit.get_mol(data["SMILES"]);
        var svg = mol.get_svg(400, 300);
        var desc = JSON.parse(mol.get_descriptors());
        var inchikey = RDKit.get_inchikey_for_inchi(mol.get_inchi());
        mol.delete();
    """,
    html="""
        <b>Molecular weight</b>: ${desc.exactmw}<br/>
        <b>HBond Acceptors</b>: ${desc.NumHBA}<br/>
        <b>HBond Donors</b>: ${desc.NumHBD}<br/>
        <b>TPSA</b>: ${desc.tpsa}<br/>
        <b>ClogP</b>: ${desc.CrippenClogP}<br/>
        <hr>
        <b>InChIKey</b>: ${inchikey}
    """,
    style="border-radius: 10px",
)

mols2grid.display(
    df,
    callback=js_callback,
)
[6]:

This functionality is directly available in mols2grid by using the mols2grid.callbacks.info() function:

mols2grid.display(
    df, callback=mols2grid.callbacks.info(),
)

It is possible to load additional JS libraries by passing custom_header="<script src=...></script>" to mols2grid.display, and they will then be available in the callback.

Displaying the 3D structure with 3Dmol.js

In the following example, we query PubChem using the SMILES of the molecule (and Cactus as a fallback, but you can also provide another custom REST API), then fetch the 3D structure in SDF format and display it with 3Dmol.js:

[7]:
mols2grid.display(
    df,
    callback=mols2grid.callbacks.show_3d(),
)
[7]: