From 2e533411c24b7bee66c1f83ff37667fd708982a7 Mon Sep 17 00:00:00 2001 From: Saumya Date: Tue, 9 Dec 2025 01:12:30 +0530 Subject: [PATCH 1/3] FIX: Prevent warning when clearing axes with shared non-linear scale When clearing an axes (via cla() or clf()) that has a shared axis with a non-linear scale (e.g., log, logit), a warning was incorrectly generated: 'Attempt to set non-positive xlim on a log-scaled axis will be ignored.' This occurred because when an axes with linear scale sets default limits (0, 1), these limits propagate to shared axes that may have non-linear scales which reject these limits. Fixed by skipping propagation of default (0, 1) limits from linear scale axes to non-linear scale shared axes. This preserves the behavior for other cases (like inverted axes) while eliminating the spurious warning. Additionally, reordered scale assignment before limit setting in sharex()/sharey() methods to ensure scale is set before limits are applied. Fixes #9970 --- lib/matplotlib/axes/_base.py | 9 +++++++-- lib/matplotlib/axis.py | 9 ++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index f047fe1809aa..97c432f13fa8 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -1274,9 +1274,10 @@ def sharex(self, other): self._sharex = other self.xaxis.major = other.xaxis.major # Ticker instances holding self.xaxis.minor = other.xaxis.minor # locator and formatter. + # Set scale before limits to avoid warnings with non-linear scales + self.xaxis._scale = other.xaxis._scale x0, x1 = other.get_xlim() self.set_xlim(x0, x1, emit=False, auto=other.get_autoscalex_on()) - self.xaxis._scale = other.xaxis._scale def sharey(self, other): """ @@ -1293,9 +1294,10 @@ def sharey(self, other): self._sharey = other self.yaxis.major = other.yaxis.major # Ticker instances holding self.yaxis.minor = other.yaxis.minor # locator and formatter. + # Set scale before limits to avoid warnings with non-linear scales + self.yaxis._scale = other.yaxis._scale y0, y1 = other.get_ylim() self.set_ylim(y0, y1, emit=False, auto=other.get_autoscaley_on()) - self.yaxis._scale = other.yaxis._scale def __clear(self): """Clear the Axes.""" @@ -1419,6 +1421,9 @@ def __clear(self): share = getattr(self, f"_share{name}") if share is not None: getattr(self, f"share{name}")(share) + # Don't set default limits for shared axes - they will be + # synchronized from the shared axis and may have non-linear + # scales that would reject the (0, 1) default limits. else: # Although the scale was set to linear as part of clear, # polar requires that _set_scale is called again diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index c3b6fcac569f..bf0bbcdf3b21 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1263,7 +1263,14 @@ def _set_lim(self, v0, v1, *, emit=True, auto): 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) + # Skip propagating default (0, 1) limits from linear scale to + # non-linear scales during clear operations to avoid warnings + other_axis = other._axis_map[name] + if (self.get_scale() == 'linear' and + other_axis.get_scale() != 'linear' and + v0 == 0 and v1 == 1): + continue + other_axis._set_lim(v0, v1, emit=False, auto=auto) if emit: other.callbacks.process(f"{name}lim_changed", other) if ((other_fig := other.get_figure(root=False)) != From b17daeb9e93a17061c0b02cf68a5a61750eb8422 Mon Sep 17 00:00:00 2001 From: Saumya Date: Tue, 23 Dec 2025 19:13:01 +0530 Subject: [PATCH 2/3] Add test for clearing shared non-linear axes without warning Verify that clearing an axes with shared non-linear scales (log, logit, symlog) does not generate spurious warnings. Tests both sharex and sharey configurations. Regression test for #9970. --- lib/matplotlib/tests/test_axes.py | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index fe121e12c9f1..21f6e26a83e4 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -11,6 +11,7 @@ import re import sys from types import SimpleNamespace +import warnings import dateutil.tz @@ -528,6 +529,56 @@ def test_inverted_cla(): plt.close(fig) +def test_shared_axes_clear_with_nonlinear_scale(): + """ + Test that clearing axes with shared non-linear scales doesn't warn. + + Regression test for issue #9970. + When clearing an axes that shares with another axes having a non-linear + scale (log, logit, symlog, etc.), no warning should be generated about + setting non-positive limits. + """ + # Test log scale on x-axis + fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True) + ax1.set_xscale('log') + x = np.logspace(0, 3, 100) + ax1.plot(x, x**2) + + # Clearing should not generate warning about non-positive xlim + with warnings.catch_warnings(): + warnings.simplefilter("error", UserWarning) + ax1.cla() + fig.clf() + + # Test log scale on y-axis + fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True) + ax1.set_yscale('log') + y = np.logspace(0, 3, 100) + ax1.plot(y, y**2) + + with warnings.catch_warnings(): + warnings.simplefilter("error", UserWarning) + ax1.cla() + fig.clf() + + # Test other non-linear scales + for scale in ['logit', 'symlog']: + fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True) + ax1.set_xscale(scale) + if scale == 'logit': + x = np.linspace(0.01, 0.99, 100) + else: # symlog + x = np.linspace(-100, 100, 100) + ax1.plot(x, x**2) + + with warnings.catch_warnings(): + warnings.simplefilter("error", UserWarning) + ax1.cla() + fig.clf() + + plt.close('all') + + def test_subclass_clear_cla(): # Ensure that subclasses of Axes call cla/clear correctly. # Note, we cannot use mocking here as we want to be sure that the From 476b3efa4541258a418f6f611645bbb64b1011db Mon Sep 17 00:00:00 2001 From: Saumya Agrawal <145997182+saumyacoder1709@users.noreply.github.com> Date: Tue, 23 Dec 2025 19:53:20 +0530 Subject: [PATCH 3/3] Clean up blank lines in test_shared_axes_clear_with_nonlinear_scale Removed unnecessary blank lines in the test for shared axes with non-linear scale. --- lib/matplotlib/tests/test_axes.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 330e937994ce..9629360b4d73 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -532,7 +532,7 @@ def test_inverted_cla(): def test_shared_axes_clear_with_nonlinear_scale(): """ Test that clearing axes with shared non-linear scales doesn't warn. - + Regression test for issue #9970. When clearing an axes that shares with another axes having a non-linear scale (log, logit, symlog, etc.), no warning should be generated about @@ -543,24 +543,20 @@ def test_shared_axes_clear_with_nonlinear_scale(): ax1.set_xscale('log') x = np.logspace(0, 3, 100) ax1.plot(x, x**2) - # Clearing should not generate warning about non-positive xlim with warnings.catch_warnings(): warnings.simplefilter("error", UserWarning) ax1.cla() fig.clf() - # Test log scale on y-axis fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True) ax1.set_yscale('log') y = np.logspace(0, 3, 100) ax1.plot(y, y**2) - with warnings.catch_warnings(): warnings.simplefilter("error", UserWarning) ax1.cla() fig.clf() - # Test other non-linear scales for scale in ['logit', 'symlog']: fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True) @@ -570,12 +566,10 @@ def test_shared_axes_clear_with_nonlinear_scale(): else: # symlog x = np.linspace(-100, 100, 100) ax1.plot(x, x**2) - with warnings.catch_warnings(): warnings.simplefilter("error", UserWarning) ax1.cla() fig.clf() - plt.close('all')