Update app.py
Browse files
app.py
CHANGED
|
@@ -1296,101 +1296,60 @@ def locator_page():
|
|
| 1296 |
except Exception:
|
| 1297 |
pass
|
| 1298 |
|
| 1299 |
-
#
|
| 1300 |
-
#
|
| 1301 |
-
#
|
| 1302 |
-
|
| 1303 |
-
# ----------------------------
|
| 1304 |
-
# Show map with drawing tools
|
| 1305 |
-
# ----------------------------
|
| 1306 |
st.markdown("π Draw a polygon/rectangle on the map (use draw tool). After drawing, click **Compute Summaries**.")
|
| 1307 |
-
|
| 1308 |
-
# VITAL:
|
| 1309 |
map_data = m.to_streamlit(height=700, responsive=True)
|
| 1310 |
|
| 1311 |
-
#
|
| 1312 |
-
# geemap returns the last drawn feature in 'last_object'.
|
| 1313 |
if map_data and map_data.get("last_object"):
|
| 1314 |
st.session_state["roi_geojson"] = json.dumps(map_data["last_object"])
|
| 1315 |
|
| 1316 |
-
#
|
| 1317 |
-
|
| 1318 |
-
# The button click causes a rerun, but the ROI is now safely in session_state.
|
| 1319 |
-
st.session_state["compute_button"] = True
|
| 1320 |
-
|
| 1321 |
-
# Update the helper function to prioritize session_state
|
| 1322 |
-
def get_roi_from_map(m):
|
| 1323 |
-
# Prefer session_state (persists across reruns)
|
| 1324 |
if "roi_geojson" in st.session_state and st.session_state["roi_geojson"]:
|
| 1325 |
try:
|
| 1326 |
-
|
|
|
|
| 1327 |
feature = json.loads(st.session_state["roi_geojson"])
|
| 1328 |
-
|
| 1329 |
except (json.JSONDecodeError, KeyError, Exception) as e:
|
| 1330 |
-
st.warning(f"Could not parse stored ROI: {e}")
|
| 1331 |
-
|
| 1332 |
-
|
| 1333 |
-
|
| 1334 |
-
|
| 1335 |
-
return m.user_roi
|
| 1336 |
-
except Exception:
|
| 1337 |
-
return None
|
| 1338 |
-
return None
|
| 1339 |
|
| 1340 |
-
#
|
| 1341 |
-
if st.session_state.get("compute_button", False):
|
| 1342 |
-
roi = get_roi_from_map(m)
|
| 1343 |
-
if roi is None:
|
| 1344 |
-
st.error("No drawn ROI found. Please draw a polygon/rectangle and press Compute Summaries again.")
|
| 1345 |
-
# Reset button state to allow for another attempt
|
| 1346 |
-
st.session_state["compute_button"] = False
|
| 1347 |
-
return # Use return instead of st.stop() in this context
|
| 1348 |
-
|
| 1349 |
-
# ... the rest of your computation code follows here ...
|
| 1350 |
-
# (Make sure to reset the button state at the end of the computation block)
|
| 1351 |
-
# st.session_state["compute_button"] = False
|
| 1352 |
-
|
| 1353 |
-
# Button to compute summaries (we'll fetch ROI from map object)
|
| 1354 |
if "compute_button" not in st.session_state:
|
| 1355 |
-
|
|
|
|
|
|
|
| 1356 |
if st.button("Compute Summaries"):
|
| 1357 |
st.session_state["compute_button"] = True
|
| 1358 |
-
|
| 1359 |
-
# get ROI helper (try multiple attributes)
|
| 1360 |
-
'''def get_roi_from_map(m):
|
| 1361 |
-
# Prefer session_state (persists across reruns)
|
| 1362 |
-
if "roi_geojson" in st.session_state:
|
| 1363 |
-
try:
|
| 1364 |
-
return ee.Geometry(json.loads(st.session_state["roi_geojson"]))
|
| 1365 |
-
except Exception:
|
| 1366 |
-
pass'''
|
| 1367 |
-
|
| 1368 |
-
# fallback checks
|
| 1369 |
-
if hasattr(m, "user_roi") and m.user_roi:
|
| 1370 |
-
try:
|
| 1371 |
-
return ee.Geometry(m.user_roi.toGeoJSONString())
|
| 1372 |
-
except Exception:
|
| 1373 |
-
return None
|
| 1374 |
|
| 1375 |
-
|
| 1376 |
-
|
| 1377 |
-
# If user pressed compute, extract ROI and compute
|
| 1378 |
if st.session_state.get("compute_button", False):
|
| 1379 |
-
|
| 1380 |
-
|
| 1381 |
-
|
| 1382 |
-
|
| 1383 |
-
|
| 1384 |
-
|
| 1385 |
-
try:
|
| 1386 |
-
if not isinstance(roi, ee.Geometry):
|
| 1387 |
-
roi = ee.Geometry(roi)
|
| 1388 |
-
except Exception:
|
| 1389 |
-
st.error("Failed to parse ROI as Earth Engine geometry.")
|
| 1390 |
-
return
|
| 1391 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1392 |
st.success("Polygon found β computing (this may take a few seconds)...")
|
| 1393 |
|
|
|
|
| 1394 |
# choose soil depth via UI (0-200cm). If soil_img is OpenLandMap provide depth selection; if SoilGrids, show its bands
|
| 1395 |
chosen_soil_band = None
|
| 1396 |
if soil_img is not None:
|
|
|
|
| 1296 |
except Exception:
|
| 1297 |
pass
|
| 1298 |
|
| 1299 |
+
# --------------------------------------------------------------------------
|
| 1300 |
+
# Section: Display Map, Handle Drawings, and Trigger Computation
|
| 1301 |
+
# --------------------------------------------------------------------------
|
| 1302 |
+
|
|
|
|
|
|
|
|
|
|
| 1303 |
st.markdown("π Draw a polygon/rectangle on the map (use draw tool). After drawing, click **Compute Summaries**.")
|
| 1304 |
+
|
| 1305 |
+
# VITAL: Render the map and capture its state from the frontend on every script run.
|
| 1306 |
map_data = m.to_streamlit(height=700, responsive=True)
|
| 1307 |
|
| 1308 |
+
# Immediately save any newly drawn geometry to the session_state to persist it.
|
| 1309 |
+
# geemap returns the last drawn feature in the 'last_object' key.
|
| 1310 |
if map_data and map_data.get("last_object"):
|
| 1311 |
st.session_state["roi_geojson"] = json.dumps(map_data["last_object"])
|
| 1312 |
|
| 1313 |
+
# Define a robust helper function to retrieve the ROI.
|
| 1314 |
+
def get_roi_from_map():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1315 |
if "roi_geojson" in st.session_state and st.session_state["roi_geojson"]:
|
| 1316 |
try:
|
| 1317 |
+
# The data from the map is a full GeoJSON "Feature".
|
| 1318 |
+
# We need to extract only the 'geometry' part for Earth Engine.
|
| 1319 |
feature = json.loads(st.session_state["roi_geojson"])
|
| 1320 |
+
return ee.Geometry(feature['geometry'])
|
| 1321 |
except (json.JSONDecodeError, KeyError, Exception) as e:
|
| 1322 |
+
st.warning(f"Could not parse the stored ROI. Please try drawing it again. Error: {e}")
|
| 1323 |
+
# Clear the invalid ROI to prevent repeated errors
|
| 1324 |
+
del st.session_state["roi_geojson"]
|
| 1325 |
+
return None
|
| 1326 |
+
return None # Return None if no ROI has been saved yet.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1327 |
|
| 1328 |
+
# Initialize the button's state if it doesn't exist
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1329 |
if "compute_button" not in st.session_state:
|
| 1330 |
+
st.session_state["compute_button"] = False
|
| 1331 |
+
|
| 1332 |
+
# When the button is clicked, set its state to True for the subsequent rerun
|
| 1333 |
if st.button("Compute Summaries"):
|
| 1334 |
st.session_state["compute_button"] = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1335 |
|
| 1336 |
+
# This block runs ONLY if the compute button was clicked in the previous run.
|
|
|
|
|
|
|
| 1337 |
if st.session_state.get("compute_button", False):
|
| 1338 |
+
# Immediately reset the button's state to False.
|
| 1339 |
+
# This prevents the computation from running again on the next interaction.
|
| 1340 |
+
st.session_state["compute_button"] = False
|
| 1341 |
+
|
| 1342 |
+
# Retrieve the ROI using our reliable helper function
|
| 1343 |
+
roi = get_roi_from_map()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1344 |
|
| 1345 |
+
if roi is None:
|
| 1346 |
+
st.error("No drawn ROI found. Please draw a polygon or rectangle and press 'Compute Summaries' again.")
|
| 1347 |
+
else:
|
| 1348 |
+
# --- YOUR COMPUTATION LOGIC GOES HERE ---
|
| 1349 |
+
# This is where you place the code that was below the original ROI check.
|
| 1350 |
st.success("Polygon found β computing (this may take a few seconds)...")
|
| 1351 |
|
| 1352 |
+
|
| 1353 |
# choose soil depth via UI (0-200cm). If soil_img is OpenLandMap provide depth selection; if SoilGrids, show its bands
|
| 1354 |
chosen_soil_band = None
|
| 1355 |
if soil_img is not None:
|