{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from openff.toolkit import Molecule" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: The content below demonstrates usage of `nglview` with `openforcefield`. This can be tricky to get working. Install with:\n", "\n", " conda install -c conda-forge nglview\n", " \n", "And configure for use with Jupyter with:\n", "\n", " jupyter-nbextension enable nglview --py --sys-prefix\n", " \n", "To use with Jupyterlab, configure with:\n", "\n", " jupyter labextension install nglview-js-widgets\n", " jupyter-labextension install @jupyter-widgets/jupyterlab-manager" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Built-in visualizations in `openff-toolkit`\n", "\n", "PR [#560](https://github.com/openforcefield/openforcefield/pull/560) introduced rich representation for the `Molecule` objects. This means you can visualize them in your Jupyter Notebooks.\n", "\n", "We have implemented three backends:\n", "- rdkit\n", "- openeye\n", "- nglview (requires conformers)\n", "\n", "There are two ways to invoke the visualization:\n", "- implicitly, by _evaluating_ the object in a cell\n", "- explicitly, by calling `Molecule.visualize()`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Implicit_ visualization will try to use `nglview` if there are conformers and fall back to `rdkit` and `openeye` (in that order) if they are not available." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "eb5ef9732d0b469abefa109be1c2553c", "version_major": 2, "version_minor": 0 }, "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/svg+xml": [ "\n", "\n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "m = Molecule.from_smiles(\"CCCCOCC\")\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The regular `display()` call works on `Molecule` objects too." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(m) # noqa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Explicit_ visualization works as one would expect:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.visualize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This method can take a `backend` parameter, which defaults to `rdkit`:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.visualize(backend=\"rdkit\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`openeye` can also be used, if available:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "try:\n", " from openeye import oechem\n", "\n", " assert oechem.OEChemIsLicensed()\n", "\n", " m.visualize(backend=\"openeye\")\n", "except (ImportError, AssertionError):\n", " print('Visualizing with `backend=\"openeye\"` requires the OpenEye Toolkits')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`nglview`, if installed, can only be used if conformers have been generated:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Visualizing with NGLview requires that the molecule has conformers.\n" ] } ], "source": [ "try:\n", " m.visualize(backend=\"nglview\") # this will fail because we have no conformers yet\n", "except ValueError as excinfo:\n", " # Catch the exception and print its message\n", " print(str(excinfo))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But, once you generate them, it works! You can zoom in/out, rotate and translate the molecule. You can even inspect the different conformers (if available) using the trajectory player:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "6fcbd2baf38244cba5ba31cf0bd86f14", "version_major": 2, "version_minor": 0 }, "text/plain": [ "NGLWidget(max_frame=2)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "m.generate_conformers()\n", "m.visualize(backend=\"nglview\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For example, a benzene ring will not have multiple conformers, so you won't see the trajectory player." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "041384084ceb41fcb23c677e445eaa6a", "version_major": 2, "version_minor": 0 }, "text/plain": [ "NGLWidget()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "n = Molecule.from_smiles(\"c1ccccc1\")\n", "n.generate_conformers()\n", "n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that, once conformers are available, the implicit representation will use `nglview` to provide a 3D visualization." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.12" } }, "nbformat": 4, "nbformat_minor": 4 }