|
import streamlit as st |
|
import json |
|
import ee |
|
import os |
|
import pandas as pd |
|
import geopandas as gpd |
|
from datetime import datetime |
|
import leafmap.foliumap as leafmap |
|
import time |
|
import re |
|
|
|
|
|
st.set_page_config(layout="wide") |
|
|
|
|
|
m = st.markdown( |
|
""" |
|
<style> |
|
div.stButton > button:first-child { |
|
background-color: #006400; |
|
color:#ffffff; |
|
} |
|
</style>""", |
|
unsafe_allow_html=True, |
|
) |
|
|
|
|
|
st.write( |
|
f""" |
|
<div style="display: flex; justify-content: space-between; align-items: center;"> |
|
<img src="https://huggingface.co/spaces/YashMK89/GEE_Calculator/resolve/main/ISRO_Logo.png" style="width: 20%; margin-right: auto;"> |
|
<img src="https://huggingface.co/spaces/YashMK89/GEE_Calculator/resolve/main/SAC_Logo.png" style="width: 20%; margin-left: auto;"> |
|
</div> |
|
""", |
|
unsafe_allow_html=True, |
|
) |
|
|
|
|
|
earthengine_credentials = os.environ.get("EE_Authentication") |
|
|
|
|
|
os.makedirs(os.path.expanduser("~/.config/earthengine/"), exist_ok=True) |
|
with open(os.path.expanduser("~/.config/earthengine/credentials"), "w") as f: |
|
f.write(earthengine_credentials) |
|
|
|
ee.Initialize(project='ee-yashsacisro24') |
|
|
|
|
|
with open("sentinel_datasets.json") as f: |
|
data = json.load(f) |
|
|
|
|
|
with open("band.json") as f: |
|
band_options = json.load(f) |
|
|
|
|
|
def get_available_bands_for_custom_formula(dataset): |
|
|
|
return band_data.get(dataset, {}).get('bands', []) |
|
|
|
|
|
st.title("Sentinel Dataset") |
|
|
|
|
|
main_selection = st.selectbox("Select Sentinel Dataset Category", list(data.keys())) |
|
|
|
if main_selection: |
|
sub_options = data[main_selection]["sub_options"] |
|
sub_selection = st.selectbox("Select Specific Dataset ID", list(sub_options.keys())) |
|
|
|
|
|
st.header("Earth Engine Index Calculator") |
|
|
|
|
|
index_choice = st.selectbox("Select an Index or Enter Custom Formula", ['NDVI', 'NDWI', 'Average NO₂', 'Custom Formula']) |
|
|
|
|
|
custom_formula = "" |
|
|
|
|
|
if index_choice.lower() == 'ndvi': |
|
st.write("Formula for NDVI: NDVI = (B8 - B4) / (B8 + B4)") |
|
elif index_choice.lower() == 'ndwi': |
|
st.write("Formula for NDWI: NDWI = (B3 - B8) / (B3 + B8)") |
|
elif index_choice.lower() == 'average no₂': |
|
st.write("Formula for Average NO₂: Average NO₂ = Mean(NO2 band)") |
|
elif index_choice.lower() == 'custom formula': |
|
|
|
available_bands = get_available_bands_for_custom_formula(sub_selection) |
|
|
|
if available_bands: |
|
|
|
st.write(f"Available bands for {sub_selection}:") |
|
selected_bands = st.multiselect("Select Bands", available_bands) |
|
|
|
|
|
st.write("Example formula: (B8 - B4) / (B8 + B4)") |
|
|
|
|
|
custom_formula = st.text_area("Enter Custom Formula", value="") |
|
|
|
|
|
st.write(f"Custom Formula: {custom_formula}") |
|
else: |
|
st.warning(f"No available bands found for the selected dataset ({sub_selection}). Please ensure the dataset contains bands.") |
|
|
|
|
|
def convert_to_ee_geometry(geometry): |
|
|
|
if geometry.is_valid: |
|
|
|
geojson = geometry.__geo_interface__ |
|
|
|
return ee.Geometry(geojson) |
|
else: |
|
raise ValueError("Invalid geometry: The polygon geometry is not valid.") |
|
|
|
|
|
def read_csv(file_path): |
|
df = pd.read_csv(file_path) |
|
return df |
|
|
|
|
|
def read_geojson(file_path): |
|
gdf = gpd.read_file(file_path) |
|
return gdf |
|
|
|
|
|
def read_kml(file_path): |
|
gdf = gpd.read_file(file_path, driver='KML') |
|
return gdf |
|
|
|
|
|
shape_type = st.selectbox("Do you want to process 'Point' or 'Polygon' data?", ["Point", "Polygon"]) |
|
|
|
|
|
file_upload = st.file_uploader(f"Upload your {shape_type} data (CSV, GeoJSON, KML)", type=["csv", "geojson", "kml"]) |
|
|
|
|
|
start_date = st.date_input("Start Date", value=pd.to_datetime('2020-01-01')) |
|
end_date = st.date_input("End Date", value=pd.to_datetime('2020-12-31')) |
|
|
|
|
|
start_date_str = start_date.strftime('%Y-%m-%d') |
|
end_date_str = end_date.strftime('%Y-%m-%d') |
|
|
|
|
|
if 'results' not in st.session_state: |
|
st.session_state.results = [] |
|
if 'last_params' not in st.session_state: |
|
st.session_state.last_params = {} |
|
if 'map_data' not in st.session_state: |
|
st.session_state.map_data = None |
|
|
|
if 'file_upload' in st.session_state: |
|
st.session_state.file_upload = None |
|
|
|
|
|
def parameters_changed(): |
|
return ( |
|
st.session_state.last_params.get('main_selection') != main_selection or |
|
st.session_state.last_params.get('sub_selection') != sub_selection or |
|
st.session_state.last_params.get('index_choice') != index_choice or |
|
st.session_state.last_params.get('start_date_str') != start_date_str or |
|
st.session_state.last_params.get('end_date_str') != end_date_str |
|
) |
|
|
|
|
|
if parameters_changed(): |
|
st.session_state.results = [] |
|
|
|
st.session_state.last_params = { |
|
'main_selection': main_selection, |
|
'sub_selection': sub_selection, |
|
'index_choice': index_choice, |
|
'start_date_str': start_date_str, |
|
'end_date_str': end_date_str |
|
} |
|
|
|
|
|
def calculate_custom_formula(image, geometry, formula, band_selection): |
|
|
|
for i, band in enumerate(band_selection, 1): |
|
formula = formula.replace(f'B{i}', band) |
|
|
|
result = image.expression(formula).rename('Custom Index').reduceRegion( |
|
reducer=ee.Reducer.mean(), |
|
geometry=geometry, |
|
scale=30 |
|
) |
|
return result.get('Custom Index') |
|
|
|
|
|
if 'file_upload' in st.session_state and st.session_state.file_upload != file_upload: |
|
reset_session_state_for_new_file() |
|
|
|
|
|
if file_upload: |
|
locations_df = None |
|
polygons_df = None |
|
|
|
file_extension = os.path.splitext(file_upload.name)[1].lower() |
|
|
|
|
|
if shape_type.lower() == 'point': |
|
if file_extension == '.csv': |
|
locations_df = read_csv(file_upload) |
|
elif file_extension == '.geojson': |
|
locations_df = read_geojson(file_upload) |
|
elif file_extension == '.kml': |
|
locations_df = read_kml(file_upload) |
|
else: |
|
st.error("Unsupported file type. Please upload a CSV, GeoJSON, or KML file for points.") |
|
elif shape_type.lower() == 'polygon': |
|
if file_extension == '.geojson': |
|
polygons_df = read_geojson(file_upload) |
|
elif file_extension == '.kml': |
|
polygons_df = read_kml(file_upload) |
|
else: |
|
st.error("Unsupported file type. Please upload a GeoJSON or KML file for polygons.") |
|
|
|
|
|
if locations_df is not None: |
|
|
|
st.write("Preview of the uploaded points data:") |
|
st.dataframe(locations_df.head()) |
|
|
|
|
|
m = leafmap.Map(center=[locations_df['latitude'].mean(), locations_df['longitude'].mean()], zoom=10) |
|
|
|
|
|
for _, row in locations_df.iterrows(): |
|
latitude = row['latitude'] |
|
longitude = row['longitude'] |
|
|
|
|
|
if pd.isna(latitude) or pd.isna(longitude): |
|
continue |
|
|
|
m.add_marker(location=[latitude, longitude], popup=row.get('name', 'No Name')) |
|
|
|
|
|
st.write("Map of Uploaded Points:") |
|
m.to_streamlit() |
|
|
|
|
|
st.session_state.map_data = m |
|
|
|
|
|
for idx, row in locations_df.iterrows(): |
|
latitude = row['latitude'] |
|
longitude = row['longitude'] |
|
location_name = row.get('name', f"Point_{idx}") |
|
|
|
|
|
if pd.isna(latitude) or pd.isna(longitude): |
|
continue |
|
|
|
|
|
roi = ee.Geometry.Point([longitude, latitude]) |
|
|
|
|
|
collection = ee.ImageCollection(sub_options[sub_selection]) \ |
|
.filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \ |
|
.filterBounds(roi) |
|
|
|
|
|
image_count = collection.size().getInfo() |
|
if image_count == 0: |
|
st.warning(f"No images found for {location_name}.") |
|
else: |
|
st.write(f"Found {image_count} images for {location_name}.") |
|
image = collection.first() |
|
|
|
|
|
result = None |
|
if index_choice.lower() == 'custom formula' and custom_formula: |
|
result = calculate_custom_formula(image, roi, custom_formula, band_selection) |
|
|
|
if result is not None: |
|
|
|
calculated_value = result.getInfo() |
|
|
|
|
|
st.session_state.results.append({ |
|
'Location Name': location_name, |
|
'Latitude': latitude, |
|
'Longitude': longitude, |
|
'Calculated Value': calculated_value |
|
}) |
|
|
|
|
|
if polygons_df is not None: |
|
|
|
st.write("Preview of the uploaded polygons data:") |
|
st.dataframe(polygons_df.head()) |
|
|
|
|
|
m = leafmap.Map(center=[polygons_df.geometry.centroid.y.mean(), polygons_df.geometry.centroid.x.mean()], zoom=10) |
|
|
|
|
|
for _, row in polygons_df.iterrows(): |
|
polygon = row['geometry'] |
|
if polygon.is_valid: |
|
|
|
gdf = gpd.GeoDataFrame([row], geometry=[polygon], crs=polygons_df.crs) |
|
|
|
|
|
m.add_gdf(gdf=gdf, layer_name=row.get('name', 'Unnamed Polygon')) |
|
|
|
|
|
st.write("Map of Uploaded Polygons:") |
|
m.to_streamlit() |
|
|
|
|
|
st.session_state.map_data = m |
|
|
|
|
|
for idx, row in polygons_df.iterrows(): |
|
polygon = row['geometry'] |
|
location_name = row.get('name', f"Polygon_{idx}") |
|
|
|
|
|
try: |
|
roi = convert_to_ee_geometry(polygon) |
|
except ValueError as e: |
|
st.error(str(e)) |
|
continue |
|
|
|
|
|
collection = ee.ImageCollection(sub_options[sub_selection]) \ |
|
.filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \ |
|
.filterBounds(roi) |
|
|
|
|
|
image_count = collection.size().getInfo() |
|
if image_count == 0: |
|
st.warning(f"No images found for {location_name}.") |
|
else: |
|
st.write(f"Found {image_count} images for {location_name}.") |
|
image = collection.first() |
|
|
|
|
|
result = None |
|
if index_choice.lower() == 'custom formula' and custom_formula: |
|
result = calculate_custom_formula(image, roi, custom_formula, band_selection) |
|
|
|
if result is not None: |
|
|
|
calculated_value = result.getInfo() |
|
|
|
|
|
st.session_state.results.append({ |
|
'Location Name': location_name, |
|
'Calculated Value': calculated_value |
|
}) |
|
|
|
|
|
if st.session_state.results: |
|
|
|
result_df = pd.DataFrame(st.session_state.results) |
|
|
|
|
|
if shape_type.lower() == 'point': |
|
|
|
st.write("Processed Results Table (Points):") |
|
st.dataframe(result_df[['Location Name', 'Latitude', 'Longitude', 'Calculated Value']]) |
|
else: |
|
|
|
st.write("Processed Results Table (Polygons):") |
|
st.dataframe(result_df[['Location Name', 'Calculated Value']]) |
|
|
|
|
|
filename = f"{main_selection}_{sub_selection}_{start_date.strftime('%Y/%m/%d')}_{end_date.strftime('%Y/%m/%d')}_{shape_type}.csv" |
|
|
|
|
|
st.download_button( |
|
label="Download results as CSV", |
|
data=result_df.to_csv(index=False).encode('utf-8'), |
|
file_name=filename, |
|
mime='text/csv' |
|
) |
|
|