Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
###
|
| 2 |
|
| 3 |
import gradio as gr
|
| 4 |
import pandas as pd
|
|
@@ -37,10 +37,45 @@ DEFAULT_LAT, DEFAULT_LON = 49.6116, 6.1319
|
|
| 37 |
# --- UTILS ---
|
| 38 |
|
| 39 |
def compute_bbox(lat, lon, dist_km):
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
|
| 46 |
def get_peaks_from_overpass(lat, lon, dist_km):
|
|
@@ -63,28 +98,56 @@ def get_peaks_from_overpass(lat, lon, dist_km):
|
|
| 63 |
return pd.DataFrame()
|
| 64 |
|
| 65 |
peaks = {"name": [], "latitude": [], "longitude": [], "altitude": []}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
for e in data.get("elements", []):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
lat_e, lon_e = e.get("lat"), e.get("lon")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
tags = e.get("tags", {})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
peaks["latitude"].append(lat_e)
|
| 70 |
peaks["longitude"].append(lon_e)
|
| 71 |
peaks["name"].append(tags.get("name", "Unnamed Peak/Hill"))
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
peaks["altitude"].append(alt if alt is not None else 0)
|
| 80 |
-
except Exception:
|
| 81 |
-
peaks["altitude"].append(0)
|
| 82 |
|
| 83 |
if not peaks["latitude"]:
|
| 84 |
return pd.DataFrame()
|
| 85 |
|
| 86 |
df = pd.DataFrame(peaks)
|
| 87 |
df["altitude"] = df["altitude"].round(0).astype(int)
|
|
|
|
| 88 |
df["distance_m"] = df.apply(
|
| 89 |
lambda r: distance.distance((r["latitude"], r["longitude"]), (lat, lon)).m, axis=1
|
| 90 |
)
|
|
@@ -115,21 +178,15 @@ def get_weather_for_peaks_iteratively(df_peaks, min_snow_cm, max_results=20, max
|
|
| 115 |
}
|
| 116 |
|
| 117 |
try:
|
| 118 |
-
# FIX: Get the list of responses and access the first one
|
| 119 |
responses = openmeteo.weather_api(url, params=params)
|
| 120 |
-
if not responses:
|
| 121 |
continue
|
| 122 |
-
response = responses[0]
|
| 123 |
|
| 124 |
-
# Now proceed with your existing processing
|
| 125 |
hourly = response.Hourly()
|
| 126 |
if hourly is None:
|
| 127 |
continue
|
| 128 |
|
| 129 |
-
#times = hourly.Time()
|
| 130 |
-
#now_utc = datetime.now(timezone.utc)
|
| 131 |
-
#times_utc = datetime.fromtimestamp(times, tz=timezone.utc)
|
| 132 |
-
#idx = int(np.argmin([abs((t - now_utc).total_seconds()) for t in times_utc]))
|
| 133 |
idx = 0
|
| 134 |
|
| 135 |
temp_c = float(hourly.Variables(0).ValuesAsNumpy()[idx])
|
|
@@ -149,7 +206,7 @@ def get_weather_for_peaks_iteratively(df_peaks, min_snow_cm, max_results=20, max
|
|
| 149 |
})
|
| 150 |
|
| 151 |
except Exception as e:
|
| 152 |
-
print(f"Error fetching weather for {row['name']}: {e}")
|
| 153 |
|
| 154 |
requests_made += 1
|
| 155 |
|
|
@@ -166,9 +223,13 @@ def format_weather_data(df):
|
|
| 166 |
code = str(int(row["weather_code"]))
|
| 167 |
tod = "day" if row["is_day"] == 1 else "night"
|
| 168 |
info = icons.get(code, {}).get(tod, {})
|
| 169 |
-
|
|
|
|
|
|
|
| 170 |
|
| 171 |
-
df[["
|
|
|
|
|
|
|
| 172 |
df["distance_km"] = (df["distance_m"] / 1000).round(1)
|
| 173 |
df["temp_c_str"] = df["temp_c"].round(0).astype(int).astype(str) + "°C"
|
| 174 |
return df
|
|
@@ -238,7 +299,7 @@ def create_map_with_center(lat, lon):
|
|
| 238 |
lon=[lon],
|
| 239 |
mode="markers",
|
| 240 |
marker=dict(size=24, color="white", opacity=0.8),
|
| 241 |
-
hoverinfo=
|
| 242 |
)
|
| 243 |
)
|
| 244 |
fig.add_trace(
|
|
@@ -246,7 +307,7 @@ def create_map_with_center(lat, lon):
|
|
| 246 |
lat=[lat],
|
| 247 |
lon=[lon],
|
| 248 |
mode="markers",
|
| 249 |
-
marker=dict(size=12, color="
|
| 250 |
text=["Search Center"],
|
| 251 |
hoverinfo="text",
|
| 252 |
)
|
|
@@ -262,23 +323,28 @@ def create_map_with_center(lat, lon):
|
|
| 262 |
|
| 263 |
def create_map_with_results(lat, lon, df_final):
|
| 264 |
fig = go.Figure()
|
|
|
|
|
|
|
| 265 |
fig.add_trace(
|
| 266 |
go.Scattermap(
|
| 267 |
lat=df_final["latitude"],
|
| 268 |
lon=df_final["longitude"],
|
| 269 |
mode="markers",
|
| 270 |
marker=dict(size=24, color="white", opacity=0.8),
|
| 271 |
-
hoverinfo=
|
| 272 |
)
|
| 273 |
)
|
|
|
|
|
|
|
| 274 |
fig.add_trace(
|
| 275 |
go.Scattermap(
|
| 276 |
lat=df_final["latitude"],
|
| 277 |
lon=df_final["longitude"],
|
| 278 |
mode="markers",
|
| 279 |
-
marker=dict(size=12, color="
|
| 280 |
customdata=df_final[
|
| 281 |
-
["name", "altitude", "distance_km", "snow_depth_cm", "weather_desc",
|
|
|
|
| 282 |
],
|
| 283 |
hovertemplate=(
|
| 284 |
"<b>%{customdata[0]}</b><br>"
|
|
@@ -290,13 +356,15 @@ def create_map_with_results(lat, lon, df_final):
|
|
| 290 |
),
|
| 291 |
)
|
| 292 |
)
|
|
|
|
|
|
|
| 293 |
fig.add_trace(
|
| 294 |
go.Scattermap(
|
| 295 |
lat=[lat],
|
| 296 |
lon=[lon],
|
| 297 |
mode="markers",
|
| 298 |
marker=dict(size=24, color="white", opacity=0.8),
|
| 299 |
-
hoverinfo=
|
| 300 |
)
|
| 301 |
)
|
| 302 |
fig.add_trace(
|
|
@@ -304,11 +372,12 @@ def create_map_with_results(lat, lon, df_final):
|
|
| 304 |
lat=[lat],
|
| 305 |
lon=[lon],
|
| 306 |
mode="markers",
|
| 307 |
-
marker=dict(size=12, color="
|
| 308 |
text=["Search Center"],
|
| 309 |
hoverinfo="text",
|
| 310 |
)
|
| 311 |
)
|
|
|
|
| 312 |
fig.update_layout(
|
| 313 |
map=dict(style="open-street-map", center={"lat": lat, "lon": lon}, zoom=9),
|
| 314 |
margin={"r": 0, "t": 40, "l": 0, "b": 0},
|
|
|
|
| 1 |
+
### app_fixed.py ###
|
| 2 |
|
| 3 |
import gradio as gr
|
| 4 |
import pandas as pd
|
|
|
|
| 37 |
# --- UTILS ---
|
| 38 |
|
| 39 |
def compute_bbox(lat, lon, dist_km):
|
| 40 |
+
"""Compute bounding box more reliably for any location."""
|
| 41 |
+
# Convert km to degrees (rough approximation)
|
| 42 |
+
# At equator: 1 degree ≈ 111 km
|
| 43 |
+
lat_delta = dist_km / 111.0
|
| 44 |
+
lon_delta = dist_km / (111.0 * np.cos(np.radians(lat)))
|
| 45 |
+
|
| 46 |
+
south = lat - lat_delta
|
| 47 |
+
north = lat + lat_delta
|
| 48 |
+
west = lon - lon_delta
|
| 49 |
+
east = lon + lon_delta
|
| 50 |
+
|
| 51 |
+
# Ensure longitude wraps properly
|
| 52 |
+
if west < -180:
|
| 53 |
+
west += 360
|
| 54 |
+
if east > 180:
|
| 55 |
+
east -= 360
|
| 56 |
+
|
| 57 |
+
# Ensure latitude stays in valid range
|
| 58 |
+
south = max(south, -90)
|
| 59 |
+
north = min(north, 90)
|
| 60 |
+
|
| 61 |
+
return f"{south},{west},{north},{east}"
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def get_elevation_from_srtm(lat, lon):
|
| 65 |
+
"""Get elevation from SRTM if within coverage area."""
|
| 66 |
+
if lat is None or lon is None:
|
| 67 |
+
return None
|
| 68 |
+
|
| 69 |
+
# SRTM coverage: 60°N to 56°S
|
| 70 |
+
if -56 <= lat <= 60:
|
| 71 |
+
try:
|
| 72 |
+
alt = elevation_data.get_elevation(lat, lon)
|
| 73 |
+
if alt is not None and alt > 0:
|
| 74 |
+
return alt
|
| 75 |
+
except Exception as ex:
|
| 76 |
+
print(f"SRTM error for {lat},{lon}: {ex}")
|
| 77 |
+
|
| 78 |
+
return None
|
| 79 |
|
| 80 |
|
| 81 |
def get_peaks_from_overpass(lat, lon, dist_km):
|
|
|
|
| 98 |
return pd.DataFrame()
|
| 99 |
|
| 100 |
peaks = {"name": [], "latitude": [], "longitude": [], "altitude": []}
|
| 101 |
+
skipped = 0
|
| 102 |
+
processed = 0
|
| 103 |
+
max_peaks = 100 # Limit processing to avoid slowdowns
|
| 104 |
+
|
| 105 |
for e in data.get("elements", []):
|
| 106 |
+
# Stop if we've processed enough peaks
|
| 107 |
+
if processed >= max_peaks:
|
| 108 |
+
break
|
| 109 |
+
|
| 110 |
lat_e, lon_e = e.get("lat"), e.get("lon")
|
| 111 |
+
|
| 112 |
+
# Skip elements without valid coordinates
|
| 113 |
+
if lat_e is None or lon_e is None:
|
| 114 |
+
skipped += 1
|
| 115 |
+
continue
|
| 116 |
+
|
| 117 |
tags = e.get("tags", {})
|
| 118 |
+
alt = None
|
| 119 |
+
|
| 120 |
+
# Strategy 1: Try to get elevation from OSM tag first
|
| 121 |
+
ele = tags.get("ele")
|
| 122 |
+
if ele and str(ele).replace(".", "").replace("-", "").isnumeric():
|
| 123 |
+
alt = float(ele)
|
| 124 |
+
|
| 125 |
+
# Strategy 2: If no OSM elevation, try SRTM as fallback
|
| 126 |
+
if alt is None or alt <= 10:
|
| 127 |
+
alt = get_elevation_from_srtm(lat_e, lon_e)
|
| 128 |
+
|
| 129 |
+
# Skip peaks if both strategies failed to produce valid elevation
|
| 130 |
+
if alt is None or alt <= 10:
|
| 131 |
+
skipped += 1
|
| 132 |
+
continue
|
| 133 |
+
|
| 134 |
peaks["latitude"].append(lat_e)
|
| 135 |
peaks["longitude"].append(lon_e)
|
| 136 |
peaks["name"].append(tags.get("name", "Unnamed Peak/Hill"))
|
| 137 |
+
peaks["altitude"].append(alt)
|
| 138 |
+
processed += 1
|
| 139 |
+
|
| 140 |
+
if skipped > 0:
|
| 141 |
+
print(f"Skipped {skipped} peaks without complete data (coordinates or elevation)")
|
| 142 |
+
if processed >= max_peaks:
|
| 143 |
+
print(f"Reached limit of {max_peaks} peaks processed")
|
|
|
|
|
|
|
|
|
|
| 144 |
|
| 145 |
if not peaks["latitude"]:
|
| 146 |
return pd.DataFrame()
|
| 147 |
|
| 148 |
df = pd.DataFrame(peaks)
|
| 149 |
df["altitude"] = df["altitude"].round(0).astype(int)
|
| 150 |
+
|
| 151 |
df["distance_m"] = df.apply(
|
| 152 |
lambda r: distance.distance((r["latitude"], r["longitude"]), (lat, lon)).m, axis=1
|
| 153 |
)
|
|
|
|
| 178 |
}
|
| 179 |
|
| 180 |
try:
|
|
|
|
| 181 |
responses = openmeteo.weather_api(url, params=params)
|
| 182 |
+
if not responses:
|
| 183 |
continue
|
| 184 |
+
response = responses[0]
|
| 185 |
|
|
|
|
| 186 |
hourly = response.Hourly()
|
| 187 |
if hourly is None:
|
| 188 |
continue
|
| 189 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
idx = 0
|
| 191 |
|
| 192 |
temp_c = float(hourly.Variables(0).ValuesAsNumpy()[idx])
|
|
|
|
| 206 |
})
|
| 207 |
|
| 208 |
except Exception as e:
|
| 209 |
+
print(f"Error fetching weather for {row['name']} at {row['latitude']},{row['longitude']}: {e}")
|
| 210 |
|
| 211 |
requests_made += 1
|
| 212 |
|
|
|
|
| 223 |
code = str(int(row["weather_code"]))
|
| 224 |
tod = "day" if row["is_day"] == 1 else "night"
|
| 225 |
info = icons.get(code, {}).get(tod, {})
|
| 226 |
+
icon_filename = info.get("icon", "")
|
| 227 |
+
description = info.get("description", "Unknown")
|
| 228 |
+
return ICON_URL + icon_filename, description, icon_filename
|
| 229 |
|
| 230 |
+
df[["weather_icon_url", "weather_desc", "weather_icon_name"]] = df.apply(
|
| 231 |
+
icon_mapper, axis=1, result_type="expand"
|
| 232 |
+
)
|
| 233 |
df["distance_km"] = (df["distance_m"] / 1000).round(1)
|
| 234 |
df["temp_c_str"] = df["temp_c"].round(0).astype(int).astype(str) + "°C"
|
| 235 |
return df
|
|
|
|
| 299 |
lon=[lon],
|
| 300 |
mode="markers",
|
| 301 |
marker=dict(size=24, color="white", opacity=0.8),
|
| 302 |
+
hoverinfo="skip",
|
| 303 |
)
|
| 304 |
)
|
| 305 |
fig.add_trace(
|
|
|
|
| 307 |
lat=[lat],
|
| 308 |
lon=[lon],
|
| 309 |
mode="markers",
|
| 310 |
+
marker=dict(size=12, color="red"),
|
| 311 |
text=["Search Center"],
|
| 312 |
hoverinfo="text",
|
| 313 |
)
|
|
|
|
| 323 |
|
| 324 |
def create_map_with_results(lat, lon, df_final):
|
| 325 |
fig = go.Figure()
|
| 326 |
+
|
| 327 |
+
# Add white halos for peaks
|
| 328 |
fig.add_trace(
|
| 329 |
go.Scattermap(
|
| 330 |
lat=df_final["latitude"],
|
| 331 |
lon=df_final["longitude"],
|
| 332 |
mode="markers",
|
| 333 |
marker=dict(size=24, color="white", opacity=0.8),
|
| 334 |
+
hoverinfo="skip",
|
| 335 |
)
|
| 336 |
)
|
| 337 |
+
|
| 338 |
+
# Add peak markers with weather info in hover (no HTML icons)
|
| 339 |
fig.add_trace(
|
| 340 |
go.Scattermap(
|
| 341 |
lat=df_final["latitude"],
|
| 342 |
lon=df_final["longitude"],
|
| 343 |
mode="markers",
|
| 344 |
+
marker=dict(size=12, color="blue"),
|
| 345 |
customdata=df_final[
|
| 346 |
+
["name", "altitude", "distance_km", "snow_depth_cm", "weather_desc",
|
| 347 |
+
"temp_c_str"]
|
| 348 |
],
|
| 349 |
hovertemplate=(
|
| 350 |
"<b>%{customdata[0]}</b><br>"
|
|
|
|
| 356 |
),
|
| 357 |
)
|
| 358 |
)
|
| 359 |
+
|
| 360 |
+
# Add search center with halo
|
| 361 |
fig.add_trace(
|
| 362 |
go.Scattermap(
|
| 363 |
lat=[lat],
|
| 364 |
lon=[lon],
|
| 365 |
mode="markers",
|
| 366 |
marker=dict(size=24, color="white", opacity=0.8),
|
| 367 |
+
hoverinfo="skip",
|
| 368 |
)
|
| 369 |
)
|
| 370 |
fig.add_trace(
|
|
|
|
| 372 |
lat=[lat],
|
| 373 |
lon=[lon],
|
| 374 |
mode="markers",
|
| 375 |
+
marker=dict(size=12, color="red"),
|
| 376 |
text=["Search Center"],
|
| 377 |
hoverinfo="text",
|
| 378 |
)
|
| 379 |
)
|
| 380 |
+
|
| 381 |
fig.update_layout(
|
| 382 |
map=dict(style="open-street-map", center={"lat": lat, "lon": lon}, zoom=9),
|
| 383 |
margin={"r": 0, "t": 40, "l": 0, "b": 0},
|