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

Skip to content

Commit 3490c90

Browse files
committed
Reuse InsetLocator to make twinned axes follow their parents.
From a positioning PoV, a twinned axes is just like an inset axes whose position exactly matches the parent's position. Doing so removes the need for the heuristic in `Figure.subplots_adjust`/`GridSpec.update` where a non-gridspec-managed Axes would track the position of any Axes with which it shared either xaxis or yaxis, which was a proxy for twinning (per 721b949). This would cause incorrect behavior in rare cases such as ```python from pylab import * ax = subplot(221) axes([.6, .6, .3, .3], sharex=ax) subplots_adjust(left=0) ``` where the `subplots_adjust` call would make the second axes go on top of the first.
1 parent bd765e0 commit 3490c90

File tree

5 files changed

+34
-50
lines changed

5 files changed

+34
-50
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 2 additions & 26 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, _InsetLocator, _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

lib/matplotlib/axes/_base.py

Lines changed: 28 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 _InsetLocator:
89+
"""
90+
Axes locator for `.Axes.inset_axes` and similarly positioned axes.
91+
92+
The locater 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*,
@@ -4336,7 +4361,9 @@ def _make_twin_axes(self, *args, **kwargs):
43364361
# Typically, SubplotBase._make_twin_axes is called instead of this.
43374362
if 'sharex' in kwargs and 'sharey' in kwargs:
43384363
raise ValueError("Twinned Axes may share only one axis")
4339-
ax2 = self.figure.add_axes(self.get_position(True), *args, **kwargs)
4364+
ax2 = self.figure.add_axes(
4365+
self.get_position(True), *args, **kwargs,
4366+
axes_locator=_InsetLocator([0, 0, 1, 1], self.transAxes))
43404367
self.set_adjustable('datalim')
43414368
ax2.set_adjustable('datalim')
43424369
self._twinned_axes.join(self, ax2)

lib/matplotlib/axes/_secondary_axes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import matplotlib.docstring as docstring
55
import matplotlib.ticker as mticker
66
from matplotlib.axes import _axes
7-
from matplotlib.axes._base import _AxesBase
7+
from matplotlib.axes._base import _AxesBase, _InsetLocator
88

99

1010
class SecondaryAxis(_AxesBase):
@@ -114,7 +114,7 @@ def set_location(self, location):
114114
else:
115115
bounds = [self._pos, 0, 1e-10, 1]
116116

117-
secondary_locator = _axes._InsetLocator(bounds, self._parent.transAxes)
117+
secondary_locator = _InsetLocator(bounds, self._parent.transAxes)
118118

119119
# this locator lets the axes move in the parent axes coordinates.
120120
# so it never needs to know where the parent is explicitly in

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

0 commit comments

Comments
 (0)