Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 61807e1

Browse files
authored
Merge pull request #18456 from anntzer/twinpos
Reuse InsetLocator to make twinned axes follow their parents.
2 parents bd39cd7 + a802405 commit 61807e1

File tree

6 files changed

+47
-55
lines changed

6 files changed

+47
-55
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,38 +31,14 @@
3131
import matplotlib.tri as mtri
3232
import matplotlib.units as munits
3333
from matplotlib import _preprocess_data, rcParams
34-
from matplotlib.axes._base import _AxesBase, _process_plot_format
34+
from matplotlib.axes._base import (
35+
_AxesBase, _TransformedBoundsLocator, _process_plot_format)
3536
from matplotlib.axes._secondary_axes import SecondaryAxis
3637
from matplotlib.container import BarContainer, ErrorbarContainer, StemContainer
3738

3839
_log = logging.getLogger(__name__)
3940

4041

41-
class _InsetLocator:
42-
"""
43-
Axes locator for `.Axes.inset_axes`.
44-
45-
The locater is a callable object used in `.Axes.set_aspect` to compute the
46-
axes location depending on the renderer.
47-
"""
48-
49-
def __init__(self, bounds, transform):
50-
"""
51-
*bounds* (a ``[l, b, w, h]`` rectangle) and *transform* together
52-
specify the position of the inset axes.
53-
"""
54-
self._bounds = bounds
55-
self._transform = transform
56-
57-
def __call__(self, ax, renderer):
58-
# Subtracting transFigure will typically rely on inverted(), freezing
59-
# the transform; thus, this needs to be delayed until draw time as
60-
# transFigure may otherwise change after this is evaluated.
61-
return mtransforms.TransformedBbox(
62-
mtransforms.Bbox.from_bounds(*self._bounds),
63-
self._transform - ax.figure.transFigure)
64-
65-
6642
# The axes module contains all the wrappers to plotting functions.
6743
# All the other methods should go in the _AxesBase class.
6844

@@ -365,7 +341,7 @@ def inset_axes(self, bounds, *, transform=None, zorder=5, **kwargs):
365341
kwargs.setdefault('label', 'inset_axes')
366342

367343
# This puts the rectangle into figure-relative coordinates.
368-
inset_locator = _InsetLocator(bounds, transform)
344+
inset_locator = _TransformedBoundsLocator(bounds, transform)
369345
bounds = inset_locator(self, None).bounds
370346
inset_ax = Axes(self.figure, bounds, zorder=zorder, **kwargs)
371347
# this locator lets the axes move if in data coordinates.

lib/matplotlib/axes/_base.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,31 @@ def wrapper(self, *args, **kwargs):
8585
setattr(owner, name, wrapper)
8686

8787

