File size: 5,177 Bytes
f0bfd2d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# import contextily as ctx
# from mpl_toolkits.basemap import Basemap
# import cartopy.crs as ccrs
# import cartopy.feature as cfeature
# def draw_etopo_basemap(ax, mode="basemap", zoom=7):
# try:
# if mode == "stock":
# ax.stock_img()
# elif mode == "contextily":
# extent = ax.get_extent(ccrs.PlateCarree())
# ax.set_extent(extent, crs=ccrs.PlateCarree())
# ctx.add_basemap(ax, crs=ccrs.PlateCarree(), source=ctx.providers.CartoDB.Voyager, zoom=zoom)
# elif mode == "basemap":
# extent = ax.get_extent(ccrs.PlateCarree())
# m = Basemap(projection='cyl',
# llcrnrlon=extent[0], urcrnrlon=extent[1],
# llcrnrlat=extent[2], urcrnrlat=extent[3],
# resolution='h', ax=ax)
# m.shadedrelief()
# m.drawcoastlines(linewidth=0.5)
# m.drawcountries(linewidth=0.7)
# m.drawmapboundary()
# else:
# raise ValueError(f"Unsupported basemap mode: {mode}")
# except Exception as e:
# print(f"[Relief Error - {mode} mode]:", e)
# ax.add_feature(cfeature.LAND)
# ax.add_feature(cfeature.OCEAN)
import os
import hashlib
import contextily as ctx
from mpl_toolkits.basemap import Basemap
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from PIL import Image
import matplotlib.pyplot as plt
# Define cache directories
# Optional: Set tile cache directory (must be done before contextily downloads tiles)
os.environ["XDG_CACHE_HOME"] = os.path.expanduser("~/.contextily_cache")
CTX_TILE_CACHE_DIR = os.path.expanduser("~/.contextily_cache")
BASEMAP_TILE_CACHE_DIR = os.path.expanduser("~/.basemap_cache")
os.makedirs(CTX_TILE_CACHE_DIR, exist_ok=True)
os.makedirs(BASEMAP_TILE_CACHE_DIR, exist_ok=True)
def draw_etopo_basemap(ax, mode="basemap", zoom=11):
"""
Draws a high-resolution basemap background on the provided Cartopy GeoAxes.
Parameters
----------
ax : matplotlib.axes._subplots.AxesSubplot
The matplotlib Axes object (with Cartopy projection) to draw the map background on.
mode : str, optional
The basemap mode to use:
- "stock": Default stock image from Cartopy.
- "contextily": Web tile background (CartoDB Voyager), with caching.
- "basemap": High-resolution shaded relief using Basemap, with caching.
Default is "basemap".
zoom : int, optional
Tile zoom level (only for "contextily"). Higher = more detail. Default is 7.
Notes
-----
- Uses high resolution for Basemap (resolution='h') and saves figure at 300 DPI.
- Cached images are reused using extent-based hashing to avoid re-rendering.
- Basemap is deprecated; Cartopy with web tiles is recommended for new projects.
"""
try:
if mode == "stock":
ax.stock_img()
elif mode == "contextily":
extent = ax.get_extent(crs=ccrs.PlateCarree())
ax.set_extent(extent, crs=ccrs.PlateCarree())
ctx.add_basemap(
ax,
crs=ccrs.PlateCarree(),
source=ctx.providers.CartoDB.Voyager,
zoom=zoom
)
elif mode == "basemap":
extent = ax.get_extent(crs=ccrs.PlateCarree())
# Create a hash key for this extent
extent_str = f"{extent[0]:.4f}_{extent[1]:.4f}_{extent[2]:.4f}_{extent[3]:.4f}"
cache_key = hashlib.md5(extent_str.encode()).hexdigest()
cache_file = os.path.join(BASEMAP_TILE_CACHE_DIR, f"{cache_key}_highres.png")
if os.path.exists(cache_file):
img = Image.open(cache_file)
ax.imshow(img, extent=extent, transform=ccrs.PlateCarree())
else:
# Create a high-resolution temporary figure
temp_fig, temp_ax = plt.subplots(figsize=(12, 9),
subplot_kw={'projection': ccrs.PlateCarree()})
temp_ax.set_extent(extent, crs=ccrs.PlateCarree())
m = Basemap(projection='cyl',
llcrnrlon=extent[0], urcrnrlon=extent[1],
llcrnrlat=extent[2], urcrnrlat=extent[3],
resolution='f', ax=temp_ax) # 'h' = high resolution
m.shadedrelief()
# m.drawcoastlines(linewidth=0.1)
# m.drawcountries(linewidth=0.1)
# m.drawmapboundary()
# Save high-DPI figure for clarity
temp_fig.savefig(cache_file, dpi=300, bbox_inches='tight', pad_inches=0)
plt.close(temp_fig)
# Load and display the cached image
img = Image.open(cache_file)
ax.imshow(img, extent=extent, transform=ccrs.PlateCarree())
else:
raise ValueError(f"Unsupported basemap mode: {mode}")
except Exception as e:
print(f"[Relief Error - {mode} mode]:", e)
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.OCEAN)
|