Skip to content

Commit 2923bfb

Browse files
authored
Merge pull request matplotlib#31353 from maf2310/fix-twin-position
Fix matplotlib#21409: Make twin axes inherit parent position
2 parents 831477a + c2a343c commit 2923bfb

2 files changed

Lines changed: 50 additions & 0 deletions

File tree

lib/matplotlib/axes/_base.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4725,6 +4725,20 @@ def _make_twin_axes(self, *args, **kwargs):
47254725
twin.set_zorder(self.zorder)
47264726

47274727
self._twinned_axes.join(self, twin)
4728+
4729+
# If the parent Axes has been manually positioned (set_position() sets
4730+
# in_layout=False), the SubplotSpec-based add_subplot(...) path ignores
4731+
# that manual position when creating a twin. In that case, explicitly
4732+
# copy both the original and active positions to the twin so they start
4733+
# aligned.
4734+
#
4735+
# For layout-managed Axes (in_layout=True), we keep the existing
4736+
# SubplotSpec-driven behavior, so layout engines such as tight_layout
4737+
# and constrained_layout continue to control positioning.
4738+
if not self.get_in_layout():
4739+
twin._set_position(self.get_position(original=True), which="original")
4740+
twin._set_position(self.get_position(original=False), which="active")
4741+
47284742
return twin
47294743

47304744
def twinx(self, axes_class=None, **kwargs):

lib/matplotlib/tests/test_axes.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,42 @@ def test_twin_inherit_autoscale_setting():
477477
assert not ax_y_off.get_autoscaley_on()
478478

479479

480+
@pytest.mark.parametrize("twin", ("x", "y"))
481+
def test_twin_respects_position_after_set_position(twin):
482+
fig, ax = plt.subplots()
483+
484+
ax.set_position([0.2, 0.2, 0.5, 0.5])
485+
ax2 = getattr(ax, f"twin{twin}")()
486+
487+
assert_allclose(ax.get_position(original=True).bounds,
488+
ax2.get_position(original=True).bounds)
489+
490+
assert_allclose(ax.get_position(original=False).bounds,
491+
ax2.get_position(original=False).bounds)
492+
493+
494+
@pytest.mark.parametrize("twin", ("x", "y"))
495+
def test_twin_keeps_layout_participation_for_layout_managed_axes(twin):
496+
fig, ax = plt.subplots()
497+
498+
ax2 = getattr(ax, f"twin{twin}")()
499+
500+
assert ax.get_in_layout()
501+
assert ax2.get_in_layout()
502+
503+
504+
@pytest.mark.parametrize("twin", ("x", "y"))
505+
def test_twin_stays_aligned_after_constrained_layout(twin):
506+
fig, ax = plt.subplots(constrained_layout=True)
507+
508+
ax.set_position([0.2, 0.2, 0.5, 0.5])
509+
ax2 = getattr(ax, f"twin{twin}")()
510+
511+
fig.canvas.draw()
512+
513+
assert_allclose(ax.get_position().bounds, ax2.get_position().bounds)
514+
515+
480516
def test_inverted_cla():
481517
# GitHub PR #5450. Setting autoscale should reset
482518
# axes to be non-inverted.

0 commit comments

Comments
 (0)