| 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 |
| """) |
|
|
| |
| 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 |
|
|
| |
| 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 = "" |
|
|
| |
| 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.") |
|
|
|
|
|
|
|
|