From 79e2a915dd0262bc9ca38cf08479fc578249be06 Mon Sep 17 00:00:00 2001 From: Zhiyi Wu <zhiyi.wu@msdtc.ox.ac.uk> Date: Fri, 2 Oct 2020 19:36:46 +0100 Subject: [PATCH] dhdl plot for the TI (#110) * partially addresses #73 * add dhdl plot from alchemical-analysis (+ improvements) * add tests and use `# pragma: no cover` for parts of plotting code that are difficult to test * update CHANGES --- CHANGES | 1 + docs/images/dhdl_TI.png | Bin 0 -> 35345 bytes docs/visualisation.rst | 40 ++++ ...visualisation.plot_mbar_overlap_matrix.rst | 2 +- .../alchemlyb.visualisation.plot_ti_dhdl.rst | 22 +++ src/alchemlyb/estimators/mbar_.py | 3 - src/alchemlyb/estimators/ti_.py | 4 + src/alchemlyb/tests/test_visualisation.py | 33 +++- src/alchemlyb/visualisation/__init__.py | 3 +- src/alchemlyb/visualisation/ti_dhdl.py | 175 ++++++++++++++++++ 10 files changed, 276 insertions(+), 7 deletions(-) create mode 100644 docs/images/dhdl_TI.png create mode 100644 docs/visualisation/alchemlyb.visualisation.plot_ti_dhdl.rst create mode 100644 src/alchemlyb/visualisation/ti_dhdl.py diff --git a/CHANGES b/CHANGES index b95aa851..c64a912b 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,7 @@ The rules for this file: Enhancements - Allow the overlap matrix of the MBAR estimator to be plotted. (PR #107) + - Allow the dhdl of the TI estimator to be plotted. (PR #110) Deprecations diff --git a/docs/images/dhdl_TI.png b/docs/images/dhdl_TI.png new file mode 100644 index 0000000000000000000000000000000000000000..1e85be392ff773d7752b0c77dd94920d0525fb5b GIT binary patch literal 35345 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 literal 0 HcmV?d00001 diff --git a/docs/visualisation.rst b/docs/visualisation.rst index e7a03336..8d67d3b3 100644 --- a/docs/visualisation.rst +++ b/docs/visualisation.rst @@ -4,6 +4,14 @@ It is quite often that the user want to visualise the results to gain confidence on the computed free energy. **alchemlyb** provides various visualisation tools to help user to judge the estimate. +.. currentmodule:: alchemlyb.visualisation + +.. autosummary:: + :toctree: visualisation + + plot_mbar_overlap_matrix + plot_ti_dhdl + .. _plot_overlap_matrix: Overlap Matrix of the MBAR @@ -34,6 +42,38 @@ Will give a plot looks like this .. image:: images/O_MBAR.png +.. _plot_TI_dhdl: + +dhdl Plot of the TI +------------------- +In order for the :class:`~alchemlyb.estimators.TI` estimator to work reliably, +the change in the dhdl between lambda state 0 and lambda state 1 should be +adequately sampled. The function :func:`~alchemlyb.visualisation.plot_ti_dhdl` +can be used to assess the change of the dhdl across the lambda states. + +More than one :class:`~alchemlyb.estimators.TI` estimators can be plotted +together as well. :: + + >>> import pandas as pd + >>> from alchemtest.gmx import load_benzene + >>> from alchemlyb.parsing.gmx import extract_dHdl + >>> from alchemlyb.estimators import TI + + >>> bz = load_benzene().data + >>> dHdl_coul = pd.concat([extract_dHdl(xvg, T=300) for xvg in bz['Coulomb']]) + >>> ti_coul = TI().fit(dHdl_coul) + >>> dHdl_vdw = pd.concat([extract_dHdl(xvg, T=300) for xvg in bz['VDW']]) + >>> ti_vdw = TI().fit(dHdl_vdw) + + >>> from alchemlyb.visualisation import plot_ti_dhdl + >>> ax = plot_ti_dhdl([ti_coul, ti_vdw], labels=['Coul', 'VDW'], colors=['r', 'g']) + >>> ax.figure.savefig('dhdl_TI.pdf') + + +Will give a plot looks like this + +.. image:: images/dhdl_TI.png + .. [Klimovich2015] Klimovich, P.V., Shirts, M.R. & Mobley, D.L. Guidelines for the analysis of free energy calculations. J Comput Aided Mol Des 29, 397–411 (2015). https://doi.org/10.1007/s10822-015-9840-9 diff --git a/docs/visualisation/alchemlyb.visualisation.plot_mbar_overlap_matrix.rst b/docs/visualisation/alchemlyb.visualisation.plot_mbar_overlap_matrix.rst index 5323d1a9..a4de37da 100644 --- a/docs/visualisation/alchemlyb.visualisation.plot_mbar_overlap_matrix.rst +++ b/docs/visualisation/alchemlyb.visualisation.plot_mbar_overlap_matrix.rst @@ -1,4 +1,4 @@ -.. _plot_overlap: +.. _visualisation_plot_mbar_overlap_matrix: Plot Overlap Matrix from MBAR ============================= diff --git a/docs/visualisation/alchemlyb.visualisation.plot_ti_dhdl.rst b/docs/visualisation/alchemlyb.visualisation.plot_ti_dhdl.rst new file mode 100644 index 00000000..d4247515 --- /dev/null +++ b/docs/visualisation/alchemlyb.visualisation.plot_ti_dhdl.rst @@ -0,0 +1,22 @@ +.. _visualisation_plot_mbar_plot_ti_dhdl: + +Plot dhdl from TI +================= + +The function :func:`~alchemlyb.visualisation.plot_ti_dhdl` allows +the user to plot the dhdl from :class:`~alchemlyb.estimators.TI` estimator. +Several :class:`~alchemlyb.estimators.TI` estimators could be passed to the +function to give a concerted picture of the whole alchemical transformation. +When custom labels are desirable, the user could pass a list of strings to the +*labels* for labelling each alchemical transformation differently. The color of +each alchemical transformation could also be set by passing a list of color +string to the *colors*. The unit in the y axis could be labelled to other units +by setting *units*, which by default is kcal/mol. The user can pass +:class:`matplotlib.axes.Axes` into the function to have the dhdl drawn on a +specific axes. + +Please check :ref:`How to plot TI dhdl <plot_TI_dhdl>` for usage. + +API Reference +------------- +.. autofunction:: alchemlyb.visualisation.plot_ti_dhdl \ No newline at end of file diff --git a/src/alchemlyb/estimators/mbar_.py b/src/alchemlyb/estimators/mbar_.py index dd8127ae..975d177b 100644 --- a/src/alchemlyb/estimators/mbar_.py +++ b/src/alchemlyb/estimators/mbar_.py @@ -45,9 +45,6 @@ class MBAR(BaseEstimator): states_ : list Lambda states for which free energy differences were obtained. - overlap_matrix: numpy.matrix - The overlap matrix. - """ def __init__(self, maximum_iterations=10000, relative_tolerance=1.0e-7, diff --git a/src/alchemlyb/estimators/ti_.py b/src/alchemlyb/estimators/ti_.py index 7f25dbe3..383341c9 100644 --- a/src/alchemlyb/estimators/ti_.py +++ b/src/alchemlyb/estimators/ti_.py @@ -26,6 +26,9 @@ class TI(BaseEstimator): states_ : list Lambda states for which free energy differences were obtained. + dhdl : DataFrame + The estimated dhdl of each state. + """ def __init__(self, verbose=False): @@ -92,6 +95,7 @@ def fit(self, dHdl): self.delta_f_ = pd.DataFrame(adelta - adelta.T, columns=means.index.values, index=means.index.values) + self.dhdl = means # yield standard deviation d_delta_f_ between each state self.d_delta_f_ = pd.DataFrame(np.sqrt(ad_delta + ad_delta.T), diff --git a/src/alchemlyb/tests/test_visualisation.py b/src/alchemlyb/tests/test_visualisation.py index d482caad..06808ea6 100644 --- a/src/alchemlyb/tests/test_visualisation.py +++ b/src/alchemlyb/tests/test_visualisation.py @@ -1,10 +1,13 @@ import matplotlib +import matplotlib.pyplot as plt import pandas as pd +import numpy as np from alchemtest.gmx import load_benzene -from alchemlyb.parsing.gmx import extract_u_nk -from alchemlyb.estimators import MBAR +from alchemlyb.parsing.gmx import extract_u_nk, extract_dHdl +from alchemlyb.estimators import MBAR, TI from alchemlyb.visualisation.mbar_matrix import plot_mbar_overlap_matrix +from alchemlyb.visualisation.ti_dhdl import plot_ti_dhdl def test_plot_mbar_omatrix(): '''Just test if the plot runs''' @@ -25,3 +28,29 @@ def test_plot_mbar_omatrix(): assert isinstance(plot_mbar_overlap_matrix(overlap_maxtrix), matplotlib.axes.Axes) +def test_plot_ti_dhdl(): + '''Just test if the plot runs''' + bz = load_benzene().data + dHdl_coul = pd.concat([extract_dHdl(xvg, T=300) for xvg in bz['Coulomb']]) + ti_coul = TI() + ti_coul.fit(dHdl_coul) + assert isinstance(plot_ti_dhdl(ti_coul), + matplotlib.axes.Axes) + fig, ax = plt.subplots(figsize=(8, 6)) + assert isinstance(plot_ti_dhdl(ti_coul, ax=ax), + matplotlib.axes.Axes) + assert isinstance(plot_ti_dhdl(ti_coul, labels=['Coul']), + matplotlib.axes.Axes) + assert isinstance(plot_ti_dhdl(ti_coul, labels=['Coul'], colors=['r']), + matplotlib.axes.Axes) + dHdl_vdw = pd.concat([extract_dHdl(xvg, T=300) for xvg in bz['VDW']]) + ti_vdw = TI().fit(dHdl_vdw) + assert isinstance(plot_ti_dhdl([ti_coul, ti_vdw]), + matplotlib.axes.Axes) + ti_coul.dhdl = pd.DataFrame.from_dict( + {'fep': range(100)}, + orient='index', + columns=np.arange(100)/100).T + assert isinstance(plot_ti_dhdl(ti_coul), + matplotlib.axes.Axes) + diff --git a/src/alchemlyb/visualisation/__init__.py b/src/alchemlyb/visualisation/__init__.py index 4fc73051..5cf2c3f9 100644 --- a/src/alchemlyb/visualisation/__init__.py +++ b/src/alchemlyb/visualisation/__init__.py @@ -1 +1,2 @@ -from .mbar_matrix import plot_mbar_overlap_matrix \ No newline at end of file +from .mbar_matrix import plot_mbar_overlap_matrix +from .ti_dhdl import plot_ti_dhdl \ No newline at end of file diff --git a/src/alchemlyb/visualisation/ti_dhdl.py b/src/alchemlyb/visualisation/ti_dhdl.py new file mode 100644 index 00000000..7b53217b --- /dev/null +++ b/src/alchemlyb/visualisation/ti_dhdl.py @@ -0,0 +1,175 @@ +"""Functions for Plotting the dhdl for the TI estimator. + +To assess the quality of the TI estimator, the dhdl from lambda state 0 +to lambda state 1 can plotted to assess if the change in dhdl is sampled +thoroughly. + +The code for producing the dhdl plot is modified based on +: `Alchemical Analysis <https://github.com/MobleyLab/alchemical-analysis>`_. + +""" +from __future__ import division + +import matplotlib.pyplot as plt +from matplotlib.font_manager import FontProperties as FP +import numpy as np + +def plot_ti_dhdl(dhdl_data, labels=None, colors=None, units='kcal/mol', ax=None): + '''Plot the dhdl of TI. + + Parameters + ---------- + dhdl_data : :class:`~alchemlyb.estimators.TI` or list + One or more :class:`~alchemlyb.estimators.TI` estimator, where the + dhdl value will be taken from. + labels : List + list of labels for labelling all the alchemical transformations. + colors : List + list of colors for plotting all the alchemical transformations. + Default: ['r', 'g', '#7F38EC', '#9F000F', 'b', 'y'] + units : str + The unit of the estimate. Default: 'kcal/mol' + ax : matplotlib.axes.Axes + Matplotlib axes object where the plot will be drawn on. If ax=None, + a new axes will be generated. + + Returns + ------- + matplotlib.axes.Axes + An axes with the TI dhdl drawn. + + Notes + ----- + The code is taken and modified from + : `Alchemical Analysis <https://github.com/MobleyLab/alchemical-analysis>`_ + + ''' + # Make it into a list + try: + len(dhdl_data) + except TypeError: + dhdl_data = [dhdl_data, ] + + if ax is None: + fig, ax = plt.subplots(figsize=(8, 6)) + + ax.spines['bottom'].set_position('zero') + ax.spines['top'].set_color('none') + ax.spines['right'].set_color('none') + ax.xaxis.set_ticks_position('bottom') + ax.yaxis.set_ticks_position('left') + + for k, spine in ax.spines.items(): + spine.set_zorder(12.2) + + # Make level names + if labels is None: + lv_names2 = [] + for dhdl in dhdl_data: + # Assume that the dhdl has only one columns + lv_names2.append(dhdl.dhdl.columns.values[0].capitalize()) + else: + if len(labels) == len(dhdl_data): + lv_names2 = labels + else: # pragma: no cover + raise ValueError( + 'Length of labels ({}) should be the same as the number of data ({})'.format( + len(labels), len(dhdl_data))) + + if colors is None: + colors = ['r', 'g', '#7F38EC', '#9F000F', 'b', 'y'] + else: + if len(colors) >= len(dhdl_data): + pass + else: # pragma: no cover + raise ValueError( + 'Number of colors ({}) should be larger than the number of data ({})'.format( + len(labels), len(dhdl_data))) + + # Get the real data out + xs, ndx, dx = [0], 0, 0.001 + min_y, max_y = 0, 0 + for dhdl in dhdl_data: + x = dhdl.dhdl.index.values + y = dhdl.dhdl.values.ravel() + + min_y = min(y.min(), min_y) + max_y = max(y.max(), max_y) + + for i in range(len(x) - 1): + if i % 2 == 0: + ax.fill_between(x[i:i + 2] + ndx, 0, y[i:i + 2], + color=colors[ndx], alpha=1.0) + else: + ax.fill_between(x[i:i + 2] + ndx, 0, y[i:i + 2], + color=colors[ndx], alpha=0.5) + + xlegend = [-100 * wnum for wnum in range(len(lv_names2))] + ax.plot(xlegend, [0 * wnum for wnum in xlegend], ls='-', + color=colors[ndx], + label=lv_names2[ndx]) + xs += (x + ndx).tolist()[1:] + ndx += 1 + + # Make sure the tick labels are not overcrowded. + xs = np.array(xs) + dl_mat = np.array([xs - i for i in xs]) + ri = range(len(xs)) + + def getInd(r=ri, z=[0]): + primo = r[0] + min_dl = ndx * 0.02 * 2 ** (primo > 10) + if dl_mat[primo].max() < min_dl: + return z + for i in r: # pragma: no cover + for j in range(len(xs)): + if dl_mat[i, j] > min_dl: + z.append(j) + return getInd(ri[j:], z) + + xt = [] + for i in range(len(xs)): + if i in getInd(): + xt.append(i) + else: + xt.append('') + + plt.xticks(xs[1:], xt[1:], fontsize=10) + ax.yaxis.label.set_size(10) + + # Remove the abscissa ticks and set up the axes limits. + for tick in ax.get_xticklines(): + tick.set_visible(False) + ax.set_xlim(0, ndx) + min_y *= 1.01 + max_y *= 1.01 + + # Modified so that the x label won't conflict with the lambda label + min_y -= (max_y-min_y)*0.1 + + ax.set_ylim(min_y, max_y) + + for i, j in zip(xs[1:], xt[1:]): + ax.annotate( + ('%.2f' % (i - 1.0 if i > 1.0 else i) if not j == '' else ''), + xy=(i, 0), xytext=(i, 0.01), size=10, rotation=90, + textcoords=('data', 'axes fraction'), va='bottom', ha='center', + color='#151B54') + if ndx > 1: + lenticks = len(ax.get_ymajorticklabels()) - 1 + if min_y < 0: lenticks -= 1 + if lenticks < 5: # pragma: no cover + from matplotlib.ticker import AutoMinorLocator as AML + ax.yaxis.set_minor_locator(AML()) + ax.grid(which='both', color='w', lw=0.25, axis='y', zorder=12) + ax.set_ylabel( + r'$\mathrm{\langle{\frac{ \partial U } { \partial \lambda }}\rangle_{\lambda}\/%s}$' % units, + fontsize=20, color='#151B54') + ax.annotate('$\mathit{\lambda}$', xy=(0, 0), xytext=(0.5, -0.05), size=18, + textcoords='axes fraction', va='top', ha='center', + color='#151B54') + lege = ax.legend(prop=FP(size=14), frameon=False, loc=1) + for l in lege.legendHandles: + l.set_linewidth(10) + return ax +