diff --git a/cookbook/assets/calc_dg.tsv b/cookbook/assets/calc_dg.tsv index 669d449e..6c4f9192 100644 --- a/cookbook/assets/calc_dg.tsv +++ b/cookbook/assets/calc_dg.tsv @@ -1,11 +1,11 @@ ligand DG(MLE) (kcal/mol) uncertainty (kcal/mol) -lig_ejm_31 -0.09 0.05 -lig_ejm_42 0.7 0.1 -lig_ejm_46 -0.98 0.05 -lig_ejm_47 -0.1 0.1 -lig_ejm_48 0.53 0.09 -lig_ejm_50 0.91 0.06 -lig_ejm_43 2.0 0.2 -lig_jmc_23 -0.68 0.09 -lig_jmc_27 -1.1 0.1 -lig_jmc_28 -1.25 0.08 +lig_ejm_31 0.04 0.05 +lig_ejm_42 0.53 0.09 +lig_ejm_43 1.7 0.1 +lig_ejm_46 -0.69 0.07 +lig_ejm_47 0.0 0.2 +lig_ejm_48 0.5 0.2 +lig_ejm_50 0.98 0.08 +lig_jmc_23 -1.08 0.08 +lig_jmc_27 -1.3 0.1 +lig_jmc_28 -0.81 0.08 diff --git a/cookbook/assets/experimental.tsv b/cookbook/assets/experimental.tsv index 2f2e07f8..ff2d3a1f 100644 --- a/cookbook/assets/experimental.tsv +++ b/cookbook/assets/experimental.tsv @@ -1,4 +1,5 @@ ligand estimate (kcal/mol) uncertainty (kcal/mol) +lig_ejm_31 -9.57 0.18 lig_ejm_42 -9.81 0.18 lig_ejm_43 -8.29 0.18 lig_ejm_45 -9.59 0.18 diff --git a/plotting_rbfes_with_cinnabar/final_results.tsv b/cookbook/assets/final_results.tsv similarity index 100% rename from plotting_rbfes_with_cinnabar/final_results.tsv rename to cookbook/assets/final_results.tsv diff --git a/cookbook/cinnabar_absolute.ipynb b/cookbook/cinnabar_absolute.ipynb deleted file mode 100644 index f3cdbe24..00000000 --- a/cookbook/cinnabar_absolute.ipynb +++ /dev/null @@ -1,191 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "ddae61fd-fa15-4be9-9160-ba3e195c67dc", - "metadata": {}, - "source": [ - "# Plotting OpenFE DG results against experiment using Cinnabar v0.6.0\n", - "\n", - "This notebook shows how one would go about creating a ``cinnabar`` style plot of OpenFE results against known experimental values. For more information on using the ``cinnabar`` API please see the [tutorials](https://cinnabar.openfree.energy/en/latest/tutorials/index.html)." - ] - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# First, we import the required libraries\n", - "%matplotlib inline\n", - "%config InlineBackend.figure_formats = ['svg']\n", - "import pandas as pd\n", - "from cinnabar import FEMap, plotting\n", - "from openff.units import unit" - ], - "id": "da7a708265bac6d9" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Loading experimental data\n", - "\n", - "First, we load the experimental data from a tab-separated values (TSV) file\n", - "\n", - "The format of the TSV file is as follows:\n", - "\n", - "```\n", - "ligand estimate (kcal/mol) uncertainty (kcal/mol)\n", - "```" - ], - "id": "d3b74ffc20c6622" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "experimental_data = pd.read_csv('assets/experimental.tsv', sep=\"\\t\")\n", - "experimental_data" - ], - "id": "5b402aa460d39cfb" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Loading free energy results\n", - "\n", - "Next we load in results from the TSV file created by running `openfe gather --report dg` on a network of results from [relative binding free energy calculations](https://docs.openfree.energy/en/latest/guide/protocols/relativehybridtopology.html#overview). [Absolute binding free energy estimates](https://docs.openfree.energy/en/latest/guide/protocols/absolutebinding.html) can also be used here, a report in the same format can be generated by running `openfe gather-abfe --report dg`.\n", - "\n", - "Please see the following tutorial for more information on how to run the gather command: https://github.com/OpenFreeEnergy/ExampleNotebooks/blob/main/rbfe_tutorial/cli_tutorial.md\n", - "\n", - "
\n", - "Note: If there is no experimental binding free energy for a ligand, that ligand's calcuated data will be excluded from the plot.\n", - "
" - ], - "id": "a9d25f4c1758b866" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "calculated_data = pd.read_csv('assets/calc_dg.tsv', sep=\"\\t\")\n", - "calculated_data" - ], - "id": "1d6fb223da1efe00" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "
\n", - "Note: When using results from relative binding afinity calculations, the derived absolute binding afinites will be centered around zero rather than the experimental mean. Thus an offset should be applied to the calculated results before comparing them.\n", - "
\n", - "\n", - "You can read more about absolute estimators in the [cinnabar guide](https://cinnabar.openfree.energy/en/latest/concepts/estimators.html#centering-of-results)\n", - "\n", - "Next, we will use the ``cinnabar`` API to gather the experimental and calculated results into a single object:" - ], - "id": "8781f5c4ff6493c1" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Create FEMap\n", - "fe_map = FEMap()\n", - "\n", - "# add the experimental data\n", - "for index, row in experimental_data.iterrows():\n", - " fe_map.add_experimental_measurement(\n", - " label=row['ligand'],\n", - " value=row['estimate (kcal/mol)'] * unit.kilocalories_per_mole,\n", - " uncertainty=row['uncertainty (kcal/mol)'] * unit.kilocalories_per_mole,\n", - " source=\"Experimental\"\n", - " )\n", - "\n", - "# add the computed data\n", - "for index, row in calculated_data.iterrows():\n", - " fe_map.add_absolute_calculation(\n", - " label=row['ligand'],\n", - " value=row[\"DG(MLE) (kcal/mol)\"] * unit.kilocalories_per_mole,\n", - " uncertainty=row[\"uncertainty (kcal/mol)\"] * unit.kilocalories_per_mole,\n", - " source=\"openfe\"\n", - " )" - ], - "id": "c3a96a00cabbd790" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "We can then check that the absolute measurements were added correctly:", - "id": "883ce05e186f631d" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "fe_map.get_absolute_dataframe()", - "id": "9f5f9ff2b2628be8" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "Finally, we can use ``cinnabar`` to plot the calculated vs. experimental results with some accuracy and ranking metrics:", - "id": "bf9d8fcff63cc1e7" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "plotting.plot_DGs(\n", - " fe_map, \n", - " source=\"openfe\", # the name of the computational source to plot\n", - " figsize=5, \n", - " shift=experimental_data[\"estimate (kcal/mol)\"].mean(), # shift the computed values by the mean of the experimental values to put them on a similar scale\n", - " xy_lim=[-15, -5]\n", - " )" - ], - "id": "641c870dbd8a0021" - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b7a7fa721a373142", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "openfe_dev", - "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": 5 -} diff --git a/plotting_rbfes_with_cinnabar/PlottingFreeEnergiesUsingCinnabar.ipynb b/cookbook/plot_results_with_cinnabar.ipynb similarity index 71% rename from plotting_rbfes_with_cinnabar/PlottingFreeEnergiesUsingCinnabar.ipynb rename to cookbook/plot_results_with_cinnabar.ipynb index 955cc0d8..00899eae 100644 --- a/plotting_rbfes_with_cinnabar/PlottingFreeEnergiesUsingCinnabar.ipynb +++ b/cookbook/plot_results_with_cinnabar.ipynb @@ -5,9 +5,20 @@ "id": "ddae61fd-fa15-4be9-9160-ba3e195c67dc", "metadata": {}, "source": [ - "# Plotting OpenFE results against experiment using Cinnabar v0.6.0\n", + "# Plot results against experiment with cinnabar\n", "\n", - "This notebook shows how one would go about creating a ``cinnabar`` style plot of OpenFE results against known experimental values. For more information on the ``cinnabar`` API and the available plot styles, see the [tutorials](https://cinnabar.openfree.energy/en/latest/tutorials/index.html)." + "Here, we show how to plot OpenFE free energy results against experimental values with [cinnabar](https://github.com/OpenFreeEnergy/cinnabar). It covers:\n", + "\n", + "1. **relative free energies**, from the table written by `openfe gather --report ddg`, and the absolute free energies derived from them, and\n", + "2. **absolute free energies**, from the table written by `openfe gather --report dg`, `openfe gather-abfe --report dg` or `openfe gather-septop --report dg`.\n", + "\n", + "For more on the `cinnabar` API and the available plot styles, see the [cinnabar tutorials](https://cinnabar.openfree.energy/en/latest/tutorials/index.html).\n", + "\n", + "
\n", + "\n", + "**Note:** This notebook requires `cinnabar` 0.6 or later, which is installed with openfe. With older versions, the plotting functions fail with errors such as `'FEMap' object has no attribute 'edges'`.\n", + "\n", + "
" ] }, { @@ -36,7 +47,7 @@ " \n", " !pip install -q condacolab\n", " import condacolab\n", - " condacolab.install_from_url(\"https://github.com/OpenFreeEnergy/openfe/releases/download/v1.7.0/OpenFEforge-1.7.0-Linux-x86_64.sh\")" + " condacolab.install_from_url(\"https://github.com/OpenFreeEnergy/openfe/releases/download/v1.13.0/OpenFEforge-1.13.0-Linux-x86_64.sh\")" ] }, { @@ -81,16 +92,12 @@ "\n", "```\n", "ligand estimate (kcal/mol) uncertainty (kcal/mol)\n", - "```\n", - "\n", - "**Important note:**\n", - "Please note that for now you must have an experimental entry for every ligand involved in your free energy network.\n", - "In future versions of cinnabar this will no longer be needed." + "```" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "id": "6abcaae7-f5fd-483c-972f-5bb5b6d4908a", "metadata": {}, "outputs": [], @@ -105,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "id": "8b80f592-f1a3-4c7f-8757-58a88c2e8ee7", "metadata": {}, "outputs": [ @@ -235,14 +242,14 @@ "12 lig_jmc_28 -11.01 0.18" ] }, - "execution_count": 4, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# read in the experimental data\n", - "experimental_data = pd.read_csv('experimental.tsv', sep=\"\\t\")\n", + "experimental_data = pd.read_csv('assets/experimental.tsv', sep=\"\\t\")\n", "experimental_data" ] }, @@ -251,16 +258,22 @@ "id": "aca5ede7-3741-4cc1-97ba-9115d90abd96", "metadata": {}, "source": [ - "## Loading free energy results\n", + "## Plotting relative free energy results\n", + "\n", + "### Loading the results\n", "\n", "Next we load in results from the TSV file created by running `openfe gather --report ddg` on a network of results from [relative binding free energy calculations](https://docs.openfree.energy/en/latest/guide/protocols/relativehybridtopology.html#overview).\n", "\n", - "Please see the full [RBFE gather command tutorial](https://github.com/OpenFreeEnergy/ExampleNotebooks/blob/main/rbfe_tutorial/cli_tutorial.md) for more information." + "Please see the full [RBFE gather command tutorial](https://github.com/OpenFreeEnergy/ExampleNotebooks/blob/main/rbfe_tutorial/cli_tutorial.md) for more information.\n", + "\n", + "
\n", + "Note: Each openfe gather command only reads the results of one protocol. For networks that combine protocols, for example hybrid topology and Separated Topologies edges, load the results in Python and add them to a single FEMap, as shown in the Mixed Protocol Networks tutorial.\n", + "
" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "id": "63a920b3-6ef3-4214-b3cc-433319053721", "metadata": {}, "outputs": [ @@ -372,14 +385,14 @@ "8 lig_ejm_46 lig_jmc_28 -0.12 0.04" ] }, - "execution_count": 5, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Read in calculated relative free energy results\n", - "calculated_data = pd.read_csv('final_results.tsv', sep=\"\\t\")\n", + "calculated_data = pd.read_csv('assets/final_results.tsv', sep=\"\\t\")\n", "calculated_data" ] }, @@ -388,7 +401,7 @@ "id": "a1daf9cf-5107-4564-a200-b9fe670837cb", "metadata": {}, "source": [ - "## Creating a Cinnabar ``FEMap``\n", + "### Creating a Cinnabar ``FEMap``\n", "\n", "Next we will use the ``cinnabar`` API to gather the experimental and calculated results into a single object which we can use to plot and analyse the network of results.\n", "\n", @@ -397,7 +410,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "id": "16d98240-62b3-469c-a12a-c2b8337caba9", "metadata": {}, "outputs": [], @@ -438,14 +451,14 @@ "id": "7dea03c7-6b6a-4e59-96e7-a94cdc9047e9", "metadata": {}, "source": [ - "## Plotting the results using Cinnabar\n", + "### Plotting the results using Cinnabar\n", "\n", "Once we've created the ``FEMap`` we can inspect the alchemical network:" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 5, "id": "86c004bc-bc58-4a55-92e2-151beb994d65", "metadata": {}, "outputs": [ @@ -460,11 +473,11 @@ " \n", " \n", " \n", - " 2026-06-11T16:46:07.194312\n", + " 2026-11-09T17:07:21.963340\n", " image/svg+xml\n", " \n", " \n", - " Matplotlib v3.10.6, https://matplotlib.org/\n", + " Matplotlib v3.10.9, https://matplotlib.org/\n", " \n", " \n", " \n", @@ -486,96 +499,96 @@ " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: none; stroke: #808080; stroke-linecap: round\"/>\n", " \n", + "\" clip-path=\"url(#p6521fe8fd4)\" style=\"fill: #808080; stroke: #808080; stroke-linecap: round\"/>\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", @@ -801,7 +814,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -863,7 +876,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -912,7 +925,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -941,7 +954,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -999,7 +1012,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1064,7 +1077,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1081,7 +1094,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1121,7 +1134,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1138,7 +1151,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1424,7 +1437,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1454,7 +1467,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 6, "id": "2edeabb9-9c07-49be-a83f-9622ef742046", "metadata": {}, "outputs": [ @@ -1469,11 +1482,11 @@ " \n", " \n", " \n", - " 2026-06-11T16:46:07.934913\n", + " 2026-11-09T17:07:22.924216\n", " image/svg+xml\n", " \n", " \n", - " Matplotlib v3.10.6, https://matplotlib.org/\n", + " Matplotlib v3.10.9, https://matplotlib.org/\n", " \n", " \n", " \n", @@ -1502,7 +1515,7 @@ " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none\"/>\n", " \n", " \n", " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1656,7 +1669,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1686,7 +1699,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1722,7 +1735,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1735,7 +1748,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2126,12 +2139,12 @@ " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2156,7 +2169,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2199,7 +2212,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2215,7 +2228,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2231,7 +2244,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2246,7 +2259,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2261,7 +2274,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2276,7 +2289,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2291,7 +2304,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2409,21 +2422,21 @@ " \n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 1.5; stroke-linecap: square\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke: #808080; stroke-width: 1.5; stroke-linecap: square\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p698636436a)\" style=\"fill: none; stroke-dasharray: 1.5,2.475; stroke-dashoffset: 0; stroke: #000000; stroke-width: 1.5\"/>\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", " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -2484,7 +2497,7 @@ "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2518,7 +2531,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -2631,7 +2644,7 @@ " \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", - " \n", + " \n", " \n", " \n", " \n", @@ -3097,7 +3110,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3132,7 +3145,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 7, "id": "f39ef3c0-4d74-4c53-83bc-94d820428d47", "metadata": {}, "outputs": [ @@ -3147,11 +3160,11 @@ " \n", " \n", " \n", - " 2026-06-11T16:46:09.054363\n", + " 2026-11-09T17:07:24.275508\n", " image/svg+xml\n", " \n", " \n", - " Matplotlib v3.10.6, https://matplotlib.org/\n", + " Matplotlib v3.10.9, https://matplotlib.org/\n", " \n", " \n", " \n", @@ -3180,7 +3193,7 @@ " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none\"/>\n", " \n", " \n", " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3341,7 +3354,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3371,7 +3384,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3407,7 +3420,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3420,7 +3433,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3810,12 +3823,12 @@ " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3840,7 +3853,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3883,7 +3896,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3899,7 +3912,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3915,7 +3928,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3930,7 +3943,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3945,7 +3958,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3960,7 +3973,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -3975,7 +3988,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -4092,11 +4105,11 @@ " \n", " \n", + "\" clip-path=\"url(#p6cf072339e)\" style=\"fill: none; stroke-dasharray: 1.5,2.475; stroke-dashoffset: 0; stroke: #000000; stroke-width: 1.5\"/>\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", " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -4160,7 +4173,7 @@ "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -4194,7 +4207,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -4323,7 +4336,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", - " \n", " \n", + " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -4692,7 +4705,7 @@ " \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", + " \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", " \n", @@ -4813,7 +4828,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -4823,7 +4838,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -4921,7 +4936,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -4950,12 +4965,12 @@ "id": "a905416e-11bd-47cb-8002-5ac923b0e95b", "metadata": {}, "source": [ - "We can also shift our free energies by the average experimental value to have DGs on the same scale as experiment." + "The MLE estimates are centred around zero, because relative calculations only determine free energy differences between ligands, not their absolute offset. To compare them with experiment, we shift them by the mean of the experimental values. You can read more about this in the [cinnabar guide](https://cinnabar.openfree.energy/en/latest/concepts/estimators.html#centering-of-results)." ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 8, "id": "7fed7b2c-076f-4f98-818d-abdbdaf3121b", "metadata": {}, "outputs": [ @@ -4970,11 +4985,11 @@ " \n", " \n", " \n", - " 2026-06-11T16:46:10.193190\n", + " 2026-11-09T17:07:25.598327\n", " image/svg+xml\n", " \n", " \n", - " Matplotlib v3.10.6, https://matplotlib.org/\n", + " Matplotlib v3.10.9, https://matplotlib.org/\n", " \n", " \n", " \n", @@ -5003,7 +5018,7 @@ " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke: #808080; stroke-width: 2\"/>\n", " \n", " \n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none\"/>\n", " \n", " \n", " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5179,7 +5194,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5194,7 +5209,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5232,7 +5247,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5278,7 +5293,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5710,12 +5725,12 @@ " \n", " \n", " \n", - " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5741,7 +5756,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5785,7 +5800,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5802,7 +5817,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5819,7 +5834,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5836,7 +5851,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5852,7 +5867,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5868,7 +5883,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -5884,7 +5899,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -6002,11 +6017,11 @@ " \n", " \n", + "\" clip-path=\"url(#pce58a87977)\" style=\"fill: none; stroke-dasharray: 1.5,2.475; stroke-dashoffset: 0; stroke: #000000; stroke-width: 1.5\"/>\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", " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -6070,7 +6085,7 @@ "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -6104,7 +6119,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -6602,7 +6617,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -6662,7 +6677,7 @@ " \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", @@ -6833,7 +6848,7 @@ " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -6863,14 +6878,14 @@ "id": "0c1b5935-d11b-4c1b-b092-038b007323ce", "metadata": {}, "source": [ - "## Writing out the MLE derived absolute free energies\n", + "### Writing out the MLE derived absolute free energies\n", "\n", "Finally, we can also extract the MLE derived absolute free energies along with the experimental results into a pandas ``DataFrame``." ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 9, "id": "26b09073-f05f-401c-a10f-95c6c957f4da", "metadata": {}, "outputs": [ @@ -7143,7 +7158,7 @@ "22 True " ] }, - "execution_count": 11, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -7165,7 +7180,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "id": "8069c254", "metadata": {}, "outputs": [ @@ -7296,7 +7311,7 @@ "9 lig_jmc_28 -0.809 0.079335 MLE True" ] }, - "execution_count": 12, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -7305,11 +7320,2351 @@ "mle_df = abs_df[abs_df[\"source\"] == \"MLE\"].reset_index(drop=True)\n", "mle_df" ] + }, + { + "cell_type": "markdown", + "id": "7df44b07-43d1-40eb-bf45-8f1d5a860d7a", + "metadata": {}, + "source": [ + "## Plotting absolute free energy results\n", + "\n", + "Absolute free energies can also be plotted directly from a table of free energies per ligand. This table can be written by:\n", + "\n", + "* `openfe gather --report dg` or `openfe gather-septop --report dg`, which derive the absolute free energies from a network of relative free energy calculations using the MLE estimator, or\n", + "* `openfe gather-abfe --report dg`, for results from the [Absolute Binding](https://docs.openfree.energy/en/latest/guide/protocols/absolutebinding.html) Protocol.\n", + "\n", + "Here we load the results of `openfe gather --report dg` for a network of relative binding free energy calculations. The free energy column is called `DG(MLE) (kcal/mol)` in this report, and `DG (kcal/mol)` in the `gather-septop` and `gather-abfe` reports.\n", + "\n", + "
\n", + "Note: If there is no experimental binding free energy for a ligand, that ligand's calculated data will be excluded from the plot.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "4638d997-5252-465c-bd40-aa368c68acd3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\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", + " \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", + "
ligandDG(MLE) (kcal/mol)uncertainty (kcal/mol)
0lig_ejm_310.040.05
1lig_ejm_420.530.09
2lig_ejm_431.700.10
3lig_ejm_46-0.690.07
4lig_ejm_470.000.20
5lig_ejm_480.500.20
6lig_ejm_500.980.08
7lig_jmc_23-1.080.08
8lig_jmc_27-1.300.10
9lig_jmc_28-0.810.08
\n", + "
" + ], + "text/plain": [ + " ligand DG(MLE) (kcal/mol) uncertainty (kcal/mol)\n", + "0 lig_ejm_31 0.04 0.05\n", + "1 lig_ejm_42 0.53 0.09\n", + "2 lig_ejm_43 1.70 0.10\n", + "3 lig_ejm_46 -0.69 0.07\n", + "4 lig_ejm_47 0.00 0.20\n", + "5 lig_ejm_48 0.50 0.20\n", + "6 lig_ejm_50 0.98 0.08\n", + "7 lig_jmc_23 -1.08 0.08\n", + "8 lig_jmc_27 -1.30 0.10\n", + "9 lig_jmc_28 -0.81 0.08" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "calculated_dg_data = pd.read_csv('assets/calc_dg.tsv', sep=\"\\t\")\n", + "calculated_dg_data" + ] + }, + { + "cell_type": "markdown", + "id": "c2774fc9-2874-4483-9d72-f402f65eb66b", + "metadata": {}, + "source": [ + "Next, we gather the experimental and calculated results into a new ``FEMap``:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "6cdb7f24-8f9b-424a-ab29-3c4634c63e19", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\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", + " \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", + " \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", + " \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", + " \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", + "
labelDG (kcal/mol)uncertainty (kcal/mol)sourcecomputational
0lig_ejm_31-9.570.18ExperimentalFalse
1lig_ejm_42-9.810.18ExperimentalFalse
2lig_ejm_43-8.290.18ExperimentalFalse
3lig_ejm_45-9.590.18ExperimentalFalse
4lig_ejm_46-11.350.17ExperimentalFalse
5lig_ejm_47-9.730.18ExperimentalFalse
6lig_ejm_48-9.030.18ExperimentalFalse
7lig_ejm_50-9.010.18ExperimentalFalse
8lig_ejm_54-10.570.18ExperimentalFalse
9lig_ejm_55-9.240.18ExperimentalFalse
10lig_jmc_23-11.740.18ExperimentalFalse
11lig_jmc_27-11.310.17ExperimentalFalse
12lig_jmc_28-11.010.18ExperimentalFalse
13lig_ejm_310.040.05openfeTrue
14lig_ejm_420.530.09openfeTrue
15lig_ejm_431.700.10openfeTrue
16lig_ejm_46-0.690.07openfeTrue
17lig_ejm_470.000.20openfeTrue
18lig_ejm_480.500.20openfeTrue
19lig_ejm_500.980.08openfeTrue
20lig_jmc_23-1.080.08openfeTrue
21lig_jmc_27-1.300.10openfeTrue
22lig_jmc_28-0.810.08openfeTrue
\n", + "
" + ], + "text/plain": [ + " label DG (kcal/mol) uncertainty (kcal/mol) source \\\n", + "0 lig_ejm_31 -9.57 0.18 Experimental \n", + "1 lig_ejm_42 -9.81 0.18 Experimental \n", + "2 lig_ejm_43 -8.29 0.18 Experimental \n", + "3 lig_ejm_45 -9.59 0.18 Experimental \n", + "4 lig_ejm_46 -11.35 0.17 Experimental \n", + "5 lig_ejm_47 -9.73 0.18 Experimental \n", + "6 lig_ejm_48 -9.03 0.18 Experimental \n", + "7 lig_ejm_50 -9.01 0.18 Experimental \n", + "8 lig_ejm_54 -10.57 0.18 Experimental \n", + "9 lig_ejm_55 -9.24 0.18 Experimental \n", + "10 lig_jmc_23 -11.74 0.18 Experimental \n", + "11 lig_jmc_27 -11.31 0.17 Experimental \n", + "12 lig_jmc_28 -11.01 0.18 Experimental \n", + "13 lig_ejm_31 0.04 0.05 openfe \n", + "14 lig_ejm_42 0.53 0.09 openfe \n", + "15 lig_ejm_43 1.70 0.10 openfe \n", + "16 lig_ejm_46 -0.69 0.07 openfe \n", + "17 lig_ejm_47 0.00 0.20 openfe \n", + "18 lig_ejm_48 0.50 0.20 openfe \n", + "19 lig_ejm_50 0.98 0.08 openfe \n", + "20 lig_jmc_23 -1.08 0.08 openfe \n", + "21 lig_jmc_27 -1.30 0.10 openfe \n", + "22 lig_jmc_28 -0.81 0.08 openfe \n", + "\n", + " computational \n", + "0 False \n", + "1 False \n", + "2 False \n", + "3 False \n", + "4 False \n", + "5 False \n", + "6 False \n", + "7 False \n", + "8 False \n", + "9 False \n", + "10 False \n", + "11 False \n", + "12 False \n", + "13 True \n", + "14 True \n", + "15 True \n", + "16 True \n", + "17 True \n", + "18 True \n", + "19 True \n", + "20 True \n", + "21 True \n", + "22 True " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dg_fe_map = FEMap()\n", + "\n", + "# add the experimental data\n", + "for _, row in experimental_data.iterrows():\n", + " dg_fe_map.add_experimental_measurement(\n", + " label=row['ligand'],\n", + " value=row['estimate (kcal/mol)'] * unit.kilocalories_per_mole,\n", + " uncertainty=row['uncertainty (kcal/mol)'] * unit.kilocalories_per_mole,\n", + " source=\"Experimental\",\n", + " )\n", + "\n", + "# add the calculated data\n", + "for _, row in calculated_dg_data.iterrows():\n", + " dg_fe_map.add_absolute_calculation(\n", + " label=row['ligand'],\n", + " # use row[\"DG (kcal/mol)\"] for gather-abfe and gather-septop reports\n", + " value=row[\"DG(MLE) (kcal/mol)\"] * unit.kilocalories_per_mole,\n", + " uncertainty=row[\"uncertainty (kcal/mol)\"] * unit.kilocalories_per_mole,\n", + " source=\"openfe\",\n", + " )\n", + "\n", + "dg_fe_map.get_absolute_dataframe()" + ] + }, + { + "cell_type": "markdown", + "id": "a9c61065-a716-47be-9da2-3c2d25e44401", + "metadata": {}, + "source": [ + "
\n", + "Note: As above, absolute free energies derived from relative calculations (gather --report dg and gather-septop --report dg) are centred around zero, so we shift them by the mean of the experimental values. Results from absolute binding free energy calculations (gather-abfe) do not need this shift.\n", + "
\n", + "\n", + "Finally, we plot the calculated against the experimental results, with some accuracy and ranking metrics:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "95eaa8f8-deb0-4671-86fd-b094598cb8ae", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " 2026-11-09T17:07:46.131985\n", + " image/svg+xml\n", + " \n", + " \n", + " Matplotlib v3.10.9, https://matplotlib.org/\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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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", + " \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": [ + "plotting.plot_DGs(\n", + " dg_fe_map,\n", + " source=\"openfe\", # the name of the computational source to plot\n", + " figsize=5,\n", + " shift=experimental_data[\"estimate (kcal/mol)\"].mean(), # leave out for ABFE results\n", + " xy_lim=[-15, -5],\n", + ")" + ] } ], "metadata": { "kernelspec": { - "display_name": "openfe_dev", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -7323,7 +9678,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.9" + "version": "3.13.14" } }, "nbformat": 4, diff --git a/plotting_rbfes_with_cinnabar/experimental.tsv b/plotting_rbfes_with_cinnabar/experimental.tsv deleted file mode 100644 index ff2d3a1f..00000000 --- a/plotting_rbfes_with_cinnabar/experimental.tsv +++ /dev/null @@ -1,14 +0,0 @@ -ligand estimate (kcal/mol) uncertainty (kcal/mol) -lig_ejm_31 -9.57 0.18 -lig_ejm_42 -9.81 0.18 -lig_ejm_43 -8.29 0.18 -lig_ejm_45 -9.59 0.18 -lig_ejm_46 -11.35 0.17 -lig_ejm_47 -9.73 0.18 -lig_ejm_48 -9.03 0.18 -lig_ejm_50 -9.01 0.18 -lig_ejm_54 -10.57 0.18 -lig_ejm_55 -9.24 0.18 -lig_jmc_23 -11.74 0.18 -lig_jmc_27 -11.31 0.17 -lig_jmc_28 -11.01 0.18