From b7666f83b9bb26a8fa0ab1d00a9beebab7aceefb Mon Sep 17 00:00:00 2001 From: Kristofer Krus Date: Mon, 8 Aug 2022 15:12:09 +0200 Subject: [PATCH 1/4] Prevent color bar from being misplaced Currently, if `plt.gca()` gives a different Axes object than `axes` in the function `_label`, the color bar will be malpositioned, ending up either on another subfigure, or in another figure window altogether. Specifying the `ax` argument when calling `plt.colorbar` prevents this. --- lib/iris/quickplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/iris/quickplot.py b/lib/iris/quickplot.py index 14f9e5d2d5..18ed2554a3 100644 --- a/lib/iris/quickplot.py +++ b/lib/iris/quickplot.py @@ -71,7 +71,7 @@ def _label(cube, mode, result=None, ndims=2, coords=None, axes=None): if result is not None: draw_edges = mode == iris.coords.POINT_MODE bar = plt.colorbar( - result, orientation="horizontal", drawedges=draw_edges + result, ax=axes, orientation="horizontal", drawedges=draw_edges ) has_known_units = not ( cube.units.is_unknown() or cube.units.is_no_unit() From f513d6cab814d9adf270449677be7012f0cb191e Mon Sep 17 00:00:00 2001 From: Bill Little Date: Tue, 9 Aug 2022 15:54:22 +0100 Subject: [PATCH 2/4] add whatsnew and test coverage --- docs/src/whatsnew/latest.rst | 8 +++++++- lib/iris/tests/test_quickplot.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 3c6391d0ba..61b4f02ffb 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -25,7 +25,7 @@ This document explains the changes made to Iris for this release 📢 Announcements ================ -#. N/A +#. Welcome to `@krikru`_ who made their first contribution to Iris 🎉 ✨ Features @@ -132,6 +132,11 @@ This document explains the changes made to Iris for this release array type. This prevents masks being lost in some cases and therefore resolves :issue:`2987`. (:pull:`3790`) +#. `@krikru`_ and `@rcomer`_ updated :mod:`iris.quickplot` such that the + colorbar is added to the correct ``axes`` when specified as a keyword + argument to a plotting routine. Otherwise, by default the colorbar will be + added to the current axes of the current figure. (:pull:`4894`) + 💣 Incompatible Changes ======================= @@ -272,6 +277,7 @@ This document explains the changes made to Iris for this release core dev names are automatically included by the common_links.inc: .. _@evertrol: https://github.com/evertrol +.. _@krikru: https://github.com/krikru .. comment diff --git a/lib/iris/tests/test_quickplot.py b/lib/iris/tests/test_quickplot.py index dec71a99ac..ea903f34d6 100644 --- a/lib/iris/tests/test_quickplot.py +++ b/lib/iris/tests/test_quickplot.py @@ -247,5 +247,35 @@ def test_not_reference_time_units(self): self.check_graphic() +@tests.skip_data +@tests.skip_plot +class TestSubplotColorbar(tests.IrisTest): + def setUp(self): + theta = _load_theta() + coords = ["model_level_number", "grid_longitude"] + self.data = next(theta.slices(coords)) + + @staticmethod + def _plot(): + fig1 = plt.figure() + ax1 = fig1.add_subplot(1, 1, 1) + fig2 = plt.figure() + _ = fig2.add_subplot(1, 1, 1) + + return fig1, ax1, fig2 + + def test__with_axes(self): + fig1, ax1, _ = self._plot() + # plot using the first figure subplot axes + gcs = qplt.contourf(self.data, axes=ax1) + self.assertIs(gcs.colorbar.ax.get_figure(), fig1) + + def test__without_axes(self): + _, _, fig2 = self._plot() + # plot using the second/last figure subplot axes (default) + gcs = qplt.contourf(self.data) + self.assertIs(gcs.colorbar.ax.get_figure(), fig2) + + if __name__ == "__main__": tests.main() From 898fe6403cc92ba4b1aed14906e8ff96521a5aaf Mon Sep 17 00:00:00 2001 From: Bill Little Date: Tue, 9 Aug 2022 22:41:00 +0100 Subject: [PATCH 3/4] check axes and figure --- lib/iris/tests/test_quickplot.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/iris/tests/test_quickplot.py b/lib/iris/tests/test_quickplot.py index ea903f34d6..80723a2247 100644 --- a/lib/iris/tests/test_quickplot.py +++ b/lib/iris/tests/test_quickplot.py @@ -254,27 +254,26 @@ def setUp(self): theta = _load_theta() coords = ["model_level_number", "grid_longitude"] self.data = next(theta.slices(coords)) + spec = (1, 1, 1) + self.fig1 = plt.figure() + self.ax1 = self.fig1.add_subplot(*spec) + self.fig2 = plt.figure() + self.ax2 = self.fig2.add_subplot(*spec) - @staticmethod - def _plot(): - fig1 = plt.figure() - ax1 = fig1.add_subplot(1, 1, 1) - fig2 = plt.figure() - _ = fig2.add_subplot(1, 1, 1) - - return fig1, ax1, fig2 + def _check(self, mappable, fig, ax): + self.assertIs(mappable.axes, ax) + self.assertIs(mappable.colorbar.mappable, mappable) + self.assertIs(mappable.colorbar.ax.get_figure(), fig) def test__with_axes(self): - fig1, ax1, _ = self._plot() # plot using the first figure subplot axes - gcs = qplt.contourf(self.data, axes=ax1) - self.assertIs(gcs.colorbar.ax.get_figure(), fig1) + mappable = qplt.contourf(self.data, axes=self.ax1) + self._check(mappable, self.fig1, self.ax1) def test__without_axes(self): - _, _, fig2 = self._plot() # plot using the second/last figure subplot axes (default) - gcs = qplt.contourf(self.data) - self.assertIs(gcs.colorbar.ax.get_figure(), fig2) + mappable = qplt.contourf(self.data) + self._check(mappable, self.fig2, self.ax2) if __name__ == "__main__": From 5411f9b97cd81d70b7f6b4e0fc52aa705677e26b Mon Sep 17 00:00:00 2001 From: Bill Little Date: Tue, 9 Aug 2022 23:02:27 +0100 Subject: [PATCH 4/4] tidy and add extra axes2 test --- lib/iris/tests/test_quickplot.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/iris/tests/test_quickplot.py b/lib/iris/tests/test_quickplot.py index 80723a2247..06f170c666 100644 --- a/lib/iris/tests/test_quickplot.py +++ b/lib/iris/tests/test_quickplot.py @@ -255,25 +255,30 @@ def setUp(self): coords = ["model_level_number", "grid_longitude"] self.data = next(theta.slices(coords)) spec = (1, 1, 1) - self.fig1 = plt.figure() - self.ax1 = self.fig1.add_subplot(*spec) - self.fig2 = plt.figure() - self.ax2 = self.fig2.add_subplot(*spec) + self.figure1 = plt.figure() + self.axes1 = self.figure1.add_subplot(*spec) + self.figure2 = plt.figure() + self.axes2 = self.figure2.add_subplot(*spec) - def _check(self, mappable, fig, ax): - self.assertIs(mappable.axes, ax) + def _check(self, mappable, figure, axes): + self.assertIs(mappable.axes, axes) self.assertIs(mappable.colorbar.mappable, mappable) - self.assertIs(mappable.colorbar.ax.get_figure(), fig) + self.assertIs(mappable.colorbar.ax.get_figure(), figure) - def test__with_axes(self): - # plot using the first figure subplot axes - mappable = qplt.contourf(self.data, axes=self.ax1) - self._check(mappable, self.fig1, self.ax1) + def test_with_axes1(self): + # plot using the first figure subplot axes (explicit) + mappable = qplt.contourf(self.data, axes=self.axes1) + self._check(mappable, self.figure1, self.axes1) - def test__without_axes(self): + def test_with_axes2(self): + # plot using the second figure subplot axes (explicit) + mappable = qplt.contourf(self.data, axes=self.axes2) + self._check(mappable, self.figure2, self.axes2) + + def test_without_axes__default(self): # plot using the second/last figure subplot axes (default) mappable = qplt.contourf(self.data) - self._check(mappable, self.fig2, self.ax2) + self._check(mappable, self.figure2, self.axes2) if __name__ == "__main__":