diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 5f909d07c190..08fe5c053802 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -1191,17 +1191,13 @@ class ListedColormap(Colormap): the list will be extended by repetition. """ def __init__(self, colors, name='from_list', N=None): - self.monochrome = False # Are all colors identical? (for contour.py) if N is None: self.colors = colors N = len(colors) else: if isinstance(colors, str): self.colors = [colors] * N - self.monochrome = True elif np.iterable(colors): - if len(colors) == 1: - self.monochrome = True self.colors = list( itertools.islice(itertools.cycle(colors), N)) else: @@ -1211,7 +1207,6 @@ def __init__(self, colors, name='from_list', N=None): pass else: self.colors = [gray] * N - self.monochrome = True super().__init__(name, N) def _init(self): @@ -1220,6 +1215,21 @@ def _init(self): self._isinit = True self._set_extremes() + @property + def monochrome(self): + """Return whether all colors in the colormap are identical.""" + # Replacement for the attribute *monochrome*. This ensures a consistent + # response independent of the way the ListedColormap was created, which + # was not the case for the manually set attribute. + # + # TODO: It's a separate discussion whether we need this property on + # colormaps at all (at least as public API). It's a very special edge + # case and we only use it for contours internally. + if not self._isinit: + self._init() + + return self.N <= 1 or np.all(self._lut[0] == self._lut[1:self.N]) + def resampled(self, lutsize): """Return a new colormap with *lutsize* entries.""" colors = self(np.linspace(0, 1, lutsize)) diff --git a/lib/matplotlib/colors.pyi b/lib/matplotlib/colors.pyi index 6941e3d5d176..4ecf90164512 100644 --- a/lib/matplotlib/colors.pyi +++ b/lib/matplotlib/colors.pyi @@ -130,11 +130,12 @@ class LinearSegmentedColormap(Colormap): def reversed(self, name: str | None = ...) -> LinearSegmentedColormap: ... class ListedColormap(Colormap): - monochrome: bool colors: ArrayLike | ColorType def __init__( self, colors: ArrayLike | ColorType, name: str = ..., N: int | None = ... ) -> None: ... + @property + def monochrome(self) -> bool: ... def resampled(self, lutsize: int) -> ListedColormap: ... def reversed(self, name: str | None = ...) -> ListedColormap: ... diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index cc6cb1bb11a7..19c60091e608 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -74,6 +74,12 @@ def test_resampled(): assert_array_almost_equal(lc(np.nan), lc3(np.nan)) +def test_monochrome(): + assert mcolors.ListedColormap(["red"]).monochrome + assert mcolors.ListedColormap(["red"] * 5).monochrome + assert not mcolors.ListedColormap(["red", "green"]).monochrome + + def test_colormaps_get_cmap(): cr = mpl.colormaps