Plotting

You can download the example data used in this documentation from the anesthetic GitHub page: | https://github.com/handley-lab/anesthetic/tree/master/tests/example_data

You will have the data automatically if you git clone anesthetic:

git clone https://github.com/handley-lab/anesthetic.git

Alternatively you can use your own chains files or generate new random data.

Import anesthetic and load the samples:

from anesthetic import read_chains, make_1d_axes, make_2d_axes
samples = read_chains("../../tests/example_data/pc")

Marginalised posterior plotting

To make marginalised posterior plots we recommend a similar routine to matplotlib, with a first line setting up the figure and axes to draw on:

  • fig, ax = plt.subplots(**kwargs) in matplotlib,

  • fig, axes = make_1d_axes(params, **kwargs) in anesthetic,

and then subsequent lines drawing on the axes:

  • ax.plot(x, y, **kwargs) in matplotlib,

  • samples.plot_1d(axes, **kwargs) in anesthetic.

We have plotting tools for 1D plots …

samples.plot_1d('x0')
_images/plotting-2.png

… multiple 1D plots …

samples.plot_1d(['x0', 'x1', 'x2', 'x3', 'x4'])
_images/plotting-3.png

… triangle plots …

samples.plot_2d(['x0', 'x1', 'x2'], kinds='kde')
_images/plotting-4.png

… triangle plots (with the equivalent scatter plot filling up the left hand side) …

samples.plot_2d(['x0', 'x1', 'x2'])
_images/plotting-5.png

… and rectangle plots.

samples.plot_2d([['x0', 'x1', 'x2'], ['x3', 'x4']])
_images/plotting-6.png

Rectangle plots are pretty flexible with what they can do.

samples.plot_2d([['x0', 'x1', 'x2'], ['x2', 'x1']])
_images/plotting-7.png

Plotting kinds: KDE, histogram, and more

Anesthetic allows for different plotting kinds, which can be specified through the kind (or kinds) keyword. The currently implemented plotting kinds are kernel density estimation (KDE) plots ('kde_1d' and 'kde_2d'), histograms ('hist_1d' and 'hist_2d'), and scatter plots ('scatter_2d').

KDE

The KDE plots make use of scipy.stats.gaussian_kde, whose keyword argument bw_method is forwarded on.

fig, axes = make_1d_axes(['x0', 'x1'], figsize=(5, 3))
samples.plot_1d(axes, kind='kde_1d', label="KDE")
axes.iloc[0].legend(loc='upper right', bbox_to_anchor=(1, 1))
_images/plotting-8.png
fig, axes = make_2d_axes(['x0', 'x1', 'x2'], upper=False)
samples.plot_2d(axes, kinds=dict(diagonal='kde_1d', lower='kde_2d'), label="KDE")
axes.iloc[-1, 0].legend(loc='upper right', bbox_to_anchor=(len(axes), len(axes)))
_images/plotting-9.png

By default, the two-dimensional plots draw the 68 and 95 percent levels as shown above. Different levels can be requested via the levels keyword:

fig, axes = make_2d_axes(['x0', 'x1', 'x2'], upper=False)
samples.plot_2d(axes, kinds='kde', levels=[0.99994, 0.99730, 0.95450, 0.68269])
_images/plotting-10.png

Histograms

The histograms make use of matplotlib.axes.Axes.hist() with all keywords piped through.

fig, axes = make_1d_axes(['x0', 'x1'], figsize=(5, 3))
samples.plot_1d(axes, kind='hist_1d', label="Histogram")
axes.iloc[0].legend(loc='upper right', bbox_to_anchor=(1, 1))
_images/plotting-11.png
fig, axes = make_2d_axes(['x0', 'x1', 'x2'], upper=False)
samples.plot_2d(axes, kinds=dict(diagonal='hist_1d', lower='hist_2d'),
                lower_kwargs=dict(bins=30),
                diagonal_kwargs=dict(bins=20),
                label="Histogram")
axes.iloc[-1, 0].legend(loc='upper right', bbox_to_anchor=(len(axes), len(axes)))
_images/plotting-12.png

