Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -5,30 +5,16 @@ import zipfile
|
|
| 5 |
import tempfile
|
| 6 |
import os
|
| 7 |
from streamlit_folium import st_folium
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
-
# Set Google Maps API Key (Replace with your actual API Key)
|
| 10 |
-
google_maps_api_key = "YOUR_GOOGLE_MAPS_API_KEY" # Replace with your own Google Maps API Key
|
| 11 |
-
|
| 12 |
-
st.set_page_config(page_title="π GIS Data Viewer", layout="wide", page_icon="πΊοΈ")
|
| 13 |
-
|
| 14 |
-
# ---------- Title & Intro ----------
|
| 15 |
-
st.markdown("""
|
| 16 |
-
<div style='text-align: center'>
|
| 17 |
-
<h1 style="color:#1f77b4;">πΊοΈ GIS Data Viewer</h1>
|
| 18 |
-
<p style="font-size:18px;">Upload and explore your geospatial data (GeoJSON, Shapefile ZIP, or KMZ) on an interactive map with **Google Maps**.</p>
|
| 19 |
-
</div>
|
| 20 |
-
""", unsafe_allow_html=True)
|
| 21 |
-
|
| 22 |
-
# ---------- Sidebar ----------
|
| 23 |
-
with st.sidebar:
|
| 24 |
-
st.header("π Upload & Options")
|
| 25 |
-
uploaded_file = st.file_uploader("Choose a GeoJSON, KMZ, or zipped Shapefile", type=["geojson", "zip", "kmz"])
|
| 26 |
-
show_coordinates = st.checkbox("Show Coordinates", value=True)
|
| 27 |
-
show_table = st.checkbox("Show Attribute Table", value=True)
|
| 28 |
-
st.markdown("---")
|
| 29 |
-
st.markdown("β
Supported formats:\n- `.geojson`\n- `.shp` in `.zip`\n- `.kmz`\n\nπ Automatically reprojects to **WGS84 (EPSG:4326)**.")
|
| 30 |
-
|
| 31 |
-
# ---------- Load File Function ----------
|
| 32 |
def load_geodata(file):
|
| 33 |
ext = file.name.lower()
|
| 34 |
with tempfile.TemporaryDirectory() as tmpdir:
|
|
@@ -50,106 +36,63 @@ def load_geodata(file):
|
|
| 50 |
gdf = gpd.read_file(os.path.join(tmpdir, kml_files[0]))
|
| 51 |
else:
|
| 52 |
raise Exception("Unsupported file format.")
|
| 53 |
-
|
| 54 |
-
# Ensure CRS is WGS84
|
| 55 |
if gdf.crs and gdf.crs.to_epsg() != 4326:
|
| 56 |
gdf = gdf.to_crs(epsg=4326)
|
| 57 |
return gdf
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
center = gdf.geometry.unary_union.centroid
|
| 63 |
-
m = folium.Map(location=[center.y, center.x], zoom_start=10
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
icon=folium.Icon(color='blue', icon='info-sign')
|
| 82 |
-
).add_to(m)
|
| 83 |
-
else:
|
| 84 |
-
centroid = row.geometry.centroid
|
| 85 |
-
folium.Marker(
|
| 86 |
-
location=[centroid.y, centroid.x],
|
| 87 |
-
popup=f"Feature {idx+1} - Coordinates: ({centroid.y}, {centroid.x})",
|
| 88 |
-
icon=folium.Icon(color='green', icon='ok-sign')
|
| 89 |
-
).add_to(m)
|
| 90 |
-
|
| 91 |
-
# Add Layer Control
|
| 92 |
folium.LayerControl().add_to(m)
|
| 93 |
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
return folium.Map(location=[30.0, 70.0], zoom_start=3)
|
| 97 |
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
- **Geometry Type**: {gdf.geom_type.iloc[0] if not gdf.empty else 'N/A'}
|
| 109 |
-
- **CRS**: {gdf.crs}
|
| 110 |
-
- **Number of Features**: {len(gdf)}
|
| 111 |
-
- **Columns**: {", ".join(gdf.columns)}
|
| 112 |
-
""")
|
| 113 |
-
|
| 114 |
-
# Show Map
|
| 115 |
-
st.subheader("πΊοΈ Map Viewer")
|
| 116 |
-
map_view = show_map(gdf, show_coordinates)
|
| 117 |
-
st_data = st_folium(map_view, width=1100, height=600)
|
| 118 |
-
|
| 119 |
-
# Show Coordinates in Table
|
| 120 |
-
if show_coordinates:
|
| 121 |
-
st.subheader("π Coordinates Table")
|
| 122 |
-
coords_list = []
|
| 123 |
-
|
| 124 |
-
# Extract coordinates from geometries
|
| 125 |
-
for idx, row in gdf.iterrows():
|
| 126 |
-
if row.geometry.geom_type == 'Point':
|
| 127 |
-
coords = row.geometry.coords[0]
|
| 128 |
-
coords_list.append({
|
| 129 |
-
"Feature ID": idx + 1,
|
| 130 |
-
"Geometry Type": row.geometry.geom_type,
|
| 131 |
-
"Coordinates": f"({coords[1]}, {coords[0]})"
|
| 132 |
-
})
|
| 133 |
-
else:
|
| 134 |
-
centroid = row.geometry.centroid
|
| 135 |
-
coords_list.append({
|
| 136 |
-
"Feature ID": idx + 1,
|
| 137 |
-
"Geometry Type": row.geometry.geom_type,
|
| 138 |
-
"Coordinates": f"({centroid.y}, {centroid.x})"
|
| 139 |
-
})
|
| 140 |
-
|
| 141 |
-
# Display coordinates as table
|
| 142 |
-
st.dataframe(coords_list)
|
| 143 |
-
|
| 144 |
-
# Show Attribute Table
|
| 145 |
-
if show_table:
|
| 146 |
-
st.subheader("π Attribute Table")
|
| 147 |
-
st.dataframe(gdf)
|
| 148 |
-
|
| 149 |
-
else:
|
| 150 |
-
st.info("Please upload a GeoJSON, zipped Shapefile, or KMZ to begin.")
|
| 151 |
-
map_view = show_map(None, False)
|
| 152 |
-
st_folium(map_view, width=1100, height=500)
|
| 153 |
-
|
| 154 |
-
except Exception as e:
|
| 155 |
-
st.error(f"β Error: {e}")
|
|
|
|
| 5 |
import tempfile
|
| 6 |
import os
|
| 7 |
from streamlit_folium import st_folium
|
| 8 |
+
from shapely.geometry import LineString
|
| 9 |
+
|
| 10 |
+
st.set_page_config(page_title="GIS Viewer", layout="wide")
|
| 11 |
+
|
| 12 |
+
st.title("πΊοΈ GIS Viewer with Connected Points")
|
| 13 |
+
|
| 14 |
+
st.markdown("Upload a GeoJSON, KMZ, or zipped Shapefile. This app will connect every 2 consecutive points with a solid line.")
|
| 15 |
+
|
| 16 |
+
uploaded_file = st.file_uploader("Upload GeoJSON, KMZ or zipped Shapefile", type=["geojson", "zip", "kmz"])
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
def load_geodata(file):
|
| 19 |
ext = file.name.lower()
|
| 20 |
with tempfile.TemporaryDirectory() as tmpdir:
|
|
|
|
| 36 |
gdf = gpd.read_file(os.path.join(tmpdir, kml_files[0]))
|
| 37 |
else:
|
| 38 |
raise Exception("Unsupported file format.")
|
|
|
|
|
|
|
| 39 |
if gdf.crs and gdf.crs.to_epsg() != 4326:
|
| 40 |
gdf = gdf.to_crs(epsg=4326)
|
| 41 |
return gdf
|
| 42 |
|
| 43 |
+
def create_lines_from_points(points_gdf):
|
| 44 |
+
lines = []
|
| 45 |
+
for i in range(0, len(points_gdf) - 1, 2):
|
| 46 |
+
p1 = points_gdf.iloc[i].geometry
|
| 47 |
+
p2 = points_gdf.iloc[i+1].geometry
|
| 48 |
+
if p1.geom_type == "Point" and p2.geom_type == "Point":
|
| 49 |
+
line = LineString([p1, p2])
|
| 50 |
+
lines.append({"geometry": line})
|
| 51 |
+
return gpd.GeoDataFrame(lines, geometry="geometry", crs="EPSG:4326")
|
| 52 |
+
|
| 53 |
+
if uploaded_file:
|
| 54 |
+
try:
|
| 55 |
+
with st.spinner("Processing file..."):
|
| 56 |
+
gdf = load_geodata(uploaded_file)
|
| 57 |
+
|
| 58 |
+
st.success("File loaded successfully!")
|
| 59 |
+
|
| 60 |
+
# Filter only points
|
| 61 |
+
point_gdf = gdf[gdf.geometry.type == "Point"].reset_index(drop=True)
|
| 62 |
+
line_gdf = create_lines_from_points(point_gdf)
|
| 63 |
+
|
| 64 |
+
# Map setup
|
| 65 |
center = gdf.geometry.unary_union.centroid
|
| 66 |
+
m = folium.Map(location=[center.y, center.x], zoom_start=10)
|
| 67 |
+
|
| 68 |
+
folium.GeoJson(gdf, name="Features",
|
| 69 |
+
tooltip=folium.GeoJsonTooltip(fields=gdf.columns[:3].tolist())).add_to(m)
|
| 70 |
+
|
| 71 |
+
# Add lines between points
|
| 72 |
+
folium.GeoJson(line_gdf, name="Lines Between Points",
|
| 73 |
+
style_function=lambda x: {"color": "red", "weight": 3}).add_to(m)
|
| 74 |
+
|
| 75 |
+
# Add point markers
|
| 76 |
+
for idx, row in point_gdf.iterrows():
|
| 77 |
+
coords = row.geometry.coords[0]
|
| 78 |
+
folium.Marker(
|
| 79 |
+
location=[coords[1], coords[0]],
|
| 80 |
+
popup=f"Point {idx+1} - ({coords[1]}, {coords[0]})",
|
| 81 |
+
icon=folium.Icon(color="blue", icon="info-sign")
|
| 82 |
+
).add_to(m)
|
| 83 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
folium.LayerControl().add_to(m)
|
| 85 |
|
| 86 |
+
st.subheader("π Map Viewer")
|
| 87 |
+
st_folium(m, width=1100, height=600)
|
|
|
|
| 88 |
|
| 89 |
+
st.subheader("π Points Table")
|
| 90 |
+
st.dataframe(point_gdf)
|
| 91 |
+
|
| 92 |
+
st.subheader("π Full Attribute Table")
|
| 93 |
+
st.dataframe(gdf)
|
| 94 |
+
|
| 95 |
+
except Exception as e:
|
| 96 |
+
st.error(f"Error: {e}")
|
| 97 |
+
else:
|
| 98 |
+
st.info("Please upload a geospatial file to get started.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|