diff --git a/docs/iris/src/whatsnew/2.1.rst b/docs/iris/src/whatsnew/2.1.rst index a1c4a21e5f..e8c91aba29 100644 --- a/docs/iris/src/whatsnew/2.1.rst +++ b/docs/iris/src/whatsnew/2.1.rst @@ -57,6 +57,8 @@ Iris 2.1 Features * Iris can now represent data on the Albers Equal Area Projection, and the NetCDF loader and saver were updated to handle this. https://github.com/SciTools/iris/issues/2943 +* The :class:`~iris.coord_systems.Mercator` projection has been updated to accept + the ``standard_parallel`` keyword argument. Bugs Fixed ========== diff --git a/lib/iris/coord_systems.py b/lib/iris/coord_systems.py index 0bc770f9b8..e02ae7dc8c 100644 --- a/lib/iris/coord_systems.py +++ b/lib/iris/coord_systems.py @@ -831,7 +831,8 @@ class Mercator(CoordSystem): grid_mapping_name = "mercator" - def __init__(self, longitude_of_projection_origin=0, ellipsoid=None): + def __init__(self, longitude_of_projection_origin=0.0, ellipsoid=None, + standard_parallel=0.0): """ Constructs a Mercator coord system. @@ -840,17 +841,23 @@ def __init__(self, longitude_of_projection_origin=0, ellipsoid=None): True longitude of planar origin in degrees. * ellipsoid :class:`GeogCS` defining the ellipsoid. + * standard_parallel + the latitude where the scale is 1. Defaults to 0 degrees. """ - #: True longitude of planar origin in degrees. self.longitude_of_projection_origin = longitude_of_projection_origin #: Ellipsoid definition. self.ellipsoid = ellipsoid + #: The latitude where the scale is 1 (defaults to 0 degrees). + self.standard_parallel = standard_parallel def __repr__(self): - res = "Mercator(longitude_of_projection_origin={!r}, ellipsoid={!r})" - return res.format(self.longitude_of_projection_origin, self.ellipsoid) + res = ("Mercator(longitude_of_projection_origin=" + "{self.longitude_of_projection_origin!r}, " + "ellipsoid={self.ellipsoid!r}, " + "standard_parallel={self.standard_parallel!r})") + return res.format(self=self) def as_cartopy_crs(self): if self.ellipsoid is not None: @@ -860,7 +867,8 @@ def as_cartopy_crs(self): return ccrs.Mercator( central_longitude=self.longitude_of_projection_origin, - globe=globe) + globe=globe, + latitude_true_scale=self.standard_parallel) def as_cartopy_projection(self): return self.as_cartopy_crs() diff --git a/lib/iris/tests/results/coord_systems/Mercator.xml b/lib/iris/tests/results/coord_systems/Mercator.xml index db84f80666..e8036ef824 100644 --- a/lib/iris/tests/results/coord_systems/Mercator.xml +++ b/lib/iris/tests/results/coord_systems/Mercator.xml @@ -1,2 +1,2 @@ - + diff --git a/lib/iris/tests/results/netcdf/netcdf_merc.cml b/lib/iris/tests/results/netcdf/netcdf_merc.cml index ef239bb2f2..02fc4e7c34 100644 --- a/lib/iris/tests/results/netcdf/netcdf_merc.cml +++ b/lib/iris/tests/results/netcdf/netcdf_merc.cml @@ -53,15 +53,15 @@ 45.5158, 45.9993]]" shape="(192, 192)" standard_name="longitude" units="Unit('degrees')" value_type="float32" var_name="lon"/> - - + - - + diff --git a/lib/iris/tests/test_coordsystem.py b/lib/iris/tests/test_coordsystem.py index 25be9bb1be..6def1a3123 100644 --- a/lib/iris/tests/test_coordsystem.py +++ b/lib/iris/tests/test_coordsystem.py @@ -33,17 +33,12 @@ from iris.coord_systems import * - - def osgb(): return TransverseMercator(latitude_of_projection_origin=49, longitude_of_central_meridian=-2, false_easting=-400, false_northing=100, scale_factor_at_central_meridian=0.9996012717, ellipsoid=GeogCS(6377563.396, 6356256.909)) -def merc(): - return Mercator(longitude_of_projection_origin=90.0, - ellipsoid=GeogCS(6377563.396, 6356256.909)) def stereo(): return Stereographic(central_lat=-90, central_lon=-45, @@ -391,58 +386,5 @@ def test_south_cutoff(self): self.assertEqual(ccrs.cutoff, 30) -class Test_Mercator_construction(tests.IrisTest): - def test_merc(self): - tm = merc() - self.assertXMLElement(tm, ("coord_systems", "Mercator.xml")) - - -class Test_Mercator_repr(tests.IrisTest): - def test_merc(self): - tm = merc() - expected = "Mercator(longitude_of_projection_origin=90.0, "\ - "ellipsoid=GeogCS(semi_major_axis=6377563.396, "\ - "semi_minor_axis=6356256.909))" - self.assertEqual(expected, repr(tm)) - - -class Test_Mercator_as_cartopy_crs(tests.IrisTest): - def test_as_cartopy_crs(self): - longitude_of_projection_origin = 90.0 - ellipsoid = GeogCS(semi_major_axis=6377563.396, - semi_minor_axis=6356256.909) - - merc_cs = Mercator( - longitude_of_projection_origin, - ellipsoid=ellipsoid) - - expected = ccrs.Mercator( - central_longitude=longitude_of_projection_origin, - globe=ccrs.Globe(semimajor_axis=6377563.396, - semiminor_axis=6356256.909, ellipse=None)) - - res = merc_cs.as_cartopy_crs() - self.assertEqual(res, expected) - - -class Test_Mercator_as_cartopy_projection(tests.IrisTest): - def test_as_cartopy_projection(self): - longitude_of_projection_origin = 90.0 - ellipsoid = GeogCS(semi_major_axis=6377563.396, - semi_minor_axis=6356256.909) - - merc_cs = Mercator( - longitude_of_projection_origin, - ellipsoid=ellipsoid) - - expected = ccrs.Mercator( - central_longitude=longitude_of_projection_origin, - globe=ccrs.Globe(semimajor_axis=6377563.396, - semiminor_axis=6356256.909, ellipse=None)) - - res = merc_cs.as_cartopy_projection() - self.assertEqual(res, expected) - - if __name__ == "__main__": tests.main() diff --git a/lib/iris/tests/unit/coord_systems/test_Mercator.py b/lib/iris/tests/unit/coord_systems/test_Mercator.py new file mode 100644 index 0000000000..a2791efe67 --- /dev/null +++ b/lib/iris/tests/unit/coord_systems/test_Mercator.py @@ -0,0 +1,109 @@ +# (C) British Crown Copyright 2018, Met Office +# +# This file is part of Iris. +# +# Iris is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Iris. If not, see . +"""Unit tests for the :class:`iris.coord_systems.Mercator` class.""" + +from __future__ import (absolute_import, division, print_function) +from six.moves import (filter, input, map, range, zip) # noqa + +# Import iris.tests first so that some things can be initialised before +# importing anything else. +import iris.tests as tests + +import cartopy.crs as ccrs +from iris.coord_systems import GeogCS, Mercator + + +class Test_Mercator__basics(tests.IrisTest): + def setUp(self): + self.tm = Mercator(longitude_of_projection_origin=90.0, + ellipsoid=GeogCS(6377563.396, 6356256.909)) + + def test_construction(self): + self.assertXMLElement(self.tm, ("coord_systems", "Mercator.xml")) + + def test_repr(self): + expected = ("Mercator(longitude_of_projection_origin=90.0, " + "ellipsoid=GeogCS(semi_major_axis=6377563.396, " + "semi_minor_axis=6356256.909), " + "standard_parallel=0.0)") + self.assertEqual(expected, repr(self.tm)) + + +class Test_Mercator__as_cartopy_crs(tests.IrisTest): + def test_simple(self): + # Check that a projection set up with all the defaults is correctly + # converted to a cartopy CRS. + merc_cs = Mercator() + res = merc_cs.as_cartopy_crs() + expected = ccrs.Mercator(globe=ccrs.Globe()) + self.assertEqual(res, expected) + + def test_extra_kwargs(self): + # Check that a projection with non-default values is correctly + # converted to a cartopy CRS. + longitude_of_projection_origin = 90.0 + true_scale_lat = 14.0 + ellipsoid = GeogCS(semi_major_axis=6377563.396, + semi_minor_axis=6356256.909) + + merc_cs = Mercator( + longitude_of_projection_origin, + ellipsoid=ellipsoid, + standard_parallel=true_scale_lat) + + expected = ccrs.Mercator( + central_longitude=longitude_of_projection_origin, + globe=ccrs.Globe(semimajor_axis=6377563.396, + semiminor_axis=6356256.909, ellipse=None), + latitude_true_scale=true_scale_lat) + + res = merc_cs.as_cartopy_crs() + self.assertEqual(res, expected) + + +class Test_as_cartopy_projection(tests.IrisTest): + def test_simple(self): + # Check that a projection set up with all the defaults is correctly + # converted to a cartopy projection. + merc_cs = Mercator() + res = merc_cs.as_cartopy_projection() + expected = ccrs.Mercator(globe=ccrs.Globe()) + self.assertEqual(res, expected) + + def test_extra_kwargs(self): + longitude_of_projection_origin = 90.0 + true_scale_lat = 14.0 + ellipsoid = GeogCS(semi_major_axis=6377563.396, + semi_minor_axis=6356256.909) + + merc_cs = Mercator( + longitude_of_projection_origin, + ellipsoid=ellipsoid, + standard_parallel=true_scale_lat) + + expected = ccrs.Mercator( + central_longitude=longitude_of_projection_origin, + globe=ccrs.Globe(semimajor_axis=6377563.396, + semiminor_axis=6356256.909, ellipse=None), + latitude_true_scale=true_scale_lat) + + res = merc_cs.as_cartopy_projection() + self.assertEqual(res, expected) + + +if __name__ == "__main__": + tests.main()