diff --git a/doc/api/next_api_changes/behavior/20012-AL.rst b/doc/api/next_api_changes/behavior/20012-AL.rst new file mode 100644 index 000000000000..78615239e17c --- /dev/null +++ b/doc/api/next_api_changes/behavior/20012-AL.rst @@ -0,0 +1,5 @@ +Default theta tick locations for non-full-circle polar plots have changed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For polar plots that don't cover a full circle, the default theta tick +locations are now at multiples of 10°, 15°, 30°, 45°, 90°, rather than using +values that mostly make sense for linear plots (20°, 25°, etc.). diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index 6e2dd8af90f3..4ee8c6bcc020 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -393,6 +393,10 @@ def _set_scale(self, value, **kwargs): raise NotImplementedError( "The xscale cannot be set on a polar plot") super()._set_scale(value, **kwargs) + # LinearScale.set_default_locators_and_formatters just set the major + # locator to be an AutoLocator, so we customize it here to have ticks + # at sensible degree multiples. + self.get_major_locator().set_params(steps=[1, 1.5, 3, 4.5, 9, 10]) self._wrap_locator_formatter() def _copy_tick_props(self, src, dest): diff --git a/lib/matplotlib/tests/test_polar.py b/lib/matplotlib/tests/test_polar.py index c614eff027b5..e3cec7b410e6 100644 --- a/lib/matplotlib/tests/test_polar.py +++ b/lib/matplotlib/tests/test_polar.py @@ -249,6 +249,8 @@ def test_polar_theta_limits(): direction=DIRECTIONS[i % len(DIRECTIONS)], rotation='auto') ax.yaxis.set_tick_params(label2On=True, rotation='auto') + ax.xaxis.get_major_locator().base.set_params( # backcompat + steps=[1, 2, 2.5, 5, 10]) @check_figures_equal(extensions=["png"]) @@ -357,3 +359,17 @@ def test_thetalim_args(): assert tuple(np.radians((ax.get_thetamin(), ax.get_thetamax()))) == (0, 1) ax.set_thetalim((2, 3)) assert tuple(np.radians((ax.get_thetamin(), ax.get_thetamax()))) == (2, 3) + + +def test_default_thetalocator(): + # Ideally we would check AAAABBC, but the smallest axes currently puts a + # single tick at 150° because MaxNLocator doesn't have a way to accept 15° + # while rejecting 150°. + fig, axs = plt.subplot_mosaic( + "AAAABB.", subplot_kw={"projection": "polar"}) + for ax in axs.values(): + ax.set_thetalim(0, np.pi) + for ax in axs.values(): + ticklocs = np.degrees(ax.xaxis.get_majorticklocs()).tolist() + assert pytest.approx(90) in ticklocs + assert pytest.approx(100) not in ticklocs