InsetPlot Context Manager
=========================

.. currentmodule:: stonerplots.context.inset_plot

Inset plots, where a second set of axes are included within the main axes of a figure, are often used to show either a
detail of the main figure, or possibly an overview or a related dataset. Unfortunately, generating insets with
matplotlib can be somewhat tricky, as the standard tools to set up and position the inset plot often require additional
work to avoid the inset axes clashing with the main axes.

StonerPlot's `InsetPlot` context manager is designed to make this easier by tweaking the placement of the inset. It is
a wrapper around :py:func:`axes.Axes.inset_axes` with additional logic to adjust the position of the inset::

    with InsetPlot() as inset:
        inset.plot(x, y)

This will create an inset that is then automatically placed in the best location within the current axes and occupies
33% of the axes horizontally and vertically. By default, the context manager also manipulates `matplotlib.pyplot`'s
current axes, so that inside the context manager, the current axes are the inset plot and afterwards, they are restored
to the original active axes.

Controlling the Inset Location
------------------------------

The context manager takes a *loc* parameter that defines the location of the inset. These take the same value as for
`matplotlib.pyplot.legend` (for convenience, any hyphens in the location string are replaced with spaces, and
everything is lower-cased)::

    with InsetPlot(loc="lower right") as inset:
        inset.plot(x, y)

Adjusting the Inset Size
------------------------

The *width*, *height* and *dimension* parameters control the size of the inset axes (note this does not include any
axes labels, tick markers, etc.). *width* and *height* are floating-point numbers. If *dimension* is "fraction"
(the default), then these floating-point numbers represent the fraction of the parent axes' size occupied by the inset
axes. Thus, the default values are 0.33, or 33%. If *dimension* is not "fraction," then the units for *width* and
*height* are::

    with InsetPlot(width=1.1, height=0.7, dimension="inches") as inset:
        inset.plot(x, y)

Control of Axes and Parameters
------------------------------

By default, the parent axes are considered the current axes from the current figure, but the *ax* parameter can be used
to specify different axes::

    with InsetPlot(ax=plt.figure(2).gca()) as inset:
        inset.plot(x, y)

As noted above, by default the context manager switches the current axes around so that Pyplot functions will work on
the inset inside the context manager::

    plt.plot(x_main, y_main)
    with InsetPlot():  # Ignore the context manager's return value
        plt.plot(x_inset, y_inset)  # On the inset axes
    plt.xlabel("Main X")  # Back on the main axes again
    plt.ylabel("Main Y")

Multiple Insets
---------------

The automatic placement of insets considers both the main axes' legend and other insets, and it will attempt to locate
the second inset in the best remaining location::

    plt.plot(x_main, y_main)
    with InsetPlot() as inset_1:
        inset_1.plot(x_inset_1, y_inset_1)
    with InsetPlot() as inset_2:
        inset_2.plot(x_inset_2, y_inset_2)
