Note
Go to the end to download the full example code.
Ocean bathymetry#
Produces a map of ocean seafloor depth, demonstrating the
cartopy.io.shapereader.Reader
interface. The data is a series
of 10m resolution nested polygons obtained from Natural Earth, 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.
![ocean bathymetry](../../_images/sphx_glr_ocean_bathymetry_001.png)
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_str, 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
depths = depths_str.astype(int)
N = len(depths)
nudge = 0.01 # shift bin edge slightly to include data
boundaries = [min(depths)] + sorted(depths+nudge) # low to high
norm = matplotlib.colors.BoundaryNorm(boundaries, N)
blues_cm = matplotlib.colormaps['Blues_r'].resampled(N)
colors_depths = blues_cm(norm(depths))
# 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_str in enumerate(depths_str):
ax.add_geometries(shp_dict[depth_str].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,
spacing='proportional',
extend='min',
ticks=depths,
label='Depth (m)')
# Convert vector bathymetries to raster (saves a lot of disk space)
# while leaving labels as vectors
ax.set_rasterized(True)
Total running time of the script: (0 minutes 20.504 seconds)