Scatter plot

fig, axes = make_2d_axes(['x0', 'x1', 'x2'], diagonal=False, upper=False)
samples.plot_2d(axes, kinds=dict(lower='scatter_2d'), label="Scatter")
axes.iloc[-1, 0].legend(loc='upper right', bbox_to_anchor=(len(axes), len(axes)))
_images/plotting-13.png

More fine grained control

It is possible to have different kinds of plots in the lower/upper triangle or on the diagonal. To achieve this you can pass only a slice of the axes (which is of type anesthetic.plot.AxesDataFrame) to the plot_2d command. It is important, however, that the slice remains two-dimensional, e.g. passing axes.iloc[0, 0] does not work, instead you should pass axes.iloc[0:1, 0:1] (to ensure it is still of type anesthetic.plot.AxesDataFrame).

fig, axes = make_2d_axes(['x0', 'x1', 'x2', 'x3', 'x4'])
samples.plot_2d(axes.iloc[0:2], kinds=dict(diagonal='kde_1d',  lower='kde_2d',     upper='hist_2d'))
samples.plot_2d(axes.iloc[2:4], kinds=dict(diagonal='hist_1d', lower='hist_2d',    upper='hist_2d'), bins=20)
samples.plot_2d(axes.iloc[4: ], kinds=dict(diagonal='kde_1d',  lower='scatter_2d', upper='scatter_2d'))
_images/plotting-14.png

Vertical lines or truth values

The anesthetic.plot.AxesDataFrame class has three convenience methods scatter, axlines, and axspans, which help highlight specific points or areas in parameter space across all subplots.

anesthetic.plot.AxesDataFrame.scatter() is for example particularly useful when pointing out the input “truth” from simulations or the best-fit parameter set of an MCMC run.

anesthetic.plot.AxesDataFrame.axlines() is particularly useful when wanting to separate the parameter space in two. A cosmological example could be the separation into closed and open universes along the line where the spatial curvature is zero.

anesthetic.plot.AxesDataFrame.axlines() is particularly useful when wanting to highlight a range of a parameter across the full parameter space, e.g. the range of sensitivity of an instrument.

fig, axes = make_2d_axes(['x0', 'x1', 'x2'])
samples.plot_2d(axes, label="posterior samples")
axes.scatter({'x0': 0, 'x1': 0, 'x2': 0}, marker='*', c='r', label="some truth")
axes.axlines({'x2': 0.3}, ls=':', c='k', label="some threshold")
axes.axspans({'x0': (-0.1, 0.1)}, c='0.5', alpha=0.3, upper=False, label="some range")
axes.iloc[-1,  0].legend(loc='lower center', bbox_to_anchor=(len(axes)/2, len(axes)))
_images/plotting-15.png

Changing the appearance

Anesthetic tries to follow matplotlib conventions as much as possible, so most changes to the appearance should be relatively straight forward for those familiar with matplotlib. In the following we present some examples, which we think might be useful. Are you wishing for an example that is missing here? Please feel free to raise an issue on the anesthetic GitHub page:

https://github.com/handley-lab/anesthetic/issues.

Colour

There are multiple options when it comes to specifying colours. The simplest is by providing the color (or short c) keyword argument. For some other plotting kinds it might be desirable to distinguish between facecolor and edgecolor (or short fc and ec), e.g. for unfilled contours (see also below “Unfilled contours”). Yet in other cases you might prefer specifying a matplotlib colormap through the cmap keyword.

fig, axes = make_2d_axes(['x0', 'x1', 'x2'])
samples.plot_2d(axes.iloc[0:1, :], kinds=dict(diagonal='kde_1d', lower='kde_2d', upper='kde_2d'), c='r')
samples.plot_2d(axes.iloc[1:2, :], kinds=dict(diagonal='kde_1d', lower='kde_2d', upper='kde_2d'), fc='C0', ec='C1')
samples.plot_2d(axes.iloc[2:3, :], kinds=dict(diagonal='kde_1d', lower='kde_2d', upper='kde_2d'), cmap=plt.cm.viridis_r, levels=[0.99994, 0.997, 0.954, 0.683])
_images/plotting-16.png

