Skip to content

Latest commit

 

History

History
325 lines (221 loc) · 11.6 KB

plotting.rst

File metadata and controls

325 lines (221 loc) · 11.6 KB

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 <reading chains> or generate new random data <passing data>.

Import anesthetic and load the samples:

context

close-figs

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 ...

context

close-figs

samples.plot_1d('x0')

... multiple 1D plots ...

context

close-figs

samples.plot_1d(['x0', 'x1', 'x2', 'x3', 'x4'])

... triangle plots ...

context

close-figs

samples.plot_2d(['x0', 'x1', 'x2'], kinds='kde')

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

context

close-figs

samples.plot_2d(['x0', 'x1', 'x2'])

... and rectangle plots.

context

close-figs

samples.plot_2d([['x0', 'x1', 'x2'], ['x3', 'x4']])

Rectangle plots are pretty flexible with what they can do.

context

close-figs

samples.plot_2d([['x0', 'x1', 'x2'], ['x2', 'x1']])

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 :pyscipy.stats.gaussian_kde, whose keyword argument bw_method is forwarded on.

context

close-figs

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))

context

close-figs

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)))

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:

context

close-figs

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])

Histograms

The histograms make use of :pymatplotlib.axes.Axes.hist with all keywords piped through.

context

close-figs

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))

context

close-figs

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)))

Scatter plot

context

close-figs

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)))

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).

context

close-figs

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'))

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.

context

close-figs

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)))

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.

context

close-figs

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])

Figure size

context

close-figs

fig, axes = make_2d_axes(['x0', 'x1', 'x2'], figsize=(4, 4)) samples.plot_2d(axes)

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:

context

close-figs

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)))

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:

context

close-figs

fig, axes = make_1d_axes(['x0', 'x1', 'x2', 'x3'], logx=['x2']) samples.plot_1d(axes, label="'x2' on log-scale") axes['x2'].legend()

context

close-figs

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')

context

close-figs

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')

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
context

close-figs

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'))

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):

context

close-figs

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')