{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Docking Ligands to Proteins\n", "\n", "> ### In this tutorial we will cover:\n", "> - how we can use BuildAMol's `docking` extension to facilitate the docking process of Molecules" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "BuildAMol is intented to let users _build_ molecular structures in any way they like. But it also tries to facilitate downstream research workflows in order to provide a streamlined user experience. Therefore we added a `docking` extension in version `1.2.9` to facilitate the process of using [AutoDock Vina](https://github.com/ccsb-scripps/AutoDock-Vina) from Python.\n", "\n", "The `docking` extension acts as a wrapper and forwards to different docking libraries. Currently available docking backends are: (1) `easydock` package by [Minibaeva et al. (2023)](https://jcheminf.biomedcentral.com/articles/10.1186/s13321-023-00772-2) and (2) `dockstring` by [García-Ortegón et al. (2022)](https://pubs.acs.org/doi/full/10.1021/acs.jcim.1c01334). Naturally, you will need to install these libraries and their dependencies in order to run the docking. Check out their GitHub pages to learn more about their installation (it's not difficult 😄).\n", "\n", "That being said, let's get started!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading a Protein and getting a Ligand\n", "\n", "To keep things simple, we will use the protein and ligand from the [Ligand Design Tutorial](https://biobuild.readthedocs.io/en/latest/examples/ligand_design.html). " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import buildamol as bam\n", "\n", "protein = bam.read_pdb(\"files/DRD2.pdb\")\n", "ligand = bam.read_pdb(\"files/DRD2_ligand.pdb\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "application/3dmoljs_load.v0": "
\n

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n
\n", "text/html": [ "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "v = protein.py3dmol(\"cartoon\", color=\"white\")\n", "v += ligand.py3dmol(\"stick\", color=\"blue\")\n", "v.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading the Docking Backend\n", "\n", "Next we import the `docking` extension. The central hub we can use then is the `dock` function. By default the backend will be set to `easydock` but we can change the backend using the `set_docking_backend` function. " ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "from buildamol.extensions import docking" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we can directly import a specific backend using: \n", "\n", "```python\n", "# directly import from whatever backend you prefer\n", "from buildamol.extensions.docking import easydock\n", "# or\n", "from buildamol.extensions.docking import dockstring\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In any case we now have access to a `dock` function that allows us to dock our ligand to our protein." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Docking our Ligand (using _easydock_, default)\n", "\n", "In order to dock our ligand, both `easydock` and `dockstring` need to know where we want to dock to - i.e. we need to pass some coordinates of a binding pocket. In this case, we luckily know where the binding pocket is: it's just where our current ligand is already docket 😉" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "sys:1: DeprecationWarning: builtin type swigvarlink has no __module__ attribute\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C20) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C21) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C25) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C22) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C24) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C23) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C36) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C37) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C41) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C38) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C40) with given element 'A'\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Atom.py:237: PDBConstructionWarning:\n", "\n", "Used element 'C' for Atom (name=C39) with given element 'A'\n", "\n" ] } ], "source": [ "# where to dock (only works because our ligand came from a previous docking run, normally we would\n", "# need to figure out a binding site first or write some code to determine a binding site)\n", "center = ligand.center_of_geometry\n", "\n", "# define the box size for docking\n", "size = (20, 20, 20)\n", "\n", "# run docking\n", "docked_poses = docking.dock(protein=protein, ligand=ligand, center=center, box_size=size)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`docked_poses` will be a `Molecule` instance with multiple `Model`s (one for each docked pose). \n", "\n", "> In case of `dockstring` each `Model` will additionally have a `docking_score` attribute (easydock sadly doesn't provide a per-pose docking score)." ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[Model(1), Model(2), Model(3), Model(4), Model(5)]\n" ] } ], "source": [ "# let's check out the models (=poses)\n", "print(docked_poses.models)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And with that we can visualize the results with py3dmol:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `2` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `3` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `4` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `5` to `0` might create access inconsistencies to children of the parent entity.\n", "\n" ] }, { "data": { "application/3dmoljs_load.v0": "
\n

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n
\n", "text/html": [ "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "v = protein.py3dmol(\"cartoon\", color=\"white\")\n", "v += ligand.py3dmol(\"stick\", color=\"black\")\n", "\n", "# split the multi-model molecule into single-model molecules\n", "docked_poses = docked_poses.split_models()\n", "for pose, color in zip(docked_poses, [\"red\", \"green\", \"blue\", \"yellow\", \"orange\"]):\n", " v += pose.py3dmol(\"stick\", color=color)\n", "v.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And there we are! Honestly, the poses look somewhat worse when using `easydock` compared to the ones from `dockstring` (at least without tweaking the default parameters) but it's faster to compute. If you want to use `dockstring` instead here's how:\n", "\n", "## Docking our Ligand (using _dockstring_)\n", "\n", "To switch backends we simply need to call `set_docking_backend` with the argument `\"dockstring\"`. The rest of the procedure remains the same:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/dockstring/utils.py:76: DockstringWarning:\n", "\n", "Although Mac use is supported, docking scores on Mac do not always perfectly match scores from Linux. Therefore, extra care should be taken when comparing results to other platforms. In particular, the baselines in the DOCKSTRING paper were computed on Linux, so please do not directly compare your docking scores to the scores reported on the paper.\n", "\n" ] } ], "source": [ "# switch docking backend\n", "docking.set_docking_backend(\"dockstring\")\n", "\n", "# run docking\n", "docked_poses = docking.dock(protein=protein, ligand=ligand, center=center, box_size=size)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since we are using `dockstring` now we also get access to the docking scores now:" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model(0) -11.6\n", "Model(1) -11.1\n", "Model(2) -11.1\n", "Model(3) -11.0\n", "Model(4) -10.7\n", "Model(5) -10.6\n", "Model(6) -10.5\n", "Model(7) -10.2\n", "Model(8) -10.1\n" ] } ], "source": [ "for model in docked_poses.models:\n", " print(model, model.docking_score)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Actually, the models are by default, sorted from lowest to highest docking score (remember that a lower docking score is better)." ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `1` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `2` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `3` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `4` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `5` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `6` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `7` to `0` might create access inconsistencies to children of the parent entity.\n", "\n", "/opt/anaconda3/envs/docking/lib/python3.12/site-packages/Bio/PDB/Entity.py:197: BiopythonWarning:\n", "\n", "The id `0` is already used for a sibling of this entity. Changing id from `8` to `0` might create access inconsistencies to children of the parent entity.\n", "\n" ] }, { "data": { "application/3dmoljs_load.v0": "
\n

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n
\n", "text/html": [ "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# the visualize the docked poses\n", "\n", "\n", "import matplotlib\n", "colors = list(matplotlib.colors.CSS4_COLORS.keys())\n", "\n", "v = protein.py3dmol(\"cartoon\", color=\"white\")\n", "v += ligand.py3dmol(\"stick\", color=\"black\")\n", "\n", "# split the multi-model molecule into single-model molecules\n", "docked_poses = docked_poses.split_models()\n", "for pose, color in zip(docked_poses, colors[:len(docked_poses)]):\n", " v += pose.py3dmol(\"stick\", color=color)\n", "\n", "v.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And that's it for this tutorial! Thanks for checking out this tutorial and hopefully you found it helpful for your research. Good luck in your project using BuildAMol!" ] } ], "metadata": { "kernelspec": { "display_name": "docking", "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.12.9" } }, "nbformat": 4, "nbformat_minor": 2 }