Skip to content

Commit

Permalink
Merge pull request #205 from ICB-DCM/develop
Browse files Browse the repository at this point in the history
Release 0.9.20
  • Loading branch information
yannikschaelte authored Nov 4, 2019
2 parents 55dff8d + 9cb0342 commit 05e238d
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 42 deletions.
7 changes: 7 additions & 0 deletions doc/releasenotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ Release Notes
..........


0.9.20 (2019-10-30)
-------------------

* Add high-level versions of the kde plotting routines (#204).
* Add unit tests for common epsilon schemes (#207).


0.9.19 (2019-10-23)
-------------------

Expand Down
2 changes: 1 addition & 1 deletion pyabc/epsilon/epsilon.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def _update(self,

# extract weights
if self.weighted:
weights = weighted_distances.w.values
weights = weighted_distances.w.values.astype(float)
# The sum of the weighted distances is larger than 1 if more than
# a single simulation per parameter is performed.
# Re-normalize in this case.
Expand Down
2 changes: 1 addition & 1 deletion pyabc/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.9.19"
__version__ = "0.9.20"
8 changes: 7 additions & 1 deletion pyabc/visualization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

from .kde import (
plot_kde_1d,
plot_kde_1d_highlevel,
plot_kde_2d,
plot_kde_matrix)
plot_kde_2d_highlevel,
plot_kde_matrix,
plot_kde_matrix_highlevel)
from .sample import (
plot_sample_numbers,
plot_total_sample_numbers,
Expand Down Expand Up @@ -37,8 +40,11 @@

__all__ = [
"plot_kde_1d",
"plot_kde_1d_highlevel",
"plot_kde_2d",
"plot_kde_2d_highlevel",
"plot_kde_matrix",
"plot_kde_matrix_highlevel",
"plot_sample_numbers",
"plot_total_sample_numbers",
"plot_sample_numbers_trajectory",
Expand Down
178 changes: 140 additions & 38 deletions pyabc/visualization/kde.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
"""

import numpy as np
from ..transition import MultivariateNormalTransition
import matplotlib.pyplot as plt
import pandas as pd

from ..transition import MultivariateNormalTransition
from ..storage import History


def kde_1d(df, w, x, xmin=None, xmax=None, numx=50, kde=None):
"""
Expand Down Expand Up @@ -51,7 +53,6 @@ class and plotted as follows::
Returns
-------
x, pdf: (np.ndarray, np.ndarray)
The x and the densities at these points.
These can be passed for plotting, for example as
Expand All @@ -72,20 +73,23 @@ class and plotted as follows::
return x_vals, pdf


def plot_kde_1d(df, w, x, xmin=None, xmax=None,
numx=50, ax=None, title: str = None,
refval=None, kde=None, **kwargs):
def plot_kde_1d_highlevel(
history: History, x: str, m: int = 0, t: int = None,
xmin=None, xmax=None, numx=50, ax=None,
size=None, title: str = None, refval=None, kde=None, **kwargs):
"""
Plots a 1d histogram.
Plot 1d kernel density estimate of parameter samples.
Parameters
----------
df: Pandas Dataframe
The rows are the observations, the columns the variables
w: The corresponding weights
history: History
History to extract data from.
x: str
The variable for the x-axis
The variable for the x-axis.
m: int, optional
Id of the model to plot for.
t: int, optional
Time point to plot for. Defaults to last time point.
xmin: float, optional
The lower limit in x for the histogram.
If left empty, it is set to the minimum of the ovbservations of the
Expand All @@ -99,6 +103,8 @@ def plot_kde_1d(df, w, x, xmin=None, xmax=None,
Defaults to 50.
ax: matplotlib.axes.Axes, optional
The axis object to use.
size: 2-Tuple of float, optional
Size of the plot in inches.
title: str, optional
Title for the plot. Defaults to None.
refval: dict, optional
Expand All @@ -112,10 +118,33 @@ def plot_kde_1d(df, w, x, xmin=None, xmax=None,
Returns
-------
ax: matplotlib axis
axis of the plot
"""
df, w = history.get_distribution(m=m, t=t)

return plot_kde_1d(df, w, x, xmin, xmax, numx, ax, size, title, refval,
kde, **kwargs)


def plot_kde_1d(df, w, x, xmin=None, xmax=None,
numx=50, ax=None, size=None, title: str = None,
refval=None, kde=None, **kwargs):
"""
Lowlevel interface for plot_kde_1d_highlevel (see there for the remaining
parameters).
Parameters
----------
df: pandas.DataFrame
The rows are the observations, the columns the variables.
w: pandas.DataFrame
The corresponding weights.
Returns
-------
ax: matplotlib axis
Axis of the plot.
"""
x_vals, pdf = kde_1d(df, w, x, xmin=xmin, xmax=xmax, numx=numx, kde=kde)
if ax is None:
Expand All @@ -128,6 +157,11 @@ def plot_kde_1d(df, w, x, xmin=None, xmax=None,
ax.set_title(title)
if refval is not None:
ax.axvline(refval[x], color='C1', linestyle='dashed')

# set size
if size is not None:
ax.get_figure().set_size_inches(size)

return ax


Expand Down Expand Up @@ -182,7 +216,6 @@ class and plotted as follows::
Returns
-------
X, Y, PDF: (np.ndarray, np.ndarray, np.ndarray)
The X, the Y and the densities at these points.
These can be passed for plotting, for example as
Expand All @@ -209,21 +242,27 @@ class and plotted as follows::
return X, Y, PDF


def plot_kde_2d(df, w, x, y, xmin=None, xmax=None, ymin=None, ymax=None,
numx=50, numy=50, ax=None, colorbar=True,
title: str = None, refval=None, kde=None, **kwargs):
def plot_kde_2d_highlevel(
history: History, x: str, y: str, m: int = 0, t: int = None,
xmin: float = None, xmax: float = None, ymin: float = None,
ymax: float = None, numx: int = 50, numy: int = 50, ax=None,
size=None, colorbar=True, title: str = None, refval=None, kde=None,
**kwargs):
"""
Plots a 2d histogram.
Plot 2d kernel density estimate of parameter samples.
Parameters
----------
df: Pandas Dataframe
The rows are the observations, the columns the variables
w: The corresponding weights.
history: History
History to extract data from.
x: str
The variable for the x-axis.
y: str
The variable for the y-axis.
m: int, optional
Id of the model to plot for.
t: int, optional
Time point to plot for. Defaults to last time point.
xmin: float, optional
The lower limit in x for the histogram.
If left empty, it is set to the minimum of the ovbservations of the
Expand All @@ -248,6 +287,8 @@ def plot_kde_2d(df, w, x, y, xmin=None, xmax=None, ymin=None, ymax=None,
Defaults tp 50.
ax: matplotlib.axes.Axes, optional
The axis object to use.
size: 2-Tuple of float
Size of the plot in inches.
colorbar: bool, optional
Whether to plot a colorbar. Defaults to True.
title: str, optional
Expand All @@ -257,13 +298,38 @@ def plot_kde_2d(df, w, x, y, xmin=None, xmax=None, ymin=None, ymax=None,
kde: pyabc.Transition, optional
The kernel density estimator to use for creating a smooth density
from the sample. If None, a multivariate normal kde with
cross-validated scaling is used.
cross-validated scaling is used..
Returns
-------
ax: matplotlib axis
Axis of the plot.
"""
df, w = history.get_distribution(m=m, t=t)

return plot_kde_2d(
df, w, x, y, xmin, xmax, ymin, ymax, numx, numy, ax, size, colorbar,
title, refval, kde, **kwargs)


def plot_kde_2d(df, w, x, y, xmin=None, xmax=None, ymin=None, ymax=None,
numx=50, numy=50, ax=None, size=None, colorbar=True,
title: str = None, refval=None, kde=None, **kwargs):
"""
Plot a 2d kernel density estimate of parameter samples.
Parameters
----------
df: Pandas Dataframe
The rows are the observations, the columns the variables
w: The corresponding weights.
For the other parameters, see `plot_kde_2d_highlevel`.
Returns
-------
ax: matplotlib axis
axis of the plot
Axis of the plot.
"""
X, Y, PDF = kde_2d(df, w, x, y,
Expand All @@ -282,31 +348,33 @@ def plot_kde_2d(df, w, x, y, xmin=None, xmax=None, ymin=None, ymax=None,
# cbar.set_label("PDF")
if refval is not None:
ax.scatter([refval[x]], [refval[y]], color='C1')

# set size
if size is not None:
ax.get_figure().set_size_inches(size)

return ax


def plot_kde_matrix(df, w,
limits=None,
colorbar=True,
height=2.5,
numx=50,
numy=50,
refval=None,
kde=None):
def plot_kde_matrix_highlevel(
history, m: int = 0, t: int = None, limits=None,
colorbar: bool = True, height: float = 2.5,
numx: int = 50, numy: int = 50, refval=None, kde=None):
"""
Plot a KDE matrix.
Plot a KDE matrix for 1- and 2-dim marginals of the parameter samples.
Parameters
----------
df: Pandas Dataframe
The rows are the observations, the columns the variables.
w: np.narray
The corresponding weights.
colorbar: bool
Whether to plot the colorbars or not.
history: History
History to extract data from.
m: int, optional
Id of the model to plot for.
t: int, optional
Time point to plot for. Defaults to last time point.
limits: dictionary, optional
Dictionary of the form ``{"name": (lower_limit, upper_limit)}``.
colorbar: bool
Whether to plot the colorbars or not.
height: float, optional
Height of each subplot in inches. Default: 2.5.
numx: int, optional
Expand All @@ -323,6 +391,40 @@ def plot_kde_matrix(df, w,
The kernel density estimator to use for creating a smooth density
from the sample. If None, a multivariate normal kde with
cross-validated scaling is used.
Returns
-------
arr_ax: Array of the generated plots' axes.
"""
df, w = history.get_distribution(m=m, t=t)

return plot_kde_matrix(
df, w, limits, colorbar, height, numx, numy, refval, kde)


def plot_kde_matrix(df, w,
limits=None,
colorbar=True,
height=2.5,
numx=50,
numy=50,
refval=None,
kde=None):
"""
Plot a KDE matrix for 1- and 2-dim marginals of the parameter samples.
Parameters
----------
df: Pandas Dataframe
The rows are the observations, the columns the variables.
w: np.narray
The corresponding weights.
Other parameters: See plot_kde_matrix_highlevel.
Returns
-------
arr_ax: Array of the generated plots' axes.
"""

n_par = df.shape[1]
Expand Down
50 changes: 50 additions & 0 deletions test/test_epsilon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import pyabc
import numpy as np
import pandas as pd
import pytest


def test_noepsilon():
eps = pyabc.NoEpsilon()
assert not np.isfinite(eps(42))


def test_constantepsilon():
eps = pyabc.ConstantEpsilon(42)
assert np.isclose(eps(100), 42)


def test_listepsilon():
eps = pyabc.ListEpsilon([3.5, 2.3, 1, 0.3])
with pytest.raises(Exception):
eps(4)


def test_quantileepsilon():
mpl = 1.1
df = pd.DataFrame({
'distance': [1, 2, 3, 4],
'w': [2, 1, 1, 1]
})

eps = pyabc.QuantileEpsilon(
initial_epsilon=5.1, alpha=0.5,
quantile_multiplier=mpl, weighted=False)

# check if initial value is respected
eps.initialize(0, lambda: df)
assert np.isclose(eps(0), 5.1)

# check if quantile is computed correctly
eps.update(1, df)
assert np.isclose(eps(1), mpl * 2.5)

# use other quantile
eps = pyabc.QuantileEpsilon(alpha=0.9, weighted=True)
eps.initialize(0, lambda: df)
assert eps(0) >= 3 and eps(0) <= 4


def test_medianepsilon():
eps = pyabc.MedianEpsilon()
assert np.isclose(eps.alpha, 0.5)
Loading

0 comments on commit 05e238d

Please sign in to comment.