diff --git a/docs/gallery_code/meteorology/plot_zonal_mean.py b/docs/gallery_code/meteorology/plot_zonal_mean.py new file mode 100644 index 0000000000..8228765275 --- /dev/null +++ b/docs/gallery_code/meteorology/plot_zonal_mean.py @@ -0,0 +1,75 @@ +""" +Zonal Mean Diagram of Air Temperature +===================================== + +This example demonstrates aligning a linear plot and a cartographic plot using Matplotlib. + +""" + +import cartopy.crs as ccrs +import matplotlib.pyplot as plt +from mpl_toolkits.axes_grid1 import make_axes_locatable +import numpy as np + +import iris +from iris.analysis import MEAN +import iris.plot as iplt + + +def main(): + fname = iris.sample_data_path("air_temp.pp") + temperature = iris.load_cube(fname) + collapsed_temp = temperature.collapsed("longitude", MEAN) + + # Set y axes with -90 and 90 limits and spacing of 15 per tick. + yticks = np.arange(-90, 105, 15) + ylim = [-90, 90] + fig = plt.figure(figsize=[12, 4]) + ax1 = fig.add_subplot(111, projection=ccrs.PlateCarree()) + plt.sca(ax1) + im = iplt.contourf(temperature, cmap="RdYlBu_r") + ax1.coastlines() + ax1.gridlines() + ax1.set_xticks([-180, -90, 0, 90, 180], crs=ccrs.PlateCarree()) + ax1.set_yticks(yticks, crs=ccrs.PlateCarree()) + ax1.set_title("Air Temperature") + ax1.set_ylabel("latitude") + ax1.set_xlabel("longitude") + ax1.set_ylim(*ylim) + divider = make_axes_locatable(ax1) + + # Gives the air temperature bar size, colour and a title. + ax2 = divider.new_vertical( + size="5%", pad=0.5, axes_class=plt.Axes, pack_start=True + ) + fig.add_axes(ax2) + plt.sca(ax2) + cbar = plt.colorbar(im, cax=ax2, orientation="horizontal") + cbar.ax.set_xlabel("Air Temperature [k]") + + # Round each tick for the third ax to the nearest 20 (ready for use). + data_max = collapsed_temp.data.max() + x_max = data_max - data_max % -20 + data_min = collapsed_temp.data.min() + x_min = data_min - data_min % 20 + + # Plot "collapsed_temp" on the mean graph and set the ticks and titles on the axes. + ax3 = divider.new_horizontal(size="30%", pad=0.4, axes_class=plt.Axes) + fig.add_axes(ax3) + plt.sca(ax3) + iplt.plot(collapsed_temp, collapsed_temp.coord("latitude")) + ax3.axvline(0, color="k", linewidth=0.5) + ax3.set_ylim(*ylim) + ax3.set_title("Zonal mean") + ax3.set_ylabel("latitude") + ax3.set_xlabel("Air Temperature [k]") + ax3.yaxis.set_label_position("right") + ax3.yaxis.tick_right() + ax3.set_yticks(yticks) + ax3.set_xlim(x_min, x_max) + + plt.show() + + +if __name__ == "__main__": + main() diff --git a/docs/gallery_tests/test_plot_zonal_mean.py b/docs/gallery_tests/test_plot_zonal_mean.py new file mode 100644 index 0000000000..e9996758b1 --- /dev/null +++ b/docs/gallery_tests/test_plot_zonal_mean.py @@ -0,0 +1,30 @@ +# Copyright Iris contributors +# +# This file is part of Iris and is released under the LGPL license. +# See COPYING and COPYING.LESSER in the root of the repository for full +# licensing details. + +# Import Iris tests first so that some things can be initialised before +# importing anything else. +import iris.tests as tests + +from .gallerytest_util import ( + add_gallery_to_path, + fail_any_deprecation_warnings, + show_replaced_by_check_graphic, +) + + +class TestGlobalMap(tests.GraphicsTest): + """Test the zonal mean gallery code.""" + + def test_plot_zonal_mean(self): + with fail_any_deprecation_warnings(): + with add_gallery_to_path(): + import plot_zonal_mean + with show_replaced_by_check_graphic(self): + plot_zonal_mean.main() + + +if __name__ == "__main__": + tests.main() diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 761833ba15..350eb732b1 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -25,7 +25,8 @@ This document explains the changes made to Iris for this release 📢 Announcements ================ -#. N/A +#. Welcome to `@TTV-Intrepid`_ who made their first contribution to Iris. + The first of many we hope! ✨ Features @@ -217,6 +218,9 @@ This document explains the changes made to Iris for this release #. `@trexfeathers`_ and `@abooton`_ modernised the Iris logo to be SVG format. (:pull:`3935`) +#. `@TTV-Intrepid`_ and `@trexfeathers`_ added a gallery example for zonal + means plotted parallel to a cartographic plot. (:pull:`4871`) + 💼 Internal =========== @@ -268,4 +272,5 @@ This document explains the changes made to Iris for this release .. _Calendar: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html#calendar .. _Cell Boundaries: https://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html#cell-boundaries .. _PyData Sphinx Theme: https://pydata-sphinx-theme.readthedocs.io/en/stable/index.html -.. _setuptools-scm: https://github.com/pypa/setuptools_scm \ No newline at end of file +.. _setuptools-scm: https://github.com/pypa/setuptools_scm +.. _@TTV-Intrepid: https://github.com/TTV-Intrepid \ No newline at end of file diff --git a/lib/iris/tests/results/imagerepo.json b/lib/iris/tests/results/imagerepo.json index 28d6f0bb03..37c51a3515 100644 --- a/lib/iris/tests/results/imagerepo.json +++ b/lib/iris/tests/results/imagerepo.json @@ -34,6 +34,7 @@ "gallery_tests.test_plot_wind_barbs.TestWindBarbs.test_wind_barbs.0": "e9e161e996169316c1fe9e96c29e36739e13c07c3d61c07f39813929c07f3f01", "gallery_tests.test_plot_wind_speed.TestWindSpeed.test_plot_wind_speed.0": "e9e960e996169306c1fe9e96c29e36739e03c06c3d61c07f3da139e1c07f3f01", "gallery_tests.test_plot_wind_speed.TestWindSpeed.test_plot_wind_speed.1": "e9e960e996169306c1ee9f96c29e36739653c06c3d61c07f39a139e1c07f3f01", + "gallery_tests.test_plot_zonal_mean.TestGlobalMap.test_plot_zonal_mean.0": "b45b30f3c924c9a6869c667cc326cba3cb9634ddc9a634f336738c6634d8c3c4", "iris.tests.experimental.test_animate.IntegrationTest.test_cube_animation.0": "fe81c17e817e3e81817e3e81857e7a817e81c17e7e81c17e7a81817e817e8c2e", "iris.tests.experimental.test_animate.IntegrationTest.test_cube_animation.1": "fe81857e817e7a85817e7a81857e7e817e81917a7e81817e7a81817e817e843e", "iris.tests.experimental.test_animate.IntegrationTest.test_cube_animation.2": "be81817ec17e7a81c17e7e81857e3e803e81817a3e81c17e7a81c17ec97e2c2f",