Skip to content

Make inset_axes and secondary_axis picklable. #17993

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 21 additions & 24 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,29 @@
_log = logging.getLogger(__name__)


def _make_inset_locator(bounds, trans, parent):
class _InsetLocator:
"""
Helper function to locate inset axes, used in
`.Axes.inset_axes`.
Axes locator for `.Axes.inset_axes`.

A locator gets used in `Axes.set_aspect` to override the default
locations... It is a function that takes an axes object and
a renderer and tells `set_aspect` where it is to be placed.

Here *rect* is a rectangle [l, b, w, h] that specifies the
location for the axes in the transform given by *trans* on the
*parent*.
The locater is a callable object used in `.Axes.set_aspect` to compute the
axes location depending on the renderer.
"""
_bounds = mtransforms.Bbox.from_bounds(*bounds)
_trans = trans
_parent = parent

def inset_locator(ax, renderer):
bbox = _bounds
bb = mtransforms.TransformedBbox(bbox, _trans)
tr = _parent.figure.transFigure.inverted()
bb = mtransforms.TransformedBbox(bb, tr)
return bb
def __init__(self, bounds, transform):
"""
*bounds* (a ``[l, b, w, h]`` rectangle) and *transform* together
specify the position of the inset axes.
"""
self._bounds = bounds
self._transform = transform

return inset_locator
def __call__(self, ax, renderer):
# Subtracting transFigure will typically rely on inverted(), freezing
# the transform; thus, this needs to be delayed until draw time as
# transFigure may otherwise change after this is evaluated.
return mtransforms.TransformedBbox(
mtransforms.Bbox.from_bounds(*self._bounds),
self._transform - ax.figure.transFigure)


# The axes module contains all the wrappers to plotting functions.
Expand Down Expand Up @@ -468,10 +466,9 @@ def inset_axes(self, bounds, *, transform=None, zorder=5, **kwargs):
kwargs.setdefault('label', 'inset_axes')

# This puts the rectangle into figure-relative coordinates.
inset_locator = _make_inset_locator(bounds, transform, self)
bb = inset_locator(None, None)

inset_ax = Axes(self.figure, bb.bounds, zorder=zorder, **kwargs)
inset_locator = _InsetLocator(bounds, transform)
bounds = inset_locator(self, None).bounds
inset_ax = Axes(self.figure, bounds, zorder=zorder, **kwargs)
# this locator lets the axes move if in data coordinates.
# it gets called in `ax.apply_aspect() (of all places)
inset_ax.set_axes_locator(inset_locator)
Expand Down
32 changes: 4 additions & 28 deletions lib/matplotlib/axes/_secondary_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,10 @@
import matplotlib.docstring as docstring
import matplotlib.ticker as mticker
import matplotlib.transforms as mtransforms
from matplotlib.axes import _axes
from matplotlib.axes._base import _AxesBase


def _make_secondary_locator(rect, parent):
"""
Helper function to locate the secondary axes.

A locator gets used in `Axes.set_aspect` to override the default
locations... It is a function that takes an axes object and
a renderer and tells `set_aspect` where it is to be placed.

This locator make the transform be in axes-relative co-coordinates
because that is how we specify the "location" of the secondary axes.

Here *rect* is a rectangle [l, b, w, h] that specifies the
location for the axes in the transform given by *trans* on the
*parent*.
"""
_rect = mtransforms.Bbox.from_bounds(*rect)
def secondary_locator(ax, renderer):
# delay evaluating transform until draw time because the
# parent transform may have changed (i.e. if window reesized)
bb = mtransforms.TransformedBbox(_rect, parent.transAxes)
tr = parent.figure.transFigure.inverted()
bb = mtransforms.TransformedBbox(bb, tr)
return bb

return secondary_locator


class SecondaryAxis(_AxesBase):
"""
General class to hold a Secondary_X/Yaxis.
Expand Down Expand Up @@ -137,11 +111,13 @@ def set_location(self, location):
self._loc = location

if self._orientation == 'x':
# An x-secondary axes is like an inset axes from x = 0 to x = 1 and
# from y = pos to y = pos + eps, in the parent's transAxes coords.
bounds = [0, self._pos, 1., 1e-10]
else:
bounds = [self._pos, 0, 1e-10, 1]

secondary_locator = _make_secondary_locator(bounds, self._parent)
secondary_locator = _axes._InsetLocator(bounds, self._parent.transAxes)

# this locator lets the axes move in the parent axes coordinates.
# so it never needs to know where the parent is explicitly in
Expand Down
7 changes: 7 additions & 0 deletions lib/matplotlib/tests/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,13 @@ def test_shared():
assert fig.axes[1].get_xlim() == (10, 20)


def test_inset_and_secondary():
fig, ax = plt.subplots()
ax.inset_axes([.1, .1, .3, .3])
ax.secondary_xaxis("top", functions=(np.square, np.sqrt))
pickle.loads(pickle.dumps(fig))


@pytest.mark.parametrize("cmap", cm._cmap_registry.values())
def test_cmap(cmap):
pickle.dumps(cmap)
Expand Down