Skip to content
Draft
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
7 changes: 7 additions & 0 deletions lib/matplotlib/_tight_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,15 @@ def get_subplotspec_list(axes_list, grid_spec=None):
subplotspec_list = []
for ax in axes_list:
axes_or_locator = ax.get_axes_locator()

if axes_or_locator is None:
axes_or_locator = ax
else:
for a in ax._twinned_axes.get_siblings(ax):
if a != ax and hasattr(a, "get_subplotspec"):
axes_or_locator = a.get_axes_locator()
if axes_or_locator is None:
axes_or_locator = a

if hasattr(axes_or_locator, "get_subplotspec"):
subplotspec = axes_or_locator.get_subplotspec()
Expand Down
74 changes: 74 additions & 0 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,80 @@ def inset_axes(self, bounds, *, transform=None, zorder=5, **kwargs):

return inset_ax

def _make_twin_axes(self, *args, **kwargs):
"""Make a twinx Axes of self. This is used for twinx and twiny."""
if 'sharex' in kwargs and 'sharey' in kwargs:
raise ValueError("Twinned Axes may share only one axis")
ax2 = self.figure.add_axes(
self.get_position(True), *args, **kwargs,
axes_locator=_TransformedBoundsLocator(
[0, 0, 1, 1], self.transAxes))
axes_locator = _TransformedBoundsLocator([0, 0, 1, 1], self.transAxes)
ax2.set_axes_locator(axes_locator)
self.set_adjustable('datalim')
ax2.set_adjustable('datalim')
self._twinned_axes.join(self, ax2)
return ax2

def twinx(self):
"""
Create a twin Axes sharing the xaxis.

Create a new Axes with an invisible x-axis and an independent
y-axis positioned opposite to the original one (i.e. at right). The
x-axis autoscale setting will be inherited from the original
Axes. To ensure that the tick marks of both y-axes align, see
`~matplotlib.ticker.LinearLocator`.

Returns
-------
Axes
The newly created Axes instance

Notes
-----
For those who are 'picking' artists while using twinx, pick
events are only called for the artists in the top-most Axes.
"""
ax2 = self._make_twin_axes(sharex=self)
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position('right')
ax2.yaxis.set_offset_position('right')
ax2.set_autoscalex_on(self.get_autoscalex_on())
self.yaxis.tick_left()
ax2.xaxis.set_visible(False)
ax2.patch.set_visible(False)
return ax2

def twiny(self):
"""
Create a twin Axes sharing the yaxis.

Create a new Axes with an invisible y-axis and an independent
x-axis positioned opposite to the original one (i.e. at top). The
y-axis autoscale setting will be inherited from the original Axes.
To ensure that the tick marks of both x-axes align, see
`~matplotlib.ticker.LinearLocator`.

Returns
-------
Axes
The newly created Axes instance

Notes
-----
For those who are 'picking' artists while using twiny, pick
events are only called for the artists in the top-most Axes.
"""
ax2 = self._make_twin_axes(sharey=self)
ax2.xaxis.tick_top()
ax2.xaxis.set_label_position('top')
ax2.set_autoscaley_on(self.get_autoscaley_on())
self.xaxis.tick_bottom()
ax2.yaxis.set_visible(False)
ax2.patch.set_visible(False)
return ax2

