From 86a96994207be627b750998be230487bdd4eb95b Mon Sep 17 00:00:00 2001 From: Samiat Date: Mon, 15 Jun 2026 13:07:07 +0100 Subject: [PATCH 1/2] Sync shared limits without callbacks --- lib/matplotlib/axis.py | 9 +++++++-- lib/matplotlib/tests/test_axes.py | 12 +++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 349e728ba8ff..aafb520a33ee 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1319,7 +1319,7 @@ def set_default_intervals(self): # attribute, and the derived code below will check for that # and use it if it's available (else just use 0..1) - def _set_lim(self, v0, v1, *, emit=True, auto): + def _set_lim(self, v0, v1, *, emit=True, auto, propagate=True): """ Set view limits. @@ -1336,6 +1336,8 @@ def _set_lim(self, v0, v1, *, emit=True, auto): auto : bool or None, default: False Whether to turn on autoscaling of the x-axis. True turns on, False turns off, None leaves unchanged. + propagate : bool, default: True + Whether to propagate the limits to shared axes. """ name = self._get_axis_name() @@ -1381,11 +1383,14 @@ def _set_lim(self, v0, v1, *, emit=True, auto): if emit: self.axes.callbacks.process(f"{name}lim_changed", self.axes) + + if propagate: # Call all of the other Axes that are shared with this one for other in self._get_shared_axes(): if other is self.axes: continue - other._axis_map[name]._set_lim(v0, v1, emit=False, auto=auto) + other._axis_map[name]._set_lim( + v0, v1, emit=False, auto=auto, propagate=False) if emit: other.callbacks.process(f"{name}lim_changed", other) if ((other_fig := other.get_figure(root=False)) != diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 2e3abec8363e..923847c3e8c8 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -10005,13 +10005,23 @@ def test_set_secondary_axis_color(): def test_xylim_changed_shared(): - fig, axs = plt.subplots(2, sharex=True, sharey=True) + fig, axs = plt.subplots(3, sharex=True, sharey=True) events = [] axs[1].callbacks.connect("xlim_changed", events.append) axs[1].callbacks.connect("ylim_changed", events.append) axs[0].set(xlim=[1, 3], ylim=[2, 4]) assert events == [axs[1], axs[1]] + axs[0].callbacks.connect("xlim_changed", events.append) + axs[0].callbacks.connect("ylim_changed", events.append) + events.clear() + axs[0].set_xlim(4, 5, emit=False) + axs[0].set_ylim(6, 7, emit=False) + for ax in axs[1:]: + assert ax.get_xlim() == (4, 5) + assert ax.get_ylim() == (6, 7) + assert events == [] + @image_comparison(["axhvlinespan_interpolation.png"], style="default") def test_axhvlinespan_interpolation(): From 5fa833f10f1564312b92c5c998cde75d9b26b70d Mon Sep 17 00:00:00 2001 From: Samiat Date: Mon, 15 Jun 2026 15:24:13 +0100 Subject: [PATCH 2/2] Preserve autoscale when sharing axes --- lib/matplotlib/axes/_base.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index c3371a55f77d..80dfa4978c05 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -1304,7 +1304,9 @@ def sharex(self, other): self.xaxis.major = other.xaxis.major # Ticker instances holding self.xaxis.minor = other.xaxis.minor # locator and formatter. x0, x1 = other.get_xlim() - self.set_xlim(x0, x1, emit=False, auto=other.get_autoscalex_on()) + self.xaxis._set_lim( + x0, x1, emit=False, auto=other.get_autoscalex_on(), + propagate=False) self.xaxis._scale = other.xaxis._scale def sharey(self, other): @@ -1323,7 +1325,9 @@ def sharey(self, other): self.yaxis.major = other.yaxis.major # Ticker instances holding self.yaxis.minor = other.yaxis.minor # locator and formatter. y0, y1 = other.get_ylim() - self.set_ylim(y0, y1, emit=False, auto=other.get_autoscaley_on()) + self.yaxis._set_lim( + y0, y1, emit=False, auto=other.get_autoscaley_on(), + propagate=False) self.yaxis._scale = other.yaxis._scale def __clear(self):