Spaces:
Sleeping
Sleeping
Update ash_animator/basemaps.py
Browse files- ash_animator/basemaps.py +15 -45
ash_animator/basemaps.py
CHANGED
|
@@ -1,70 +1,53 @@
|
|
| 1 |
-
|
| 2 |
import os
|
| 3 |
import hashlib
|
| 4 |
from PIL import Image
|
| 5 |
import matplotlib.pyplot as plt
|
| 6 |
-
|
| 7 |
-
import
|
| 8 |
-
import
|
|
|
|
| 9 |
|
| 10 |
def get_cache_dir(app_name):
|
| 11 |
if os.name == 'nt':
|
| 12 |
-
# Windows: Use LOCALAPPDATA or fallback
|
| 13 |
return os.path.join(os.getenv('LOCALAPPDATA', os.getcwd()), f"{app_name}_cache")
|
| 14 |
else:
|
| 15 |
-
# Unix:
|
| 16 |
base_dir = "/code"
|
| 17 |
cache_path = os.path.join(base_dir, f"{app_name}_cache")
|
| 18 |
try:
|
| 19 |
os.makedirs(cache_path, exist_ok=True)
|
| 20 |
-
os.chmod(cache_path, 0o777)
|
| 21 |
except PermissionError:
|
| 22 |
print(f"[PermissionError] Cannot write to {cache_path}. Falling back to /tmp.")
|
| 23 |
cache_path = os.path.join("/tmp", f"{app_name}_cache")
|
| 24 |
os.makedirs(cache_path, exist_ok=True)
|
| 25 |
return cache_path
|
| 26 |
|
|
|
|
| 27 |
CTX_TILE_CACHE_DIR = get_cache_dir("contextily")
|
| 28 |
BASEMAP_TILE_CACHE_DIR = get_cache_dir("basemap")
|
| 29 |
CARTOPY_CACHE_DIR = get_cache_dir("cartopy")
|
| 30 |
|
|
|
|
| 31 |
os.environ["CARTOPY_USER_BACKGROUNDS"] = CARTOPY_CACHE_DIR
|
| 32 |
os.environ["CARTOPY_CACHE_DIR"] = CARTOPY_CACHE_DIR
|
| 33 |
|
| 34 |
-
|
| 35 |
os.makedirs(CTX_TILE_CACHE_DIR, exist_ok=True)
|
| 36 |
os.makedirs(BASEMAP_TILE_CACHE_DIR, exist_ok=True)
|
| 37 |
|
| 38 |
-
|
| 39 |
-
import contextily as ctx
|
| 40 |
-
from mpl_toolkits.basemap import Basemap
|
| 41 |
-
import cartopy.crs as ccrs
|
| 42 |
-
import cartopy.feature as cfeature
|
| 43 |
-
|
| 44 |
def draw_etopo_basemap(ax, mode="basemap", zoom=11):
|
| 45 |
"""
|
| 46 |
Draws a high-resolution basemap background on the provided Cartopy GeoAxes.
|
| 47 |
-
|
| 48 |
Parameters
|
| 49 |
----------
|
| 50 |
ax : matplotlib.axes._subplots.AxesSubplot
|
| 51 |
The matplotlib Axes object (with Cartopy projection) to draw the map background on.
|
| 52 |
-
|
| 53 |
mode : str, optional
|
| 54 |
-
The basemap mode to use:
|
| 55 |
-
- "stock": Default stock image from Cartopy.
|
| 56 |
-
- "contextily": Web tile background (CartoDB Voyager), with caching.
|
| 57 |
-
- "basemap": High-resolution shaded relief using Basemap, with caching.
|
| 58 |
-
Default is "basemap".
|
| 59 |
-
|
| 60 |
zoom : int, optional
|
| 61 |
-
Tile zoom level
|
| 62 |
-
|
| 63 |
-
Notes
|
| 64 |
-
-----
|
| 65 |
-
- Uses high resolution for Basemap (resolution='h') and saves figure at 300 DPI.
|
| 66 |
-
- Cached images are reused using extent-based hashing to avoid re-rendering.
|
| 67 |
-
- Basemap is deprecated; Cartopy with web tiles is recommended for new projects.
|
| 68 |
"""
|
| 69 |
try:
|
| 70 |
if mode == "stock":
|
|
@@ -73,17 +56,11 @@ def draw_etopo_basemap(ax, mode="basemap", zoom=11):
|
|
| 73 |
elif mode == "contextily":
|
| 74 |
extent = ax.get_extent(crs=ccrs.PlateCarree())
|
| 75 |
ax.set_extent(extent, crs=ccrs.PlateCarree())
|
| 76 |
-
ctx.add_basemap(
|
| 77 |
-
|
| 78 |
-
crs=ccrs.PlateCarree(),
|
| 79 |
-
source=ctx.providers.CartoDB.Voyager,
|
| 80 |
-
zoom=zoom
|
| 81 |
-
)
|
| 82 |
|
| 83 |
elif mode == "basemap":
|
| 84 |
extent = ax.get_extent(crs=ccrs.PlateCarree())
|
| 85 |
-
|
| 86 |
-
# Create a hash key for this extent
|
| 87 |
extent_str = f"{extent[0]:.4f}_{extent[1]:.4f}_{extent[2]:.4f}_{extent[3]:.4f}"
|
| 88 |
cache_key = hashlib.md5(extent_str.encode()).hexdigest()
|
| 89 |
cache_file = os.path.join(BASEMAP_TILE_CACHE_DIR, f"{cache_key}_highres.png")
|
|
@@ -92,7 +69,6 @@ def draw_etopo_basemap(ax, mode="basemap", zoom=11):
|
|
| 92 |
img = Image.open(cache_file)
|
| 93 |
ax.imshow(img, extent=extent, transform=ccrs.PlateCarree())
|
| 94 |
else:
|
| 95 |
-
# Create a high-resolution temporary figure
|
| 96 |
temp_fig, temp_ax = plt.subplots(figsize=(12, 9),
|
| 97 |
subplot_kw={'projection': ccrs.PlateCarree()})
|
| 98 |
temp_ax.set_extent(extent, crs=ccrs.PlateCarree())
|
|
@@ -100,18 +76,12 @@ def draw_etopo_basemap(ax, mode="basemap", zoom=11):
|
|
| 100 |
m = Basemap(projection='cyl',
|
| 101 |
llcrnrlon=extent[0], urcrnrlon=extent[1],
|
| 102 |
llcrnrlat=extent[2], urcrnrlat=extent[3],
|
| 103 |
-
resolution='f', ax=temp_ax)
|
| 104 |
|
| 105 |
m.shadedrelief()
|
| 106 |
-
# m.drawcoastlines(linewidth=0.1)
|
| 107 |
-
# m.drawcountries(linewidth=0.1)
|
| 108 |
-
# m.drawmapboundary()
|
| 109 |
-
|
| 110 |
-
# Save high-DPI figure for clarity
|
| 111 |
temp_fig.savefig(cache_file, dpi=300, bbox_inches='tight', pad_inches=0)
|
| 112 |
plt.close(temp_fig)
|
| 113 |
|
| 114 |
-
# Load and display the cached image
|
| 115 |
img = Image.open(cache_file)
|
| 116 |
ax.imshow(img, extent=extent, transform=ccrs.PlateCarree())
|
| 117 |
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
import hashlib
|
| 3 |
from PIL import Image
|
| 4 |
import matplotlib.pyplot as plt
|
| 5 |
+
import contextily as ctx
|
| 6 |
+
from mpl_toolkits.basemap import Basemap
|
| 7 |
+
import cartopy.crs as ccrs
|
| 8 |
+
import cartopy.feature as cfeature
|
| 9 |
|
| 10 |
def get_cache_dir(app_name):
|
| 11 |
if os.name == 'nt':
|
| 12 |
+
# Windows: Use LOCALAPPDATA or fallback to cwd
|
| 13 |
return os.path.join(os.getenv('LOCALAPPDATA', os.getcwd()), f"{app_name}_cache")
|
| 14 |
else:
|
| 15 |
+
# Unix: Try /code/app_name_cache, fallback to /tmp
|
| 16 |
base_dir = "/code"
|
| 17 |
cache_path = os.path.join(base_dir, f"{app_name}_cache")
|
| 18 |
try:
|
| 19 |
os.makedirs(cache_path, exist_ok=True)
|
| 20 |
+
os.chmod(cache_path, 0o777)
|
| 21 |
except PermissionError:
|
| 22 |
print(f"[PermissionError] Cannot write to {cache_path}. Falling back to /tmp.")
|
| 23 |
cache_path = os.path.join("/tmp", f"{app_name}_cache")
|
| 24 |
os.makedirs(cache_path, exist_ok=True)
|
| 25 |
return cache_path
|
| 26 |
|
| 27 |
+
# Define cache dirs
|
| 28 |
CTX_TILE_CACHE_DIR = get_cache_dir("contextily")
|
| 29 |
BASEMAP_TILE_CACHE_DIR = get_cache_dir("basemap")
|
| 30 |
CARTOPY_CACHE_DIR = get_cache_dir("cartopy")
|
| 31 |
|
| 32 |
+
# Set environment variables for Cartopy
|
| 33 |
os.environ["CARTOPY_USER_BACKGROUNDS"] = CARTOPY_CACHE_DIR
|
| 34 |
os.environ["CARTOPY_CACHE_DIR"] = CARTOPY_CACHE_DIR
|
| 35 |
|
| 36 |
+
# Ensure cache dirs exist
|
| 37 |
os.makedirs(CTX_TILE_CACHE_DIR, exist_ok=True)
|
| 38 |
os.makedirs(BASEMAP_TILE_CACHE_DIR, exist_ok=True)
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
def draw_etopo_basemap(ax, mode="basemap", zoom=11):
|
| 41 |
"""
|
| 42 |
Draws a high-resolution basemap background on the provided Cartopy GeoAxes.
|
|
|
|
| 43 |
Parameters
|
| 44 |
----------
|
| 45 |
ax : matplotlib.axes._subplots.AxesSubplot
|
| 46 |
The matplotlib Axes object (with Cartopy projection) to draw the map background on.
|
|
|
|
| 47 |
mode : str, optional
|
| 48 |
+
The basemap mode to use: "stock", "contextily", "basemap".
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
zoom : int, optional
|
| 50 |
+
Tile zoom level for contextily.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
"""
|
| 52 |
try:
|
| 53 |
if mode == "stock":
|
|
|
|
| 56 |
elif mode == "contextily":
|
| 57 |
extent = ax.get_extent(crs=ccrs.PlateCarree())
|
| 58 |
ax.set_extent(extent, crs=ccrs.PlateCarree())
|
| 59 |
+
ctx.add_basemap(ax, crs=ccrs.PlateCarree(),
|
| 60 |
+
source=ctx.providers.CartoDB.Voyager, zoom=zoom)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
elif mode == "basemap":
|
| 63 |
extent = ax.get_extent(crs=ccrs.PlateCarree())
|
|
|
|
|
|
|
| 64 |
extent_str = f"{extent[0]:.4f}_{extent[1]:.4f}_{extent[2]:.4f}_{extent[3]:.4f}"
|
| 65 |
cache_key = hashlib.md5(extent_str.encode()).hexdigest()
|
| 66 |
cache_file = os.path.join(BASEMAP_TILE_CACHE_DIR, f"{cache_key}_highres.png")
|
|
|
|
| 69 |
img = Image.open(cache_file)
|
| 70 |
ax.imshow(img, extent=extent, transform=ccrs.PlateCarree())
|
| 71 |
else:
|
|
|
|
| 72 |
temp_fig, temp_ax = plt.subplots(figsize=(12, 9),
|
| 73 |
subplot_kw={'projection': ccrs.PlateCarree()})
|
| 74 |
temp_ax.set_extent(extent, crs=ccrs.PlateCarree())
|
|
|
|
| 76 |
m = Basemap(projection='cyl',
|
| 77 |
llcrnrlon=extent[0], urcrnrlon=extent[1],
|
| 78 |
llcrnrlat=extent[2], urcrnrlat=extent[3],
|
| 79 |
+
resolution='f', ax=temp_ax)
|
| 80 |
|
| 81 |
m.shadedrelief()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
temp_fig.savefig(cache_file, dpi=300, bbox_inches='tight', pad_inches=0)
|
| 83 |
plt.close(temp_fig)
|
| 84 |
|
|
|
|
| 85 |
img = Image.open(cache_file)
|
| 86 |
ax.imshow(img, extent=extent, transform=ccrs.PlateCarree())
|
| 87 |
|