Skip to content

Commit

Permalink
Allow version specific NE
Browse files Browse the repository at this point in the history
  • Loading branch information
lgolston committed Oct 26, 2024
1 parent 1a36e4e commit d3e8f7e
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 15 deletions.
16 changes: 11 additions & 5 deletions lib/cartopy/feature/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,13 @@ class NaturalEarthFeature(Feature):
"""
A simple interface to Natural Earth shapefiles.
See https://www.naturalearthdata.com/
See https://www.naturalearthdata.com/ for an overview of the data
and https://github.com/nvkelso/natural-earth-vector/releases for recent
version information.
"""

def __init__(self, category, name, scale, **kwargs):
def __init__(self, category, name, scale, version=None, **kwargs):
"""
Parameters
----------
Expand All @@ -251,6 +253,8 @@ def __init__(self, category, name, scale, **kwargs):
The dataset scale, i.e. one of '10m', '50m', or '110m',
or Scaler object. Dataset scales correspond to 1:10,000,000,
1:50,000,000, and 1:110,000,000 respectively.
version: optional
The specific dataset version to use, e.g. '5.1.0'.
Other Parameters
----------------
Expand All @@ -261,6 +265,7 @@ def __init__(self, category, name, scale, **kwargs):
super().__init__(cartopy.crs.PlateCarree(), **kwargs)
self.category = category
self.name = name
self.version = version

# Cast the given scale to a (constant) Scaler if a string is passed.
if isinstance(scale, str):
Expand All @@ -286,11 +291,12 @@ def geometries(self):
Returns an iterator of (shapely) geometries for this feature.
"""
key = (self.name, self.category, self.scale)
key = (self.name, self.category, self.scale, self.version)
if key not in _NATURAL_EARTH_GEOM_CACHE:
path = shapereader.natural_earth(resolution=self.scale,
category=self.category,
name=self.name)
name=self.name,
version=self.version)
geometries = tuple(shapereader.Reader(path).geometries())
_NATURAL_EARTH_GEOM_CACHE[key] = geometries
else:
Expand Down Expand Up @@ -321,7 +327,7 @@ def with_scale(self, new_scale):
"""
return NaturalEarthFeature(self.category, self.name, new_scale,
**self.kwargs)
self.version, **self.kwargs)


class GSHHSFeature(Feature):
Expand Down
17 changes: 10 additions & 7 deletions lib/cartopy/io/shapereader.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,12 @@ def records(self):
"""


def natural_earth(resolution='110m', category='physical', name='coastline'):
def natural_earth(resolution='110m', category='physical',
name='coastline', version=None):
"""
Return the path to the requested natural earth shapefile,
downloading and unzipping if necessary.
downloading and unzipping if necessary. If version is not specified,
the latest available version will be downloaded.
To identify valid components for this function, either browse
NaturalEarthData.com, or if you know what you are looking for, go to
Expand All @@ -299,10 +301,11 @@ def natural_earth(resolution='110m', category='physical', name='coastline'):
# get hold of the Downloader (typically a NEShpDownloader instance)
# which we can then simply call its path method to get the appropriate
# shapefile (it will download if necessary)
_version_string = "" if version is None else f"{version}/"
ne_downloader = Downloader.from_config(('shapefiles', 'natural_earth',
resolution, category, name))
format_dict = {'config': config, 'category': category,
'name': name, 'resolution': resolution}
resolution, category, name))
format_dict = {'config': config, 'category': category, 'name': name,
'resolution': resolution, 'version': _version_string}
return ne_downloader.path(format_dict)


Expand All @@ -321,7 +324,7 @@ class NEShpDownloader(Downloader):
# Define the NaturalEarth URL template. Shapefiles are hosted on AWS since
# 2021: https://github.com/nvkelso/natural-earth-vector/issues/445
_NE_URL_TEMPLATE = ('https://naturalearth.s3.amazonaws.com/'
'{resolution}_{category}/ne_{resolution}_{name}.zip')
'{version}{resolution}_{category}/ne_{resolution}_{name}.zip')

def __init__(self,
url_template=_NE_URL_TEMPLATE,
Expand Down Expand Up @@ -386,7 +389,7 @@ def default_downloader():
ne_{resolution}_{name}.shp
"""
default_spec = ('shapefiles', 'natural_earth', '{category}',
default_spec = ('shapefiles', 'natural_earth', '{category}', '{version}',
'ne_{resolution}_{name}.shp')
ne_path_template = str(
Path('{config[data_dir]}').joinpath(*default_spec))
Expand Down
3 changes: 2 additions & 1 deletion lib/cartopy/tests/io/test_downloaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ def test_natural_earth_downloader(tmp_path):
# isn't important - it is the download mechanism that is.
format_dict = {'category': 'physical',
'name': 'rivers_lake_centerlines',
'resolution': '110m'}
'resolution': '110m',
'version': ''}

dnld_item = NEShpDownloader(target_path_template=shp_path_template)

Expand Down
2 changes: 1 addition & 1 deletion lib/cartopy/tests/mpl/test_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_natural_earth():
@pytest.mark.mpl_image_compare(filename='natural_earth_custom.png')
def test_natural_earth_custom():
ax = plt.axes(projection=ccrs.PlateCarree())
feature = cfeature.NaturalEarthFeature('physical', 'coastline', '50m',
feature = cfeature.NaturalEarthFeature('physical', 'coastline', '50m', '5.1.0',
edgecolor='black',
facecolor='none')
ax.add_feature(feature)
Expand Down
3 changes: 2 additions & 1 deletion lib/cartopy/tests/test_shapereader.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ class TestRivers:
def setup_class(self):
RIVERS_PATH = shp.natural_earth(resolution='110m',
category='physical',
name='rivers_lake_centerlines')
name='rivers_lake_centerlines',
version='5.0.0')
self.reader = shp.Reader(RIVERS_PATH)
names = [record.attributes['name'] for record in self.reader.records()]
# Choose a nice small river
Expand Down

0 comments on commit d3e8f7e

Please sign in to comment.