diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index aeee67e3816d..b35752c08187 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -6,6 +6,7 @@ import functools import logging from numbers import Real +import warnings import numpy as np @@ -1965,7 +1966,10 @@ def set_ticklabels(self, labels, *, minor=False, fontdict=None, **kwargs): raise TypeError(f"{labels:=} must be a sequence") from None locator = (self.get_minor_locator() if minor else self.get_major_locator()) - if isinstance(locator, mticker.FixedLocator): + if not labels: + # eg labels=[]: + formatter = mticker.NullFormatter() + elif isinstance(locator, mticker.FixedLocator): # Passing [] as a list of labels is often used as a way to # remove all tick labels, so only error for > 0 labels if len(locator.locs) != len(labels) and len(labels) != 0: @@ -1978,16 +1982,23 @@ def set_ticklabels(self, labels, *, minor=False, fontdict=None, **kwargs): func = functools.partial(self._format_with_dict, tickd) formatter = mticker.FuncFormatter(func) else: + _api.warn_external( + "set_ticklabels() should only be used with a fixed number of " + "ticks, i.e. after set_ticks() or using a FixedLocator.") formatter = mticker.FixedFormatter(labels) - if minor: - self.set_minor_formatter(formatter) - locs = self.get_minorticklocs() - ticks = self.get_minor_ticks(len(locs)) - else: - self.set_major_formatter(formatter) - locs = self.get_majorticklocs() - ticks = self.get_major_ticks(len(locs)) + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + message="FixedFormatter should only be used together with FixedLocator") + if minor: + self.set_minor_formatter(formatter) + locs = self.get_minorticklocs() + ticks = self.get_minor_ticks(len(locs)) + else: + self.set_major_formatter(formatter) + locs = self.get_majorticklocs() + ticks = self.get_major_ticks(len(locs)) ret = [] if fontdict is not None: diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 7e7b8a26d7de..3fe5e839bffb 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -6063,6 +6063,21 @@ def test_retain_tick_visibility(): ax.tick_params(axis="y", which="both", length=0) +def test_warn_too_few_labels(): + # note that the axis is still using an AutoLocator: + fig, ax = plt.subplots() + with pytest.warns( + UserWarning, + match=r'set_ticklabels\(\) should only be used with a fixed number'): + ax.set_xticklabels(['0', '0.1']) + # note that the axis is still using a FixedLocator: + fig, ax = plt.subplots() + ax.set_xticks([0, 0.5, 1]) + with pytest.raises(ValueError, + match='The number of FixedLocator locations'): + ax.set_xticklabels(['0', '0.1']) + + def test_tick_label_update(): # test issue 9397