# import streamlit as st # import geopandas as gpd # from shapely.geometry import Point # import folium # from streamlit_folium import st_folium # from geopy.geocoders import Nominatim # import tempfile # import os # import zipfile # # Configure page # st.set_page_config(page_title="City Shapefile Generator", layout="wide") # st.title("🌍 City Location Exporter") # # Initialize geocoder # geolocator = Nominatim(user_agent="city_shape_app") # def get_city_location(city_name): # """Get coordinates for a city name""" # location = geolocator.geocode(city_name) # if location: # return location.latitude, location.longitude # return None # def create_geodataframe(lat, lon, city_name): # """Create a GeoDataFrame from coordinates""" # geometry = Point(lon, lat) # return gpd.GeoDataFrame( # [[city_name, lat, lon, geometry]], # columns=["city", "latitude", "longitude", "geometry"], # crs="EPSG:4326" # ) # def create_map(lat, lon, city_name): # """Create Folium map with marker""" # m = folium.Map(location=[lat, lon], zoom_start=12) # folium.Marker( # [lat, lon], # popup=city_name, # tooltip=city_name, # icon=folium.Icon(color="red", icon="info-sign") # ).add_to(m) # folium.CircleMarker( # [lat, lon], # radius=100, # color='blue', # fill=True, # fill_color='blue' # ).add_to(m) # return m # def save_to_format(gdf, format_type, temp_dir, city_name): # """Save to specific format and return file path""" # base_path = os.path.join(temp_dir, f"{city_name}_location") # if format_type == "SHP": # full_path = f"{base_path}.shp" # gdf.to_file(full_path) # return [f"{base_path}.{ext}" for ext in ["shp", "shx", "dbf", "prj", "cpg"]] # elif format_type == "GeoJSON": # full_path = f"{base_path}.geojson" # gdf.to_file(full_path, driver='GeoJSON') # return [full_path] # elif format_type == "KML": # full_path = f"{base_path}.kml" # gdf.to_file(full_path, driver='KML') # return [full_path] # def create_download_button(file_paths, format_type, city_name): # """Create a download button for the files""" # if format_type == "SHP": # zip_path = f"{city_name}_shapefile.zip" # with zipfile.ZipFile(zip_path, 'w') as zipf: # for file in file_paths: # if os.path.exists(file): # zipf.write(file, os.path.basename(file)) # with open(zip_path, 'rb') as f: # return st.download_button( # label=f"Download {format_type}", # data=f, # file_name=zip_path, # mime="application/zip", # key=f"{city_name}_shp" # Unique key for each button # ) # else: # with open(file_paths[0], 'rb') as f: # return st.download_button( # label=f"Download {format_type}", # data=f, # file_name=os.path.basename(file_paths[0]), # mime="application/octet-stream", # key=f"{city_name}_{format_type.lower()}" # ) # # Main app # city_name = st.text_input("Enter city name:", "Paris") # if 'coords' not in st.session_state: # st.session_state.coords = None # if 'city_found' not in st.session_state: # st.session_state.city_found = None # if st.button("Locate City"): # with st.spinner("Searching location..."): # coords = get_city_location(city_name) # st.session_state.coords = coords # st.session_state.city_found = city_name # if st.session_state.coords: # lat, lon = st.session_state.coords # st.success(f"Found {st.session_state.city_found} at coordinates: {lat:.4f}, {lon:.4f}") # # Display persistent map # m = create_map(lat, lon, st.session_state.city_found) # st_folium(m, width=800, height=500) # # Create GeoDataFrame # gdf = create_geodataframe(lat, lon, st.session_state.city_found) # # Persistent download buttons # st.header("Download Options") # col1, col2, col3 = st.columns(3) # with tempfile.TemporaryDirectory() as temp_dir: # # Shapefile # with col1: # shp_files = save_to_format(gdf, "SHP", temp_dir, st.session_state.city_found) # create_download_button(shp_files, "SHP", st.session_state.city_found) # # GeoJSON # with col2: # geojson_file = save_to_format(gdf, "GeoJSON", temp_dir, st.session_state.city_found) # create_download_button(geojson_file, "GeoJSON", st.session_state.city_found) # # KML # with col3: # kml_file = save_to_format(gdf, "KML", temp_dir, st.session_state.city_found) # create_download_button(kml_file, "KML", st.session_state.city_found) # elif st.session_state.city_found and not st.session_state.coords: # st.error("City not found. Please try a different name.") import streamlit as st import geopandas as gpd import folium from streamlit_folium import st_folium import tempfile import os import zipfile import osmnx as ox from shapely.geometry import Polygon # Configure page st.set_page_config(page_title="City Boundary Exporter", layout="wide") st.title("🌆 City Boundary Exporter") def get_city_boundary(city_name): """Get city boundary polygon from OpenStreetMap""" try: # Get the boundary geometry gdf = ox.geocode_to_gdf(city_name) # Simplify geometry if too complex if gdf.shape[0] > 0: gdf['geometry'] = gdf['geometry'].simplify(0.001) return gdf return None except Exception as e: st.error(f"Error fetching boundary: {str(e)}") return None def create_map(gdf): """Create Folium map with the boundary""" centroid = gdf.geometry.centroid.iloc[0] m = folium.Map(location=[centroid.y, centroid.x], zoom_start=11) folium.GeoJson( gdf.__geo_interface__, style_function=lambda x: { 'fillColor': '#1f77b4', 'color': '#1f77b4', 'weight': 2, 'fillOpacity': 0.4 } ).add_to(m) # Add centroid marker folium.Marker( [centroid.y, centroid.x], popup="Centroid", icon=folium.Icon(color="red") ).add_to(m) return m def save_to_format(gdf, format_type, temp_dir, city_name): """Save to specific format and return file path""" base_path = os.path.join(temp_dir, f"{city_name}_boundary") if format_type == "SHP": full_path = f"{base_path}.shp" gdf.to_file(full_path) return [f"{base_path}.{ext}" for ext in ["shp", "shx", "dbf", "prj", "cpg"]] elif format_type == "GeoJSON": full_path = f"{base_path}.geojson" gdf.to_file(full_path, driver='GeoJSON') return [full_path] elif format_type == "KML": full_path = f"{base_path}.kml" gdf.to_file(full_path, driver='KML') return [full_path] def create_download_button(file_paths, format_type, city_name): """Create a download button for the files""" if format_type == "SHP": zip_path = f"{city_name}_boundary.zip" with zipfile.ZipFile(zip_path, 'w') as zipf: for file in file_paths: if os.path.exists(file): zipf.write(file, os.path.basename(file)) with open(zip_path, 'rb') as f: st.download_button( label=f"Download {format_type}", data=f, file_name=zip_path, mime="application/zip", key=f"{city_name}_shp" ) else: with open(file_paths[0], 'rb') as f: st.download_button( label=f"Download {format_type}", data=f, file_name=os.path.basename(file_paths[0]), mime="application/octet-stream", key=f"{city_name}_{format_type.lower()}" ) # Main app city_name = st.text_input("Enter city name (include country if needed):", "Berlin, Germany") if st.button("Get City Boundary"): with st.spinner("Fetching boundary from OpenStreetMap..."): boundary_gdf = get_city_boundary(city_name) if boundary_gdf is not None: st.session_state.boundary_gdf = boundary_gdf st.session_state.city_found = city_name if 'boundary_gdf' in st.session_state: st.success(f"Found boundary for {st.session_state.city_found}") # Display map m = create_map(st.session_state.boundary_gdf) st_folium(m, width=800, height=500) # Download options st.header("Download Options") col1, col2, col3 = st.columns(3) with tempfile.TemporaryDirectory() as temp_dir: # Shapefile with col1: shp_files = save_to_format(st.session_state.boundary_gdf, "SHP", temp_dir, st.session_state.city_found) create_download_button(shp_files, "SHP", st.session_state.city_found) # GeoJSON with col2: geojson_file = save_to_format(st.session_state.boundary_gdf, "GeoJSON", temp_dir, st.session_state.city_found) create_download_button(geojson_file, "GeoJSON", st.session_state.city_found) # KML with col3: kml_file = save_to_format(st.session_state.boundary_gdf, "KML", temp_dir, st.session_state.city_found) create_download_button(kml_file, "KML", st.session_state.city_found)