Spaces:
Build error
Build error
| import geopandas as gpd | |
| import pandas as pd | |
| from shapely.geometry import shape, Polygon, LineString, Point | |
| from shapely.ops import unary_union | |
| import xml.etree.ElementTree as ET | |
| import zipfile | |
| import os | |
| import matplotlib.pyplot as plt | |
| import streamlit as st | |
| from transformers import pipeline | |
| # For KML access, extracting 3D coordinates (Polygon Z) | |
| def p(kml_file): | |
| cont = kml_file.decode('utf-8') # Decode bytes to string | |
| k = ET.ElementTree(ET.fromstring(cont)) | |
| root = k.getroot() | |
| ns = {'kml': 'http://www.opengis.net/kml/2.2'} | |
| shapes = [] | |
| for mark in root.findall('.//kml:Placemark', ns): | |
| polygon = mark.find('.//kml:Polygon/kml:coordinates', ns) | |
| if polygon is not None: | |
| coordinates = polygon.text.strip().split() | |
| coords = [(float(lon), float(lat), float(z) if z else 0) for lon, lat, z in [coord.split(',') for coord in coordinates]] | |
| shapes.append(Polygon([coords])) # Make it a Polygon with Z | |
| line = mark.find('.//kml:LineString/kml:coordinates', ns) | |
| if line is not None: | |
| coordinates = line.text.strip().split() | |
| coords = [(float(lon), float(lat), float(z) if z else 0) for lon, lat, z in [coord.split(',') for coord in coordinates]] | |
| shapes.append(LineString(coords)) | |
| point = mark.find('.//kml:Point/kml:coordinates', ns) | |
| if point is not None: | |
| lon, lat, z = point.text.strip().split(',') | |
| shapes.append(Point(float(lon), float(lat), float(z) if z else 0)) | |
| return shapes if shapes else None | |
| # For file extraction if it is in KMZ form | |
| def ext(kmz_file): | |
| with zipfile.ZipFile(kmz_file, 'r') as zip_ref: | |
| zip_ref.extractall('temp_kml') | |
| kml_file = [f for f in os.listdir('temp_kml') if f.endswith('.kml')][0] | |
| with open(os.path.join('temp_kml', kml_file), 'rb') as f: | |
| return p(f.read()) | |
| # See if it is a kml or kmz file | |
| def choose(upf): | |
| file_bytes = upf.read() | |
| if upf.name.endswith('.kmz'): | |
| return ext(file_bytes) | |
| else: | |
| return p(file_bytes) | |
| # For file uploading | |
| st.title("Flood Zone Analysis") | |
| upf = st.file_uploader("Upload KML/KMZ file", type=['kml', 'kmz']) | |
| # Convert 2D to 3D if needed (add default Z = 0) | |
| def convert_to_3d(geom): | |
| """Convert 2D geometries to 3D by adding a Z value (default = 0)""" | |
| if geom.geom_type == 'Polygon': | |
| coords = [(x, y, 0) for x, y in geom.exterior.coords] | |
| return Polygon(coords) | |
| elif geom.geom_type == 'LineString': | |
| coords = [(x, y, 0) for x, y in geom.coords] | |
| return LineString(coords) | |
| elif geom.geom_type == 'Point': | |
| return Point(geom.x, geom.y, 0) | |
| return geom # Return unchanged if not 2D | |
| # For comparing the boundary between KML and shapefile | |
| def bound(f, gdf): | |
| if f.empty: # Handle invalid KML shapes | |
| return "Invalid KML shape or no valid polygon found.", None | |
| overlaps = [] # Save matching boundaries | |
| for kml_shape in f: | |
| intersection = gdf[gdf.intersects(kml_shape)] | |
| if not intersection.empty: | |
| overlaps.append(intersection) | |
| if not overlaps: | |
| return "Boundary doesn't match", None | |
| every_int = unary_union([geom for intersect in overlaps for geom in intersect.geometry]) | |
| return overlaps, every_int | |
| # Find common bound's Acreage and Usable Land | |
| def land(overlaps, every_int): | |
| all = pd.concat(overlaps) | |
| all['area'] = all.geometry.area | |
| all['area_acres'] = all['area'] / 4046.86 # Convert to acres | |
| fza = {zone: all[all['FLD_ZONE'] == zone]['area_acres'].sum() for zone in all['FLD_ZONE'].unique()} | |
| areas = ['A', 'AE', 'AH', 'AO', 'VE'] | |
| non = all[~all['FLD_ZONE'].isin(areas)]['area_acres'].sum() | |
| merged_area = every_int.area / 4046.86 | |
| return fza, non, merged_area | |
| # Initial summary was with GPT-2 | |
| def summ(fza, non, total_acreage): | |
| summarizer = pipeline("summarization", model="gpt2") | |
| areas = ['A', 'AE', 'AH', 'AO', 'VE'] | |
| flood_zone_summary = "\n".join([f" Zone {zone}: {fza.get(zone, 0):.2f} acres" for zone in areas]) | |
| prompt = f""" | |
| **Total Land Area**: {total_acreage:.2f} acres | |
| **Usable Area**: {non:.2f} acres | |
| **Flood-prone Zones**: | |
| {flood_zone_summary} | |
| Summarize the above given data in 2-3 sentences. | |
| """ | |
| response = summarizer(prompt, max_length=200, min_length=30, do_sample=False) | |
| return response[0]['summary_text'] | |
| if upf is not None: | |
| # Read shapefiles and convert them to 3D if needed | |
| kent = gpd.read_file("K_FLD_HAZ_AR.shp") | |
| nc = gpd.read_file("N_FLD_HAZ_AR.shp") | |
| sussex = gpd.read_file("S_FLD_HAZ_AR.shp") | |
| # Combine them | |
| dela = gpd.GeoDataFrame(pd.concat([kent, nc, sussex], ignore_index=True)) | |
| # Add Coordinate Reference System | |
| dela = dela.set_crs(kent.crs, allow_override=True) | |
| # Convert to 3D (add Z = 0 if missing) | |
| dela['geometry'] = dela['geometry'].apply(convert_to_3d) | |
| dela = dela.to_crs(epsg=3857) | |
| # Fix invalid geometries | |
| dela['geometry'] = dela['geometry'].apply(lambda x: x.buffer(0) if not x.is_valid else x) | |
| # Upload KML/KMZ file | |
| f = choose(upf) | |
| if f: | |
| # Check if KML has valid geometries | |
| kml_gdf = gpd.GeoDataFrame(geometry=f, crs="EPSG:4326") | |
| kml_gdf = kml_gdf.to_crs(epsg=3857) | |
| # Convert KML to 3D (add Z = 0 if missing) | |
| kml_gdf['geometry'] = kml_gdf['geometry'].apply(convert_to_3d) | |
| # Compare KML and Shapefile | |
| intersection, every_int = bound(kml_gdf.geometry, dela) | |
| if isinstance(intersection, str): | |
| st.write(intersection) | |
| else: | |
| flood_zone_areas, non, merged_area = land(intersection, every_int) | |
| st.write(f"Flood Zone Areas:") | |
| for zone, area in flood_zone_areas.items(): | |
| st.write(f" Zone {zone}: {area:.2f} acres") | |
| st.write(f"\nNon-Flooded Land Area: {non:.2f} acres") | |
| st.write(f"\nMerged Area of Intersected Boundary: {merged_area:.2f} acres") | |
| summary = summ(flood_zone_areas, non, merged_area) | |
| st.write(f"GPT-2 Summary: {summary}") | |
| # Show map | |
| fig, ax = plt.subplots(figsize=(10, 10)) | |
| # shapefile | |
| dela.plot(ax=ax, color='blue', alpha=0.5) | |
| # Show overlap with KML | |
| if intersection: | |
| intersection_geom = unary_union([geom for intersect in intersection for geom in intersect.geometry]) | |
| gpd.GeoDataFrame(geometry=[intersection_geom], crs=dela.crs).plot(ax=ax, color='red', alpha=0.7) | |
| # Plot the KML boundary (green color) | |
| kml_gdf.plot(ax=ax, color='green', alpha=0.3) | |
| # Display the plot | |
| st.pyplot(fig) | |
| else: | |
| st.write("No valid geometries found in the uploaded KML file.") | |
| else: | |
| st.write("Please upload a KML/KMZ file to continue.") | |