From ace1232765b23429a8de9f64d7b63bdad0040ea3 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 12:17:28 +0200 Subject: [PATCH 01/11] Remove default re-definition --- xarray/plot/utils.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index a71613562a5..a8aeb052ad6 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -931,9 +931,6 @@ def _process_cmap_cbar_kwargs( cbar_kwargs = {} if cbar_kwargs is None else dict(cbar_kwargs) - if "contour" in func.__name__ and levels is None: - levels = 7 # this is the matplotlib default - # colors is mutually exclusive with cmap if cmap and colors: raise ValueError("Can't specify both cmap and colors.") From 7f10fd021e48851df567e01b17913eb4ba4f2a42 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:01:01 +0200 Subject: [PATCH 02/11] colors arg should take priority over default cmaps --- xarray/plot/dataarray_plot.py | 2 +- xarray/tests/test_plot.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/xarray/plot/dataarray_plot.py b/xarray/plot/dataarray_plot.py index 537fbd5bafb..4a79f9ad0ef 100644 --- a/xarray/plot/dataarray_plot.py +++ b/xarray/plot/dataarray_plot.py @@ -1588,7 +1588,7 @@ def newplotfunc( kwargs["levels"] = cmap_params["levels"] # if colors == a single color, matplotlib draws dashed negative # contours. we lose this feature if we pass cmap and not colors - if isinstance(colors, str): + if colors is not None: cmap_params["cmap"] = None kwargs["colors"] = colors diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index bfe0b81e4b6..67cae053350 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1787,16 +1787,18 @@ def test_colors(self) -> None: artist = self.plotmethod(colors="k") assert artist.cmap.colors[0] == "k" + # 2 colors, will repeat every other tick: artist = self.plotmethod(colors=["k", "b"]) - assert self._color_as_tuple(artist.cmap.colors[1]) == (0.0, 0.0, 1.0) + assert artist.cmap.colors[:2] == ["k", "b"] + # 4 colors, will repeat every 4th tick: artist = self.darray.plot.contour( levels=[-0.5, 0.0, 0.5, 1.0], colors=["k", "r", "w", "b"] ) - assert self._color_as_tuple(artist.cmap.colors[1]) == (1.0, 0.0, 0.0) - assert self._color_as_tuple(artist.cmap.colors[2]) == (1.0, 1.0, 1.0) + assert artist.cmap.colors[:5] == ["k", "r", "w", "b"] + # the last color is now under "over" - assert self._color_as_tuple(artist.cmap._rgba_over) == (0.0, 0.0, 1.0) + assert self._color_as_tuple(artist.cmap.get_over()) == (0.0, 0.0, 1.0) def test_colors_np_levels(self) -> None: # https://github.com/pydata/xarray/issues/3284 From 0acde69afa706e91b3fb77529a081edd02f06a42 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:10:08 +0200 Subject: [PATCH 03/11] Update test_plot.py --- xarray/tests/test_plot.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 67cae053350..2326b33aa76 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1810,11 +1810,10 @@ def test_colors_np_levels(self) -> None: # https://github.com/matplotlib/matplotlib/blob/84464dd085210fb57cc2419f0d4c0235391d97e6/lib/matplotlib/colors.pyi#L133 colors = cast(np.ndarray, cmap.colors) - assert self._color_as_tuple(colors[1]) == (1.0, 0.0, 0.0) - assert self._color_as_tuple(colors[2]) == (1.0, 1.0, 1.0) + assert artist.cmap.colors[:5] == ["k", "r", "w", "b"] + # the last color is now under "over" - assert hasattr(cmap, "_rgba_over") - assert self._color_as_tuple(cmap._rgba_over) == (0.0, 0.0, 1.0) + assert self._color_as_tuple(cmap.get_over()) == (0.0, 0.0, 1.0) def test_cmap_and_color_both(self) -> None: with pytest.raises(ValueError): From 455af1e979c7f61006542d357f16881bb641ae67 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:18:59 +0200 Subject: [PATCH 04/11] Update test_plot.py --- xarray/tests/test_plot.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 2326b33aa76..200c2955fb0 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1806,9 +1806,6 @@ def test_colors_np_levels(self) -> None: artist = self.darray.plot.contour(levels=levels, colors=["k", "r", "w", "b"]) cmap = artist.cmap assert isinstance(cmap, mpl.colors.ListedColormap) - # non-optimal typing in matplotlib (ArrayLike) - # https://github.com/matplotlib/matplotlib/blob/84464dd085210fb57cc2419f0d4c0235391d97e6/lib/matplotlib/colors.pyi#L133 - colors = cast(np.ndarray, cmap.colors) assert artist.cmap.colors[:5] == ["k", "r", "w", "b"] From 9e5e377e85c5bf009e5665b5178fedd7d7e50ee6 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:50:20 +0200 Subject: [PATCH 05/11] add log norm test --- xarray/tests/test_plot.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 200c2955fb0..6c21323e8f8 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1834,6 +1834,21 @@ def test_single_level(self) -> None: self.plotmethod(levels=[0.1]) self.plotmethod(levels=1) + def test_colormap_norm(self) -> None: + norm = mpl.colors.LogNorm(0.1, 1e1) + + artist = self.plotmethod(norm=norm) + + lev_exp = np.arange( + np.floor(np.log10(artist.colorbar.vmin) - 2), + np.ceil(np.log10(artist.colorbar.vmax) + 4), + 2, + ) + expected = np.power(10, lev_exp) + + actual = artist.colorbar.locator() + np.testing.assert_allclose(actual, expected) + class TestPcolormesh(Common2dMixin, PlotTestCase): plotfunc = staticmethod(xplt.pcolormesh) From 1a8738539e24d4abaa815413ee95c45a28426430 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:55:10 +0200 Subject: [PATCH 06/11] Add tests --- xarray/tests/test_plot.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 6c21323e8f8..83354697fc4 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1771,6 +1771,16 @@ def test_levels(self) -> None: artist = self.plotmethod(levels=3) assert artist.extend == "neither" + def test_colormap_norm(self) -> None: + norm = mpl.colors.LogNorm(0.1, 1e1) + + artist = self.plotmethod(norm=norm, add_colorbar=True) + + actual = artist.colorbar.locator() + expected = np.array([0.01, 0.1, 1.0, 10.0]) + + np.testing.assert_allclose(actual, expected) + @pytest.mark.slow class TestContour(Common2dMixin, PlotTestCase): @@ -1837,19 +1847,19 @@ def test_single_level(self) -> None: def test_colormap_norm(self) -> None: norm = mpl.colors.LogNorm(0.1, 1e1) - artist = self.plotmethod(norm=norm) - - lev_exp = np.arange( - np.floor(np.log10(artist.colorbar.vmin) - 2), - np.ceil(np.log10(artist.colorbar.vmax) + 4), - 2, - ) - expected = np.power(10, lev_exp) + artist = self.plotmethod(norm=norm, add_colorbar=True) actual = artist.colorbar.locator() + expected = np.array([0.01, 0.1, 1.0, 10.0]) + np.testing.assert_allclose(actual, expected) +c = TestContour() +c.setUp() +c.test_colors() +c.test_colormap_norm() +err class TestPcolormesh(Common2dMixin, PlotTestCase): plotfunc = staticmethod(xplt.pcolormesh) From aee1ae07dc6a813736229e966123c3d5d7f08506 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:00:51 +0000 Subject: [PATCH 07/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/tests/test_plot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 83354697fc4..d4ec12317b7 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1860,6 +1860,8 @@ def test_colormap_norm(self) -> None: c.test_colors() c.test_colormap_norm() err + + class TestPcolormesh(Common2dMixin, PlotTestCase): plotfunc = staticmethod(xplt.pcolormesh) From 050f245b95912a893746e9bb49cea921070d597d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 15:03:48 +0200 Subject: [PATCH 08/11] Update test_plot.py --- xarray/tests/test_plot.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index d4ec12317b7..4eb857d90ca 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1855,13 +1855,6 @@ def test_colormap_norm(self) -> None: np.testing.assert_allclose(actual, expected) -c = TestContour() -c.setUp() -c.test_colors() -c.test_colormap_norm() -err - - class TestPcolormesh(Common2dMixin, PlotTestCase): plotfunc = staticmethod(xplt.pcolormesh) From 0f93f0452279e86db9d75a5dd44fd714d4ac96cc Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 15:09:52 +0200 Subject: [PATCH 09/11] Update test_plot.py --- xarray/tests/test_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 4eb857d90ca..4e7c5bba84a 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1817,7 +1817,7 @@ def test_colors_np_levels(self) -> None: cmap = artist.cmap assert isinstance(cmap, mpl.colors.ListedColormap) - assert artist.cmap.colors[:5] == ["k", "r", "w", "b"] + assert artist.cmap.colors[:5] == ["k", "r", "w", "b"] # type: ignore[attr-defined] # the last color is now under "over" assert self._color_as_tuple(cmap.get_over()) == (0.0, 0.0, 1.0) From ad3d0a63eacbfabf47c1328148e63c93b7a6c1ee Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 15:15:53 +0200 Subject: [PATCH 10/11] Update test_plot.py --- xarray/tests/test_plot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index 4e7c5bba84a..ceba15594be 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1772,6 +1772,7 @@ def test_levels(self) -> None: assert artist.extend == "neither" def test_colormap_norm(self) -> None: + # Using a norm should plot a nice colorbar and look consistent with pcolormesh. norm = mpl.colors.LogNorm(0.1, 1e1) artist = self.plotmethod(norm=norm, add_colorbar=True) @@ -1845,6 +1846,7 @@ def test_single_level(self) -> None: self.plotmethod(levels=1) def test_colormap_norm(self) -> None: + # Using a norm should plot a nice colorbar and look consistent with pcolormesh. norm = mpl.colors.LogNorm(0.1, 1e1) artist = self.plotmethod(norm=norm, add_colorbar=True) From 8c102cf70372cb19a3bd204e6537d5931760f221 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 24 Jul 2025 15:25:30 +0200 Subject: [PATCH 11/11] Update test_plot.py --- xarray/tests/test_plot.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index ceba15594be..bc1918a8028 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -1775,7 +1775,8 @@ def test_colormap_norm(self) -> None: # Using a norm should plot a nice colorbar and look consistent with pcolormesh. norm = mpl.colors.LogNorm(0.1, 1e1) - artist = self.plotmethod(norm=norm, add_colorbar=True) + with pytest.warns(UserWarning): + artist = self.plotmethod(norm=norm, add_colorbar=True) actual = artist.colorbar.locator() expected = np.array([0.01, 0.1, 1.0, 10.0]) @@ -1849,7 +1850,8 @@ def test_colormap_norm(self) -> None: # Using a norm should plot a nice colorbar and look consistent with pcolormesh. norm = mpl.colors.LogNorm(0.1, 1e1) - artist = self.plotmethod(norm=norm, add_colorbar=True) + with pytest.warns(UserWarning): + artist = self.plotmethod(norm=norm, add_colorbar=True) actual = artist.colorbar.locator() expected = np.array([0.01, 0.1, 1.0, 10.0])