import streamlit as st import geopandas as gpd import folium import zipfile import tempfile import os from streamlit_folium import st_folium from shapely.geometry import LineString st.set_page_config(page_title="GIS Viewer", layout="wide") st.title("πŸ—ΊοΈ GIS Viewer with Connected Points") st.markdown("Upload a GeoJSON, KMZ, or zipped Shapefile. This app will connect every 2 consecutive points with a solid line.") uploaded_file = st.file_uploader("Upload GeoJSON, KMZ or zipped Shapefile", type=["geojson", "zip", "kmz"]) def load_geodata(file): ext = file.name.lower() with tempfile.TemporaryDirectory() as tmpdir: if ext.endswith(".geojson"): gdf = gpd.read_file(file) elif ext.endswith(".zip"): with zipfile.ZipFile(file, "r") as z: z.extractall(tmpdir) shp_files = [f for f in os.listdir(tmpdir) if f.endswith(".shp")] if not shp_files: raise Exception("No .shp file found in ZIP.") gdf = gpd.read_file(os.path.join(tmpdir, shp_files[0])) elif ext.endswith(".kmz"): with zipfile.ZipFile(file, "r") as z: z.extractall(tmpdir) kml_files = [f for f in os.listdir(tmpdir) if f.endswith(".kml")] if not kml_files: raise Exception("No .kml file found inside KMZ.") gdf = gpd.read_file(os.path.join(tmpdir, kml_files[0])) else: raise Exception("Unsupported file format.") if gdf.crs and gdf.crs.to_epsg() != 4326: gdf = gdf.to_crs(epsg=4326) return gdf def create_lines_from_points(points_gdf): lines = [] for i in range(0, len(points_gdf) - 1, 2): p1 = points_gdf.iloc[i].geometry p2 = points_gdf.iloc[i+1].geometry if p1.geom_type == "Point" and p2.geom_type == "Point": line = LineString([p1, p2]) lines.append({"geometry": line}) return gpd.GeoDataFrame(lines, geometry="geometry", crs="EPSG:4326") if uploaded_file: try: with st.spinner("Processing file..."): gdf = load_geodata(uploaded_file) st.success("File loaded successfully!") # Filter only points point_gdf = gdf[gdf.geometry.type == "Point"].reset_index(drop=True) line_gdf = create_lines_from_points(point_gdf) # Map setup center = gdf.geometry.unary_union.centroid m = folium.Map(location=[center.y, center.x], zoom_start=10) folium.GeoJson(gdf, name="Features", tooltip=folium.GeoJsonTooltip(fields=gdf.columns[:3].tolist())).add_to(m) # Add lines between points folium.GeoJson(line_gdf, name="Lines Between Points", style_function=lambda x: {"color": "red", "weight": 3}).add_to(m) # Add point markers for idx, row in point_gdf.iterrows(): coords = row.geometry.coords[0] folium.Marker( location=[coords[1], coords[0]], popup=f"Point {idx+1} - ({coords[1]}, {coords[0]})", icon=folium.Icon(color="blue", icon="info-sign") ).add_to(m) folium.LayerControl().add_to(m) st.subheader("🌍 Map Viewer") st_folium(m, width=1100, height=600) st.subheader("πŸ“ Points Table") st.dataframe(point_gdf) st.subheader("πŸ“‹ Full Attribute Table") st.dataframe(gdf) except Exception as e: st.error(f"Error: {e}") else: st.info("Please upload a geospatial file to get started.")