@_docstring.dedent_interpd
def indicate_inset(self, bounds, inset_ax=None, *, transform=None,
facecolor='none', edgecolor='0.5', alpha=0.5,
Expand Down
73 changes: 0 additions & 73 deletions lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4521,79 +4521,6 @@ def get_tightbbox(self, renderer, call_axes_locator=True,
return mtransforms.Bbox.union(
[b for b in bb if b.width != 0 or b.height != 0])

def _make_twin_axes(self, *args, **kwargs):
"""Make a twinx Axes of self. This is used for twinx and twiny."""
# Typically, SubplotBase._make_twin_axes is called instead of this.
if 'sharex' in kwargs and 'sharey' in kwargs:
raise ValueError("Twinned Axes may share only one axis")
ax2 = self.figure.add_axes(
self.get_position(True), *args, **kwargs,
axes_locator=_TransformedBoundsLocator(
[0, 0, 1, 1], self.transAxes))
self.set_adjustable('datalim')
ax2.set_adjustable('datalim')
self._twinned_axes.join(self, ax2)
return ax2

def twinx(self):
"""
Create a twin Axes sharing the xaxis.

Create a new Axes with an invisible x-axis and an independent
y-axis positioned opposite to the original one (i.e. at right). The
x-axis autoscale setting will be inherited from the original
Axes. To ensure that the tick marks of both y-axes align, see
`~matplotlib.ticker.LinearLocator`.

Returns
-------
Axes
The newly created Axes instance

Notes
-----
For those who are 'picking' artists while using twinx, pick
events are only called for the artists in the top-most Axes.
"""
ax2 = self._make_twin_axes(sharex=self)
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position('right')
ax2.yaxis.set_offset_position('right')
ax2.set_autoscalex_on(self.get_autoscalex_on())
self.yaxis.tick_left()
ax2.xaxis.set_visible(False)
ax2.patch.set_visible(False)
return ax2

def twiny(self):
"""
Create a twin Axes sharing the yaxis.

Create a new Axes with an invisible y-axis and an independent
x-axis positioned opposite to the original one (i.e. at top). The
y-axis autoscale setting will be inherited from the original Axes.
To ensure that the tick marks of both x-axes align, see
`~matplotlib.ticker.LinearLocator`.

Returns
-------
Axes
The newly created Axes instance

Notes
-----
For those who are 'picking' artists while using twiny, pick
events are only called for the artists in the top-most Axes.
"""
ax2 = self._make_twin_axes(sharey=self)
ax2.xaxis.tick_top()
ax2.xaxis.set_label_position('top')
ax2.set_autoscaley_on(self.get_autoscaley_on())
self.xaxis.tick_bottom()
ax2.yaxis.set_visible(False)
ax2.patch.set_visible(False)
return ax2

def get_shared_x_axes(self):
"""Return a reference to the shared axes Grouper object for x axes."""
return self._shared_axes["x"]
Expand Down
13 changes: 0 additions & 13 deletions lib/matplotlib/axes/_subplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,19 +151,6 @@ def _label_outer_yaxis(self, *, check_patch):
if self.yaxis.offsetText.get_position()[0] == 1:
self.yaxis.offsetText.set_visible(False)

def _make_twin_axes(self, *args, **kwargs):
"""Make a twinx axes of self. This is used for twinx and twiny."""
if 'sharex' in kwargs and 'sharey' in kwargs:
# The following line is added in v2.2 to avoid breaking Seaborn,
# which currently uses this internal API.
if kwargs["sharex"] is not self and kwargs["sharey"] is not self:
raise ValueError("Twinned Axes may share only one axis")
twin = self.figure.add_subplot(self.get_subplotspec(), *args, **kwargs)
self.set_adjustable('datalim')
twin.set_adjustable('datalim')
self._twinned_axes.join(self, twin)
return twin


subplot_class_factory = cbook._make_class_factory(
SubplotBase, "{}Subplot", "_axes_class")
Expand Down
12 changes: 12 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5118,6 +5118,18 @@ def test_twin_with_aspect(twin):
ax_twin.bbox.extents)


@pytest.mark.parametrize('twin', ('x', 'y'))
def test_twin_moved(twin):
fig, ax = plt.subplots()
ax.set_position([0.2, 0.2, 0.5, 0.5])
# test twinx or twiny
ax_twin = getattr(ax, 'twin{}'.format(twin))()
fig.draw_without_rendering()

assert_array_equal(ax.bbox.extents,
ax_twin.bbox.extents)


def test_relim_visible_only():
x1 = (0., 10.)
y1 = (0., 10.)
Expand Down