Figure size

fig, axes = make_2d_axes(['x0', 'x1', 'x2'], figsize=(4, 4))
samples.plot_2d(axes)
_images/plotting-17.png

Legends

The easiest way of working with legends in anesthetic is probably by picking your favourite subplot and calling the matplotlib.axes.Axes.legend() method from there, directing it to the correct position with the loc and bbox_to_anchor keywords:

fig, axes = make_2d_axes(['x0', 'x1', 'x2'])
samples.plot_2d(axes, label='Posterior')
axes.iloc[ 0,  0].legend(loc='lower left',   bbox_to_anchor=(0, 1))
axes.iloc[ 0, -1].legend(loc='lower right',  bbox_to_anchor=(1, 1))
axes.iloc[-1,  0].legend(loc='lower center', bbox_to_anchor=(len(axes)/2, len(axes)))
_images/plotting-18.png

Log-scale

You can plot selected parameters on a log-scale by passing a list of those parameters under the keyword logx to anesthetic.plot.make_1d_axes() or anesthetic.samples.Samples.plot_1d(), and under the keywords logx and logy to anesthetic.plot.make_2d_axes() or anesthetic.samples.Samples.plot_2d():

fig, axes = make_1d_axes(['x0', 'x1', 'x2', 'x3'], logx=['x2'])
samples.plot_1d(axes, label="'x2' on log-scale")
axes['x2'].legend()
_images/plotting-19.png
fig, axes = make_2d_axes(['x0', 'x1', 'x2', 'x3'], logx=['x2'], logy=['x2'])
samples.plot_2d(axes, label="'x2' on log-scale")
axes.iloc[-1, 0].legend(bbox_to_anchor=(len(axes), len(axes)), loc='lower right')
_images/plotting-20.png
fig, axes = make_2d_axes(['x0', 'x1', 'x2', 'x3'], logx=['x2'])
samples.plot_2d(axes, label="'x2' on log-scale for x-axis, but not for y-axis")
axes.iloc[-1, 0].legend(bbox_to_anchor=(len(axes), len(axes)), loc='lower right')
_images/plotting-21.png

Ticks

You can pass the keyword ticks to anesthetic.plot.make_2d_axes(): to adjust the tick settings of the 2D axes. There are three options:

  • ticks='inner'

  • ticks='outer'

  • ticks=None

fig, axes = make_2d_axes(['x0', 'x1'], figsize=(3, 3), ticks='inner')
samples.plot_2d(axes)
fig.suptitle("ticks='inner'", fontproperties=dict(family='monospace'))

fig, axes = make_2d_axes(['x0', 'x1'], figsize=(3, 3), ticks='outer')
samples.plot_2d(axes)
fig.suptitle("ticks='outer'", fontproperties=dict(family='monospace'))

fig, axes = make_2d_axes(['x0', 'x1'], figsize=(3, 3), ticks=None)
samples.plot_2d(axes)
fig.suptitle("ticks=None", fontproperties=dict(family='monospace'))
_images/plotting-22_00.png
_images/plotting-22_01.png
_images/plotting-22_02.png

Further tick customisation can be done by calling the methods anesthetic.plot.AxesSeries.tick_params() or anesthetic.plot.AxesDataFrame.tick_params() on the axes instance, which will broadcast the corresponding matplotlib.axes.Axes.tick_params() method across all sub-axes.

Unfilled contours

You can get unfilled contours by setting the facecolor (or fc) keyword to one of None or 'None'. By default this will then cause the lines to be plotted in the colours that otherwise the faces would have been coloured in. If you would prefer the same colour for all level lines, you can enforce that by explicitly providing the keyword edgecolor (or ec):

fig, axes = make_2d_axes(['x0', 'x1', 'x2'])
samples.plot_2d(axes, kinds=dict(diagonal='kde_1d', lower='kde_2d'), fc=None, c='C0')
samples.plot_2d(axes, kinds=dict(diagonal='kde_1d', upper='kde_2d'), fc=None, ec='C1')
_images/plotting-23.png