88+
class _TransformedBoundsLocator:
89+
"""
90+
Axes locator for `.Axes.inset_axes` and similarly positioned axes.
91+
92+
The locator is a callable object used in `.Axes.set_aspect` to compute the
93+
axes location depending on the renderer.
94+
"""
95+
96+
def __init__(self, bounds, transform):
97+
"""
98+
*bounds* (a ``[l, b, w, h]`` rectangle) and *transform* together
99+
specify the position of the inset axes.
100+
"""
101+
self._bounds = bounds
102+
self._transform = transform
103+
104+
def __call__(self, ax, renderer):
105+
# Subtracting transFigure will typically rely on inverted(), freezing
106+
# the transform; thus, this needs to be delayed until draw time as
107+
# transFigure may otherwise change after this is evaluated.
108+
return mtransforms.TransformedBbox(
109+
mtransforms.Bbox.from_bounds(*self._bounds),
110+
self._transform - ax.figure.transFigure)
111+
112+
88113
def _process_plot_format(fmt):
89114
"""
90115
Convert a MATLAB style color/line style format string to a (*linestyle*,
@@ -4349,7 +4374,10 @@ def _make_twin_axes(self, *args, **kwargs):
43494374
# Typically, SubplotBase._make_twin_axes is called instead of this.
43504375
if 'sharex' in kwargs and 'sharey' in kwargs:
43514376
raise ValueError("Twinned Axes may share only one axis")
4352-
ax2 = self.figure.add_axes(self.get_position(True), *args, **kwargs)
4377+
ax2 = self.figure.add_axes(
4378+
self.get_position(True), *args, **kwargs,
4379+
axes_locator=_TransformedBoundsLocator(
4380+
[0, 0, 1, 1], self.transAxes))
43534381
self.set_adjustable('datalim')
43544382
ax2.set_adjustable('datalim')
43554383
self._twinned_axes.join(self, ax2)

lib/matplotlib/axes/_secondary_axes.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
import matplotlib.cbook as cbook
44
import matplotlib.docstring as docstring
55
import matplotlib.ticker as mticker
6-
from matplotlib.axes import _axes
7-
from matplotlib.axes._base import _AxesBase
6+
from matplotlib.axes._base import _AxesBase, _TransformedBoundsLocator
87

98

109
class SecondaryAxis(_AxesBase):
@@ -114,13 +113,12 @@ def set_location(self, location):
114113
else:
115114
bounds = [self._pos, 0, 1e-10, 1]
116115

117-
secondary_locator = _axes._InsetLocator(bounds, self._parent.transAxes)
118-
119116
# this locator lets the axes move in the parent axes coordinates.
120117
# so it never needs to know where the parent is explicitly in
121118
# figure coordinates.
122-
# it gets called in `ax.apply_aspect() (of all places)
123-
self.set_axes_locator(secondary_locator)
119+
# it gets called in ax.apply_aspect() (of all places)
120+
self.set_axes_locator(
121+
_TransformedBoundsLocator(bounds, self._parent.transAxes))
124122

125123
def apply_aspect(self, position=None):
126124
# docstring inherited.

lib/matplotlib/figure.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,15 +2424,7 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None,
24242424
"constrained_layout==False. ")
24252425
self.subplotpars.update(left, bottom, right, top, wspace, hspace)
24262426
for ax in self.axes:
2427-
if not isinstance(ax, SubplotBase):
2428-
# Check if sharing a subplots axis
2429-
if isinstance(ax._sharex, SubplotBase):
2430-
ax._sharex.update_params()
2431-
ax.set_position(ax._sharex.figbox)
2432-
elif isinstance(ax._sharey, SubplotBase):
2433-
ax._sharey.update_params()
2434-
ax.set_position(ax._sharey.figbox)
2435-
else:
2427+
if isinstance(ax, SubplotBase):
24362428
ax.update_params()
24372429
ax.set_position(ax.figbox)
24382430
self.stale = True

lib/matplotlib/gridspec.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -486,18 +486,7 @@ def update(self, **kwargs):
486486
raise AttributeError(f"{k} is an unknown keyword")
487487
for figmanager in _pylab_helpers.Gcf.figs.values():
488488
for ax in figmanager.canvas.figure.axes:
489-
# copied from Figure.subplots_adjust
490-
if not isinstance(ax, mpl.axes.SubplotBase):
491-
# Check if sharing a subplots axis
492-
if isinstance(ax._sharex, mpl.axes.SubplotBase):
493-
if ax._sharex.get_subplotspec().get_gridspec() == self:
494-
ax._sharex.update_params()
495-
ax._set_position(ax._sharex.figbox)
496-
elif isinstance(ax._sharey, mpl.axes.SubplotBase):
497-
if ax._sharey.get_subplotspec().get_gridspec() == self:
498-
ax._sharey.update_params()
499-
ax._set_position(ax._sharey.figbox)
500-
else:
489+
if isinstance(ax, mpl.axes.SubplotBase):
501490
ss = ax.get_subplotspec().get_topmost_subplotspec()
502491
if ss.get_gridspec() == self:
503492
ax.update_params()

lib/matplotlib/tests/test_axes.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6581,3 +6581,12 @@ def test_multiplot_autoscale():
65816581
ax2.axhspan(-5, 5)
65826582
xlim = ax1.get_xlim()
65836583
assert np.allclose(xlim, [0.5, 4.5])
6584+
6585+
6586+
def test_sharing_does_not_link_positions():
6587+
fig = plt.figure()
6588+
ax0 = fig.add_subplot(221)
6589+
ax1 = fig.add_axes([.6, .6, .3, .3], sharex=ax0)
6590+
init_pos = ax1.get_position()
6591+
fig.subplots_adjust(left=0)
6592+
assert (ax1.get_position().get_points() == init_pos.get_points()).all()

0 commit comments

Comments
 (0)