Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create ocean bathymetry example #2195

Merged
merged 7 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
96 changes: 96 additions & 0 deletions examples/lines_and_polygons/ocean_bathymetry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
Ocean bathymetry
----------------

Produces a map of ocean seafloor depth, demonstrating the
:class:`cartopy.io.shapereader.Reader` interface. The data is a series
of 10m resolution nested polygons obtained from Natural Earth, and derived
from the NASA SRTM Plus product. Since the dataset contains a zipfile with
multiple shapefiles representing different depths, the example demonstrates
manually downloading and reading them with the general shapereader interface,
instead of the specialized `cartopy.feature.NaturalEarthFeature` interface.

"""
from glob import glob

import matplotlib
import matplotlib.pyplot as plt
import numpy as np

import cartopy.crs as ccrs
import cartopy.feature as cfeature
import cartopy.io.shapereader as shpreader


def load_bathymetry(zip_file_url):
"""Read zip file from Natural Earth containing bathymetry shapefiles"""
# Download and extract shapefiles
import io
import zipfile

import requests
r = requests.get(zip_file_url)
z = zipfile.ZipFile(io.BytesIO(r.content))
z.extractall("ne_10m_bathymetry_all/")

# Read shapefiles, sorted by depth
shp_dict = {}
files = glob('ne_10m_bathymetry_all/*.shp')
assert len(files) > 0
files.sort()
depths = []
for f in files:
depth = '-' + f.split('_')[-1].split('.')[0] # depth from file name
depths.append(depth)
bbox = (90, -15, 160, 60) # (x0, y0, x1, y1)
nei = shpreader.Reader(f, bbox=bbox)
shp_dict[depth] = nei
depths = np.array(depths)[::-1] # sort from surface to bottom
return depths, shp_dict


if __name__ == "__main__":
# Load data (14.8 MB file)
depths, shp_dict = load_bathymetry(
'https://naturalearth.s3.amazonaws.com/' +
'10m_physical/ne_10m_bathymetry_all.zip')

# Construct a discrete colormap with colors corresponding to each depth
bounds = sorted(depths.astype(float)) # low to high
lgolston marked this conversation as resolved.
Show resolved Hide resolved
N = len(bounds)
norm = matplotlib.colors.BoundaryNorm(bounds, N)
blues_cm = matplotlib.colormaps['Blues_r'].resampled(N)
colors_depths = blues_cm(norm(depths.astype(float)))
lgolston marked this conversation as resolved.
Show resolved Hide resolved

# Set up plot
subplot_kw = {'projection': ccrs.LambertCylindrical()}
fig, ax = plt.subplots(subplot_kw=subplot_kw, figsize=(9, 7))
ax.set_extent([90, 160, -15, 60], crs=ccrs.PlateCarree()) # x0, x1, y0, y1

# Iterate and plot feature for each depth level
for i, depth in enumerate(depths):
ax.add_geometries(shp_dict[depth].geometries(),
crs=ccrs.PlateCarree(),
color=colors_depths[i])

# Add standard features
ax.add_feature(cfeature.LAND, color='grey')
ax.coastlines(lw=1, resolution='110m')
ax.gridlines(draw_labels=False)
ax.set_position([0.03, 0.05, 0.8, 0.9])

# Add custom colorbar
axi = fig.add_axes([0.85, 0.1, 0.025, 0.8])
ax.add_feature(cfeature.BORDERS, linestyle=':')
sm = plt.cm.ScalarMappable(cmap=blues_cm, norm=norm)
fig.colorbar(mappable=sm,
cax=axi,
boundaries=depths.astype(int)[::-1],
lgolston marked this conversation as resolved.
Show resolved Hide resolved
spacing='proportional',
extend='min',
ticks=depths.astype(int),
label='Depth (m)')

# Convert vector bathymetries to raster (saves a lot of disk space)
# while leaving labels as vectors
ax.set_rasterized(True)
2 changes: 1 addition & 1 deletion lib/cartopy/io/shapereader.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class BasicReader:

"""

def __init__(self, filename):
def __init__(self, filename, bbox=None):
# Validate the filename/shapefile
self._reader = reader = shapefile.Reader(filename)
if reader.shp is None or reader.shx is None or reader.dbf is None:
Expand Down
Loading