import streamlit as st import requests import folium from streamlit_folium import st_folium import geopandas as gpd from shapely.geometry import shape st.set_page_config(page_title="MBE App with Catchment Delineation", layout="wide") st.title("🏞️ Minimum Basement Elevation (MBE) App with Catchment Delineation") st.markdown(""" This application allows you to: - Input a **lot address** and one or more **drainage manhole FacilityIDs** - Query the **City of Surrey's GIS API** layers for: - Lot boundaries (Layer 148) - Drainage manholes (Layer 23) - Drainage mains (Layer 18) - Contour data (Layer 105) - Automatically delineate the catchment draining to the manholes using contour-derived DEM - Calculate catchment area (ha) and compute flow Q using the Rational Method - Visualize the map with all layers """) # Helper function: Try multiple patterns to fetch a lot polygon from Layer 148 def get_lot_geometry(address: str): base_url = "https://gisservices.surrey.ca/arcgis/rest/services/OpenData/MapServer/148/query" patterns = [ f"SITEADDRESS LIKE '%{address.upper()}%'", f"SITEADDRESS LIKE '%{address.replace('Ave', 'Avenue').upper()}%'", f"SITEADDRESS LIKE '%{address.replace('-', ' ').upper()}%'" ] for where_clause in patterns: params = { "f": "geojson", "where": where_clause, "outFields": "*", "returnGeometry": "true" } try: response = requests.get(base_url, params=params, timeout=10) if response.status_code == 200: data = response.json() features = data.get("features", []) if features: return features[0]["geometry"], where_clause except: continue return None, None # Session state if "inputs_confirmed" not in st.session_state: st.session_state.inputs_confirmed = False if "facility_ids" not in st.session_state: st.session_state.facility_ids = [] if "lot_address" not in st.session_state: st.session_state.lot_address = "" # Input section st.header("📥 Input Lot Address and Manhole FacilityIDs") lot_address = st.text_input("🏠 Enter Lot Address", placeholder="e.g. 14852 68A Avenue") manhole_ids = st.text_area("🕳️ Enter Drainage Manhole FacilityIDs (comma-separated)", placeholder="e.g. 100796657, 100796658") if st.button("Submit"): if lot_address and manhole_ids: facility_ids = [x.strip() for x in manhole_ids.split(",") if x.strip()] if facility_ids: st.session_state.lot_address = lot_address st.session_state.facility_ids = facility_ids st.session_state.inputs_confirmed = True else: st.error("❌ Please enter at least one valid FacilityID.") else: st.error("❌ Please enter both a lot address and at least one manhole FacilityID.") if st.session_state.inputs_confirmed: st.success(f"✅ Lot Address: `{st.session_state.lot_address}`") st.write(f"📌 Manhole FacilityIDs ({len(st.session_state.facility_ids)}):") st.code(", ".join(st.session_state.facility_ids)) if st.button("➡️ Next: Run Catchment Delineation"): with st.spinner("🔍 Fetching lot geometry from GIS..."): geom, used_query = get_lot_geometry(st.session_state.lot_address) if geom: lot_gdf = gpd.GeoDataFrame(geometry=[shape(geom)], crs="EPSG:4326") center = lot_gdf.geometry[0].centroid.coords[0][::-1] m = folium.Map(location=center, zoom_start=17) folium.GeoJson(lot_gdf.geometry[0], name="Lot").add_to(m) st_folium(m, width=725, height=500) st.success("✅ Lot geometry retrieved using:") st.code(used_query) else: st.error("⚠️ No lot geometry found. Try reformatting the address.")