diff --git a/lib/cartopy/mpl_integration/geoaxes.py b/lib/cartopy/mpl_integration/geoaxes.py index 96c236a5c..b7d536e3e 100644 --- a/lib/cartopy/mpl_integration/geoaxes.py +++ b/lib/cartopy/mpl_integration/geoaxes.py @@ -273,7 +273,7 @@ def draw(self, renderer=None, inframe=False): been set. """ - # if no data has been added, and no extents set, then make the + # if no data has been added, and no extent set, then make the # map global if self.ignore_existing_data_limits and \ self._autoscaleXon and self._autoscaleYon: @@ -468,8 +468,8 @@ def get_extent(self, crs=None): Get the extent (x0, x1, y0, y1) of the map in the given coordinate system. - If no crs is given, the returned extents' coordinate system will be - assumed to be the Geodetic version of this axes' projection. + If no crs is given, the coordinate system of the returned extent will + be this axes' projection. """ p = self._get_extent_geom(crs) @@ -519,19 +519,22 @@ def _get_extent_geom(self, crs=None): return domain_in_crs - def set_extent(self, extents, crs=None): + def set_extent(self, extent, crs=None): """ Set the extent (x0, x1, y0, y1) of the map in the given coordinate system. - If no crs is given, the extents' coordinate system will be assumed - to be the Geodetic version of this axes' projection. + If no crs is given, the extent's coordinate system will be assumed + to be this axes' projection. """ # TODO: Implement the same semantics as plt.xlim and # plt.ylim - allowing users to set None for a minimum and/or # maximum value - x1, x2, y1, y2 = extents + if crs is None: + crs = self.projection + + x1, x2, y1, y2 = extent domain_in_crs = shapely.geometry.LineString([[x1, y1], [x2, y1], [x2, y2], [x1, y2], [x1, y1]]) @@ -549,8 +552,8 @@ def set_global(self): In some cases where the projection has a limited sensible range the ``set_global`` method does not actually make the whole globe - visible. Instead, the most appropriate extents will be used (e.g. - Ordnance Survey UK will set the extents to be around the British + visible. Instead, the most appropriate extent will be used (e.g. + Ordnance Survey UK will set the extent to be around the British Isles. """ diff --git a/lib/cartopy/tests/mpl/baseline_images/mpl/test_set_extent/set_extent_wrapping.png b/lib/cartopy/tests/mpl/baseline_images/mpl/test_set_extent/set_extent_wrapping.png new file mode 100644 index 000000000..2795fb91e Binary files /dev/null and b/lib/cartopy/tests/mpl/baseline_images/mpl/test_set_extent/set_extent_wrapping.png differ diff --git a/lib/cartopy/tests/mpl/test_get_extent.py b/lib/cartopy/tests/mpl/test_get_extent.py new file mode 100644 index 000000000..70d9c636d --- /dev/null +++ b/lib/cartopy/tests/mpl/test_get_extent.py @@ -0,0 +1,82 @@ +# (C) British Crown Copyright 2011 - 2012, Met Office +# +# This file is part of cartopy. +# +# cartopy 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. +# +# cartopy 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 cartopy. If not, see . +import unittest +import warnings + +import matplotlib.pyplot as plt +from numpy.testing import assert_array_almost_equal + +import cartopy.crs as ccrs + +class TestGetExtent(unittest.TestCase): + def test_get_extent(self): + # Set up known extent around the UK. + uk = (-12.5, 4., 49., 60.) + uk_crs = ccrs.Geodetic() + projection = ccrs.Mollweide() + ax = plt.axes(projection=projection) + ax.set_extent(uk, crs=uk_crs) + + # Result of get_extent with no specified coordinate system should be + # in the projection of the axes (Mollweide in this case). + assert_array_almost_equal(ax.get_extent(), ax.get_extent(projection)) + + # Obtain the extent in a range of projections and check against + # expected values. + + # Mollweide + expected = (-963125.8421709834, 308200.26949471474, + 5768352.350108459, 6876758.993328802) + extent = ax.get_extent(ccrs.Mollweide()) + assert_array_almost_equal(extent, expected) + + # Geodetic (should raise warning, but still give the PlateCarree result). + expected_plate_carree = (-14.850129, 4.752041, 49., 60.) + expected = expected_plate_carree + with warnings.catch_warnings(): + # Check for warning. + warnings.simplefilter('error') + with self.assertRaises(UserWarning): + ax.get_extent(ccrs.Geodetic()) + # Check result. + warnings.simplefilter('ignore') + extent = ax.get_extent(ccrs.Geodetic()) + assert_array_almost_equal(extent, expected) + + # PlateCarree + expected = expected_plate_carree + extent = ax.get_extent(ccrs.PlateCarree()) + assert_array_almost_equal(extent, expected) + + # PlateCarree with nonzero central_longitude + central_longitude = 20 + expected = (expected_plate_carree[0] - central_longitude, + expected_plate_carree[1] - central_longitude, + expected_plate_carree[2], + expected_plate_carree[3]) + extent = ax.get_extent(ccrs.PlateCarree(central_longitude)) + assert_array_almost_equal(extent, expected) + + # NorthPolarStereo + expected = (-1034046.2256626057, 333263.47741164186, + -4765889.766015143, -3311994.6422885) + extent = ax.get_extent(ccrs.NorthPolarStereo()) + assert_array_almost_equal(extent, expected) + + +if __name__ == '__main__': + unittest.main() diff --git a/lib/cartopy/tests/mpl/test_mpl_integration.py b/lib/cartopy/tests/mpl/test_mpl_integration.py index 6af19b161..c8c72af48 100644 --- a/lib/cartopy/tests/mpl/test_mpl_integration.py +++ b/lib/cartopy/tests/mpl/test_mpl_integration.py @@ -307,7 +307,7 @@ def test_pcolormesh_limited_area_wrap(): ax = plt.subplot(223, projection=ccrs.PlateCarree(180)) plt.pcolormesh(x, y, data, transform=rp, cmap='Set1') ax.coastlines() - ax.set_extent([-70, 0, 0, 80]) + ax.set_extent([-70, 0, 0, 80], ccrs.Geodetic()) ax = plt.subplot(224, projection=rp) plt.pcolormesh(xbnds, ybnds, data, transform=rp, cmap='Set1') diff --git a/lib/cartopy/tests/mpl/test_set_extent.py b/lib/cartopy/tests/mpl/test_set_extent.py index 903ca7e7f..efdb5f704 100644 --- a/lib/cartopy/tests/mpl/test_set_extent.py +++ b/lib/cartopy/tests/mpl/test_set_extent.py @@ -21,7 +21,7 @@ from numpy.testing import assert_array_almost_equal import cartopy.crs as ccrs - +from cartopy.tests.mpl import ImageTesting @cleanup def test_extents(): @@ -51,7 +51,40 @@ def test_extents(): np.array([[-17.17698577, 48.21879707], [ 5.68924381, 60.54218893]]) ) - + +@ImageTesting(['set_extent_wrapping']) +def test_wrapping(): + # Tests that set_extent() handles longitudes in 0 to 360 format + # and that an extent that crosses the boundary is handled appropriately. + fig = plt.figure(figsize=(10, 6)) + + # Extent of Australia region in 0 to 360. + extent_0_to_360 = (85.0, 220.0, -55.0, 20.0) + + # In PlateCarree(180) Australia region is central and + # should not wrap. 0 to 360 conversion should be handled implicitly. + ax = fig.add_subplot(2, 2, 1, projection=ccrs.PlateCarree(180)) + ax.coastlines() + ax.set_extent(extent_0_to_360, ccrs.PlateCarree()) + + # In PlateCarree() the region crosses the boundary so the result + # should be a -180 to 180 strip covering -55 to 20 deg lat. + ax = fig.add_subplot(2, 2, 2, projection=ccrs.PlateCarree()) + ax.coastlines() + ax.set_extent(extent_0_to_360, ccrs.PlateCarree()) + + # The extent when expressed in the projection of the axes + # should not require the crs to be specified. + extent = (-95.0, 40.0, -55.0, 20.0) + ax = fig.add_subplot(2, 2, 3, projection=ccrs.PlateCarree(180)) + ax.coastlines() + ax.set_extent(extent) + + # If we do set the crs explicitly we should still get the same result as + # the previous plot. + ax = fig.add_subplot(2, 2, 4, projection=ccrs.PlateCarree(180)) + ax.coastlines() + ax.set_extent(extent, ccrs.PlateCarree(180)) def test_update_lim(): # check that the standard data lim setting works