Spaces:
Running
Running
File size: 7,525 Bytes
9914376 73b9278 954111c 7eeceec 73b9278 210106d 189935d 2284563 189935d 2284563 189935d a633cb2 73b9278 b90f50d a633cb2 b90f50d 189935d 45c1420 b90f50d 7eeceec b90f50d 13c538e b90f50d 7eeceec b90f50d 7eeceec b90f50d 73b9278 b90f50d 7eeceec b90f50d 566bbba b90f50d 41103fd 73b9278 b90f50d 7480d60 73b9278 b90f50d 2284563 566bbba ec37d32 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
import re
import json
import streamlit as st
import pandas as pd
import geopandas as gpd
import leafmap.foliumap as leafmap
from optree import tree_map
from shapely.ops import transform
def shape_3d_to_2d(shape):
if shape.has_z:
return transform(lambda x, y, z: (x, y), shape)
else:
return shape
def preprocess_gdf(gdf):
gdf = gdf.to_crs(epsg=7761) # epsg for Gujarat
gdf["geometry"] = gdf["geometry"].apply(shape_3d_to_2d)
gdf["geometry"] = gdf.buffer(0) # Fixes some invalid geometries
return gdf
# wide streamlit display
st.set_page_config(layout="wide")
# Function
# Logo
cols = st.columns([1, 11, 1])
with cols[0]:
st.image("Final_IITGN-Logo-symmetric-Color.png")
with cols[-1]:
st.image("IFS.jpg")
# Title
# make title in center
with cols[1]:
st.markdown(
f"""
<h1 style="text-align: center;">KML Viewer</h1>
""",
unsafe_allow_html=True,
)
file_url = st.query_params.get("file_url", None)
if not file_url:
st.warning(
"Please provide a KML or GeoJSON URL as a query parameter, e.g., `?file_url=<your_file_url>` or upload a file."
)
file_url = st.file_uploader("Upload KML/GeoJSON file", type=["geojson", "kml", "shp"])
if not file_url:
st.stop()
if ("file_url" in st.session_state) and ("input_gdf" in st.session_state) and (st.session_state.file_url == file_url):
# st.toast("Using cached data")
input_gdf = st.session_state.input_gdf
else:
st.session_state.file_url = file_url
if isinstance(file_url, str):
if file_url.startswith("https://drive.google.com/file/d/"):
ID = file_url.replace("https://drive.google.com/file/d/", "").split("/")[0]
file_url = f"https://drive.google.com/uc?id={ID}"
elif file_url.startswith("https://drive.google.com/open?id="):
ID = file_url.replace("https://drive.google.com/open?id=", "")
file_url = f"https://drive.google.com/uc?id={ID}"
input_gdf = preprocess_gdf(gpd.read_file(file_url))
if len(input_gdf) != 1:
st.error(
f"Expecting only one geometry per KML, but found {len(input_gdf)} geometries. Please fix the KML or provide another KML."
)
st.stop()
st.session_state.input_gdf = input_gdf
# st.toast("Data loaded and cached")
def format_fn(x):
return input_gdf.drop(columns=["geometry"]).loc[x].to_dict()
with st.expander("Advanced Controls", expanded=False):
# input_geometry_idx = st.selectbox("Select the geometry", input_gdf.index, format_func=format_fn)
map_type = st.radio(
"",
["Esri Satellite Map", "Google Hybrid Map (displays place names)", "Google Satellite Map"],
horizontal=True,
)
height = st.number_input("Map height (px)", 1, 10000, 600, 1)
geometry_gdf = input_gdf[input_gdf.index == 0]
def check_valid_geometry(geometry_gdf):
geometry = geometry_gdf.geometry.item()
if geometry.type != "Polygon":
st.error(f"Selected geometry is of type '{geometry.type}'. Please provide a 'Polygon' geometry.")
st.stop()
check_valid_geometry(geometry_gdf)
m = leafmap.Map()
st.markdown(
"""
<style>
.stRadio [role=radiogroup]{
align-items: center;
justify-content: center;
}
</style>
""",
unsafe_allow_html=True,
)
if map_type == "Google Hybrid Map (displays place names)":
st.write(
"<h4><div style='text-align: center;'>Google Hybrid (displays place names)</div></h4>",
unsafe_allow_html=True,
)
m.add_basemap("HYBRID")
elif map_type == "Google Satellite Map":
st.write("<h4><div style='text-align: center;'>Google Satellite</div></h4>", unsafe_allow_html=True)
m.add_basemap("SATELLITE")
elif map_type == "Esri Satellite Map":
st.write("<h4><div style='text-align: center;'>Esri - 2024/10/10</div></h4>", unsafe_allow_html=True)
m.add_wms_layer(
"https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/GoogleMapsCompatible/MapServer/tile/56450/{z}/{y}/{x}",
layers="0",
)
else:
st.error("Invalid map type")
st.stop()
m.add_gdf(
geometry_gdf.to_crs(epsg=4326),
layer_name="Geometry",
zoom_to_layer=True,
style_function=lambda x: {"color": "red", "fillOpacity": 0.0},
)
m.to_streamlit(height=height)
# Metrics
stats_df = pd.DataFrame()
stats_df["Points"] = json.loads(geometry_gdf.to_crs(4326).to_json())["features"][0]["geometry"]["coordinates"]
stats_df["Centroid"] = geometry_gdf.centroid.to_crs(4326).item()
stats_df["Area (ha)"] = geometry_gdf.geometry.area.item() / 10000
stats_df["Perimeter (m)"] = geometry_gdf.geometry.length.item()
st.write("<h3><div style='text-align: center;'>Geometry Metrics</div></h3>", unsafe_allow_html=True)
# st.markdown(
# f"""| Metric | Value |
# | --- | --- |
# | Area (ha) | {stats_df['Area (ha)'].item():.2f} ha|
# | Perimeter (m) | {stats_df['Perimeter (m)'].item():.2f} m |"""
# unsafe_allow_html=True)
centroid_lon = stats_df["Centroid"].item().xy[0][0]
centroid_lat = stats_df["Centroid"].item().xy[1][0]
centroid_url = f"http://maps.google.com/maps?q={centroid_lat},{centroid_lon}&layer=satellite"
st.markdown(
f"""
<div style="display: flex; justify-content: center;">
<table>
<tr>
<th>Metric</th>
<th>Value</th>
</tr>
<td>Centroid</td>
<td>
({centroid_lon:.5f}, {centroid_lat:.5f})
<a href="{centroid_url}" target="_blank">
<button>View on Google Maps</button>
</a>
</td>
</tr>
<td>Area (ha)</td>
<td>{stats_df['Area (ha)'].item():.2f} ha</td>
</tr>
<tr>
<td>Perimeter (m)</td>
<td>{stats_df['Perimeter (m)'].item():.2f} m</td>
</tr>
</table>
</div>
""",
unsafe_allow_html=True,
)
print(stats_df["Points"].item())
print(type(stats_df["Points"].item()))
csv = stats_df.T.to_csv(index=True)
st.download_button("Download Geometry Metrics", csv, f"{file_url}_metrics.csv", "text/csv", use_container_width=True)
if isinstance(file_url, str):
st.markdown(
f"""
<div style="display: flex; justify-content: center;">
<a href="https://huggingface.co/spaces/SustainabilityLabIITGN/NDVI_PERG?file_url={file_url}" target="_blank">
<button style="
background-color: #006400; /* Green background */
color: white; /* White text */
padding: 10px 20px;
font-size: 16px;
border: none;
border-radius: 5px;
cursor: pointer;
">
Click for NDVI Timeseries
</button>
</a>
</div>
""",
unsafe_allow_html=True,
)
# else:
# st.markdown(
# f"""
# <div style="display: flex; justify-content: center;">
# <button style="
# background-color: #FF0000; /* Green background */
# color: white; /* White text */
# padding: 10px 20px;
# font-size: 16px;
# border: none;
# border-radius: 5px;
# cursor: pointer;
# ">
# Click for NDVI Timeseries (This button will be enabled when you provide a file via `?file_url=`)
# </button>
# </a>
# </div>
# """,
# unsafe_allow_html=True,
# )
|