Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions lib/cartopy/mpl_integration/geoaxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]])
Expand All @@ -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.

"""
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions lib/cartopy/tests/mpl/test_get_extent.py
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
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():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is such a common requirement, I'm tempted to ask to to expose a context manager which has the following syntax:

with assert_warns(UserWarning):
    ax.get_extent()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# 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()
2 changes: 1 addition & 1 deletion lib/cartopy/tests/mpl/test_mpl_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just don't agree that this is preferable. 95% of the time, the user will want to define the extent of their map in "lons and lats" not in the native coordinate system.


ax = plt.subplot(224, projection=rp)
plt.pcolormesh(xbnds, ybnds, data, transform=rp, cmap='Set1')
Expand Down
37 changes: 35 additions & 2 deletions lib/cartopy/tests/mpl/test_set_extent.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down Expand Up @@ -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
Expand Down