Update DEM and Slope
Browse files
app.py
CHANGED
|
@@ -177,45 +177,44 @@ def get_wayback_data():
|
|
| 177 |
|
| 178 |
# Parse XML
|
| 179 |
root = ET.fromstring(response.content)
|
|
|
|
| 180 |
ns = {
|
| 181 |
-
"wmts": "
|
| 182 |
-
"ows": "
|
| 183 |
-
"xlink": "
|
| 184 |
}
|
| 185 |
|
|
|
|
|
|
|
| 186 |
layers = root.findall(".//wmts:Contents/wmts:Layer", ns)
|
| 187 |
|
| 188 |
layer_data = []
|
| 189 |
for layer in layers:
|
| 190 |
-
|
| 191 |
-
|
|
|
|
| 192 |
|
| 193 |
-
|
| 194 |
-
if
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
title_text = title_element.text
|
| 198 |
-
url_template = resource_element.get("template")
|
| 199 |
|
| 200 |
layer_data.append({"Title": title_text, "ResourceURL_Template": url_template})
|
| 201 |
|
| 202 |
wayback_df = pd.DataFrame(layer_data)
|
| 203 |
-
|
| 204 |
-
if wayback_df.empty:
|
| 205 |
-
print("Warning: No valid Wayback layers were found in the XML data.")
|
| 206 |
-
return wayback_df
|
| 207 |
-
|
| 208 |
wayback_df["date"] = pd.to_datetime(wayback_df["Title"].str.extract(r"(\d{4}-\d{2}-\d{2})").squeeze(), errors="coerce")
|
| 209 |
-
# Drop rows where a date could not be parsed
|
| 210 |
-
wayback_df.dropna(subset=['date'], inplace=True)
|
| 211 |
-
|
| 212 |
wayback_df.set_index("date", inplace=True)
|
| 213 |
-
wayback_df.sort_index(ascending=False, inplace=True) # Sort with the latest first
|
| 214 |
return wayback_df
|
| 215 |
|
| 216 |
-
except
|
| 217 |
-
print(f"Could not fetch
|
| 218 |
-
return pd.DataFrame()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
|
| 220 |
def get_dem_slope_maps(ee_geometry, map_center, zoom=12, wayback_url=None, wayback_title=None):
|
| 221 |
"""Creates DEM and Slope maps from SRTM data, using wayback tiles as a basemap if available."""
|
|
@@ -363,12 +362,22 @@ def process_and_display(file_obj, url_str, buffer_m, progress=gr.Progress()):
|
|
| 363 |
return None, f"Error processing file: {e}", None, None, None, None, None
|
| 364 |
|
| 365 |
progress(0.5, desc="Generating maps and stats...")
|
| 366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
# --- Generate Maps ---
|
| 368 |
-
wayback_url, wayback_title = None, None
|
| 369 |
if not WAYBACK_DF.empty:
|
|
|
|
| 370 |
latest_item = WAYBACK_DF.iloc[0]
|
| 371 |
wayback_title = f"Esri Wayback ({latest_item.name.strftime('%Y-%m-%d')})"
|
|
|
|
| 372 |
wayback_url = (
|
| 373 |
latest_item["ResourceURL_Template"]
|
| 374 |
.replace("{TileMatrixSet}", "GoogleMapsCompatible")
|
|
@@ -376,25 +385,15 @@ def process_and_display(file_obj, url_str, buffer_m, progress=gr.Progress()):
|
|
| 376 |
.replace("{TileRow}", "{y}")
|
| 377 |
.replace("{TileCol}", "{x}")
|
| 378 |
)
|
| 379 |
-
|
| 380 |
-
# **NEW**: Calculate map center from the geometry's bounds
|
| 381 |
-
bounds = geometry_gdf.to_crs(epsg=4326).total_bounds
|
| 382 |
-
map_center = [(bounds[1] + bounds[3]) / 2, (bounds[0] + bounds[2]) / 2]
|
| 383 |
-
|
| 384 |
-
# **MODIFIED**: Pass map_center to the function
|
| 385 |
-
ee_geometry = ee.Geometry(json.loads(geometry_gdf.to_crs(4326).to_json())['features'][0]['geometry'])
|
| 386 |
-
dem_html, slope_html = get_dem_slope_maps(ee_geometry, map_center, wayback_url=wayback_url, wayback_title=wayback_title)
|
| 387 |
-
|
| 388 |
-
# Create main map with folium using the calculated center
|
| 389 |
-
m = folium.Map(location=map_center)
|
| 390 |
-
|
| 391 |
-
if wayback_url:
|
| 392 |
-
print("added wayback layer")
|
| 393 |
folium.TileLayer(tiles=wayback_url, attr="Esri", name=wayback_title).add_to(m)
|
| 394 |
-
|
| 395 |
-
m = add_geometry_to_map(m, geometry_gdf, buffer_geometry_gdf)
|
| 396 |
m.add_child(folium.LayerControl())
|
| 397 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
|
| 399 |
# ... (rest of the function remains the same) ...
|
| 400 |
stats_df = pd.DataFrame({
|
|
|
|
| 177 |
|
| 178 |
# Parse XML
|
| 179 |
root = ET.fromstring(response.content)
|
| 180 |
+
|
| 181 |
ns = {
|
| 182 |
+
"wmts": "https://www.opengis.net/wmts/1.0",
|
| 183 |
+
"ows": "https://www.opengis.net/ows/1.1",
|
| 184 |
+
"xlink": "https://www.w3.org/1999/xlink",
|
| 185 |
}
|
| 186 |
|
| 187 |
+
# Use a robust XPath to find all 'Layer' elements anywhere in the document.
|
| 188 |
+
# This is less brittle than specifying the full path.
|
| 189 |
layers = root.findall(".//wmts:Contents/wmts:Layer", ns)
|
| 190 |
|
| 191 |
layer_data = []
|
| 192 |
for layer in layers:
|
| 193 |
+
title = layer.find("ows:Title", ns)
|
| 194 |
+
identifier = layer.find("ows:Identifier", ns)
|
| 195 |
+
resource = layer.find("wmts:ResourceURL", ns) # Tile URL template
|
| 196 |
|
| 197 |
+
title_text = title.text if title is not None else "N/A"
|
| 198 |
+
identifier_text = identifier.text if identifier is not None else "N/A"
|
| 199 |
+
url_template = resource.get("template") if resource is not None else "N/A"
|
|
|
|
|
|
|
|
|
|
| 200 |
|
| 201 |
layer_data.append({"Title": title_text, "ResourceURL_Template": url_template})
|
| 202 |
|
| 203 |
wayback_df = pd.DataFrame(layer_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
wayback_df["date"] = pd.to_datetime(wayback_df["Title"].str.extract(r"(\d{4}-\d{2}-\d{2})").squeeze(), errors="coerce")
|
|
|
|
|
|
|
|
|
|
| 205 |
wayback_df.set_index("date", inplace=True)
|
|
|
|
| 206 |
return wayback_df
|
| 207 |
|
| 208 |
+
except requests.exceptions.RequestException as e:
|
| 209 |
+
print(f"Could not fetch Wayback data from URL: {e}")
|
| 210 |
+
return pd.DataFrame()
|
| 211 |
+
except ET.ParseError as e:
|
| 212 |
+
print(f"Could not parse Wayback XML data: {e}")
|
| 213 |
+
return pd.DataFrame()
|
| 214 |
+
except Exception as e:
|
| 215 |
+
print(f"An unexpected error occurred in get_wayback_data: {e}")
|
| 216 |
+
return pd.DataFrame()
|
| 217 |
+
|
| 218 |
|
| 219 |
def get_dem_slope_maps(ee_geometry, map_center, zoom=12, wayback_url=None, wayback_title=None):
|
| 220 |
"""Creates DEM and Slope maps from SRTM data, using wayback tiles as a basemap if available."""
|
|
|
|
| 362 |
return None, f"Error processing file: {e}", None, None, None, None, None
|
| 363 |
|
| 364 |
progress(0.5, desc="Generating maps and stats...")
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
# Pass map_center to the function
|
| 368 |
+
ee_geometry = ee.Geometry(json.loads(geometry_gdf.to_crs(4326).to_json())['features'][0]['geometry'])
|
| 369 |
+
dem_html, slope_html = get_dem_slope_maps(ee_geometry, map_center, wayback_url=wayback_url, wayback_title=wayback_title)
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
# Create main map with folium using the calculated center
|
| 373 |
+
m = folium.Map()
|
| 374 |
+
|
| 375 |
# --- Generate Maps ---
|
|
|
|
| 376 |
if not WAYBACK_DF.empty:
|
| 377 |
+
# Select the first row, which is the most recent date after sorting
|
| 378 |
latest_item = WAYBACK_DF.iloc[0]
|
| 379 |
wayback_title = f"Esri Wayback ({latest_item.name.strftime('%Y-%m-%d')})"
|
| 380 |
+
print(wayback_title)
|
| 381 |
wayback_url = (
|
| 382 |
latest_item["ResourceURL_Template"]
|
| 383 |
.replace("{TileMatrixSet}", "GoogleMapsCompatible")
|
|
|
|
| 385 |
.replace("{TileRow}", "{y}")
|
| 386 |
.replace("{TileCol}", "{x}")
|
| 387 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
folium.TileLayer(tiles=wayback_url, attr="Esri", name=wayback_title).add_to(m)
|
| 389 |
+
|
| 390 |
+
m = add_geometry_to_map(m, geometry_gdf, buffer_geometry_gdf, opacity=0.3)
|
| 391 |
m.add_child(folium.LayerControl())
|
| 392 |
+
|
| 393 |
+
# Fit the map view to the bounds of the geometry
|
| 394 |
+
bounds = geometry_gdf.to_crs(epsg=4326).total_bounds
|
| 395 |
+
map_bounds = [[bounds[1], bounds[0]], [bounds[3], bounds[2]]] # Format: [[south, west], [north, east]]
|
| 396 |
+
m.fit_bounds(map_bounds, padding=(10, 10))
|
| 397 |
|
| 398 |
# ... (rest of the function remains the same) ...
|
| 399 |
stats_df = pd.DataFrame({
|