YashMK89 commited on
Commit
d2c85d1
·
verified ·
1 Parent(s): 8e4e9db

update app.py

Browse files
Files changed (1) hide show
  1. app.py +5 -804
app.py CHANGED
@@ -1,803 +1,3 @@
1
- # import streamlit as st
2
- # import json
3
- # import ee
4
- # import os
5
- # import pandas as pd
6
- # import geopandas as gpd
7
- # from datetime import datetime
8
- # import leafmap.foliumap as leafmap
9
- # import re
10
- # from shapely.geometry import base
11
- # from lxml import etree
12
- # from xml.etree import ElementTree as ET
13
-
14
- # # Set up the page layout
15
- # st.set_page_config(layout="wide")
16
-
17
- # # Custom button styling
18
- # m = st.markdown(
19
- # """
20
- # <style>
21
- # div.stButton > button:first-child {
22
- # background-color: #006400;
23
- # color:#ffffff;
24
- # }
25
- # </style>""",
26
- # unsafe_allow_html=True,
27
- # )
28
-
29
- # # Logo
30
- # st.write(
31
- # f"""
32
- # <div style="display: flex; justify-content: space-between; align-items: center;">
33
- # <img src="https://huggingface.co/spaces/YashMK89/GEE_Calculator/resolve/main/ISRO_Logo.png" style="width: 20%; margin-right: auto;">
34
- # <img src="https://huggingface.co/spaces/YashMK89/GEE_Calculator/resolve/main/SAC_Logo.png" style="width: 20%; margin-left: auto;">
35
- # </div>
36
- # """,
37
- # unsafe_allow_html=True,
38
- # )
39
-
40
- # # Title
41
- # st.markdown(
42
- # f"""
43
- # <h1 style="text-align: center;">Precision Analysis for Vegetation, Water, and Air Quality</h1>
44
- # """,
45
- # unsafe_allow_html=True,
46
- # )
47
- # st.write("<h2><div style='text-align: center;'>User Inputs</div></h2>", unsafe_allow_html=True)
48
-
49
- # # Authenticate and initialize Earth Engine
50
- # earthengine_credentials = os.environ.get("EE_Authentication")
51
-
52
- # # Initialize Earth Engine with secret credentials
53
- # os.makedirs(os.path.expanduser("~/.config/earthengine/"), exist_ok=True)
54
- # with open(os.path.expanduser("~/.config/earthengine/credentials"), "w") as f:
55
- # f.write(earthengine_credentials)
56
-
57
- # ee.Initialize(project='ee-yashsacisro24')
58
-
59
- # # Load the Sentinel dataset options from JSON file
60
- # with open("sentinel_datasets.json") as f:
61
- # data = json.load(f)
62
-
63
- # # Display the title for the Streamlit app
64
- # st.title("Sentinel Dataset")
65
-
66
- # # Select dataset category (main selection)
67
- # main_selection = st.selectbox("Select Sentinel Dataset Category", list(data.keys()))
68
-
69
- # # If a category is selected, display the sub-options (specific datasets)
70
- # if main_selection:
71
- # sub_options = data[main_selection]["sub_options"]
72
- # sub_selection = st.selectbox("Select Specific Dataset ID", list(sub_options.keys()))
73
-
74
- # # Display the selected dataset ID based on user input
75
- # if sub_selection:
76
- # st.write(f"You selected: {main_selection} -> {sub_selection}")
77
- # st.write(f"Dataset ID: {sub_options[sub_selection]}")
78
-
79
- # # Fetch the correct dataset ID from the sub-selection
80
- # dataset_id = sub_options[sub_selection]
81
-
82
- # # Earth Engine Index Calculator Section
83
- # st.header("Earth Engine Index Calculator")
84
-
85
- # index_choice = st.selectbox("Select an Index or Enter Custom Formula", ['NDVI', 'NDWI', 'Average NO₂', 'Custom Formula'])
86
-
87
- # # Initialize custom_formula variable
88
- # custom_formula = ""
89
-
90
- # # Display corresponding formula based on the index selected (case-insensitive)
91
- # if index_choice.lower() == 'ndvi':
92
- # st.write("Formula for NDVI: NDVI = (B8 - B4) / (B8 + B4)")
93
- # elif index_choice.lower() == 'ndwi':
94
- # st.write("Formula for NDWI: NDWI = (B3 - B8) / (B3 + B8)")
95
- # elif index_choice.lower() == 'average no₂':
96
- # st.write("Formula for Average NO₂: Average NO₂ = Mean(NO2 band)")
97
- # elif index_choice.lower() == 'custom formula':
98
- # custom_formula = st.text_input("Enter Custom Formula (e.g., B5,B4 for two bands or B3 for one band)")
99
- # # Check if custom formula is empty and show warning
100
- # if not custom_formula:
101
- # st.warning("Please enter a custom formula before proceeding.")
102
- # else:
103
- # # Check if the input contains a comma (indicating two bands)
104
- # if ',' in custom_formula:
105
- # # Split the input into two bands and strip whitespace
106
- # band1, band2 = [b.strip() for b in custom_formula.split(',', 1)]
107
- # st.write(f"Custom Formula: ({band1} - {band2}) / ({band1} + {band2})")
108
- # else:
109
- # # Single band case
110
- # band = custom_formula.strip()
111
- # st.write(f"Custom Formula: {band}")
112
-
113
- # # Function to get the corresponding reducer based on user input
114
- # def get_reducer(reducer_name):
115
- # """
116
- # Map user-friendly reducer names to Earth Engine reducer objects.
117
- # """
118
- # reducers = {
119
- # 'mean': ee.Reducer.mean(),
120
- # 'sum': ee.Reducer.sum(),
121
- # 'median': ee.Reducer.median(),
122
- # 'min': ee.Reducer.min(),
123
- # 'max': ee.Reducer.max(),
124
- # 'count': ee.Reducer.count(),
125
- # }
126
-
127
- # # Default to 'mean' if the reducer_name is not recognized
128
- # return reducers.get(reducer_name.lower(), ee.Reducer.mean())
129
-
130
- # # Streamlit selectbox for reducer choice
131
- # reducer_choice = st.selectbox(
132
- # "Select Reducer",
133
- # ['mean', 'sum', 'median', 'min', 'max', 'count'],
134
- # index=0 # Default to 'mean'
135
- # )
136
-
137
- # def convert_to_ee_geometry(geometry):
138
- # # Handle Shapely geometry
139
- # if isinstance(geometry, base.BaseGeometry):
140
- # if geometry.is_valid:
141
- # geojson = geometry.__geo_interface__
142
- # print("Shapely GeoJSON:", geojson) # Debugging: Inspect the GeoJSON structure
143
- # return ee.Geometry(geojson)
144
- # else:
145
- # raise ValueError("Invalid geometry: The polygon geometry is not valid.")
146
-
147
- # # Handle GeoJSON input (string or dictionary)
148
- # elif isinstance(geometry, dict) or isinstance(geometry, str):
149
- # try:
150
- # if isinstance(geometry, str):
151
- # geometry = json.loads(geometry)
152
- # if 'type' in geometry and 'coordinates' in geometry:
153
- # print("GeoJSON Geometry:", geometry) # Debugging: Inspect the GeoJSON structure
154
- # return ee.Geometry(geometry)
155
- # else:
156
- # raise ValueError("GeoJSON format is invalid.")
157
- # except Exception as e:
158
- # raise ValueError(f"Error parsing GeoJSON: {e}")
159
-
160
- # # Handle KML input (string or file path)
161
- # elif isinstance(geometry, str) and geometry.lower().endswith(".kml"):
162
- # try:
163
- # # Parse the KML file
164
- # tree = ET.parse(geometry)
165
- # kml_root = tree.getroot()
166
-
167
- # # Extract coordinates from KML geometry (assuming it's a Polygon or MultiPolygon)
168
- # # KML coordinates are usually within the <coordinates> tag
169
- # kml_namespace = {'kml': 'http://www.opengis.net/kml/2.2'}
170
- # coordinates = kml_root.findall(".//kml:coordinates", kml_namespace)
171
-
172
- # if coordinates:
173
- # # Extract and format coordinates
174
- # coords_text = coordinates[0].text.strip()
175
- # coords = coords_text.split()
176
- # # Convert KML coordinates (comma-separated) into a list of tuples
177
- # coords = [tuple(map(float, coord.split(','))) for coord in coords]
178
- # geojson = {
179
- # "type": "Polygon", # Make sure the GeoJSON type is Polygon
180
- # "coordinates": [coords] # Wrap the coordinates in a list (required by GeoJSON format)
181
- # }
182
-
183
- # # Debugging: Inspect the KML-to-GeoJSON structure
184
- # print("KML GeoJSON:", geojson)
185
-
186
- # return ee.Geometry(geojson)
187
- # else:
188
- # raise ValueError("KML does not contain valid coordinates.")
189
- # except Exception as e:
190
- # raise ValueError(f"Error parsing KML: {e}")
191
-
192
- # else:
193
- # raise ValueError("Unsupported geometry input type. Supported types are Shapely, GeoJSON, and KML.")
194
-
195
- # # Function to read points from CSV
196
- # def read_csv(file_path):
197
- # df = pd.read_csv(file_path)
198
- # return df
199
-
200
- # # Function to read points from GeoJSON
201
- # def read_geojson(file_path):
202
- # gdf = gpd.read_file(file_path)
203
- # return gdf
204
-
205
- # # Function to read points from KML
206
- # def read_kml(file_path):
207
- # gdf = gpd.read_file(file_path, driver='KML')
208
- # return gdf
209
-
210
-
211
- # # Date Input for Start and End Dates
212
- # start_date = st.date_input("Start Date", value=pd.to_datetime('2024-11-01'))
213
- # end_date = st.date_input("End Date", value=pd.to_datetime('2024-12-01'))
214
-
215
- # # Convert start_date and end_date to string format for Earth Engine
216
- # start_date_str = start_date.strftime('%Y-%m-%d')
217
- # end_date_str = end_date.strftime('%Y-%m-%d')
218
-
219
- # # Aggregation period selection
220
- # aggregation_period = st.selectbox("Select Aggregation Period", ["Daily", "Weekly", "Monthly", "Yearly"], index=0)
221
-
222
- # # Ask user whether they want to process 'Point' or 'Polygon' data (case-insensitive)
223
- # shape_type = st.selectbox("Do you want to process 'Point' or 'Polygon' data?", ["Point", "Polygon"])
224
-
225
- # # Ask user to upload a file based on shape type (case-insensitive)
226
- # file_upload = st.file_uploader(f"Upload your {shape_type} data (CSV, GeoJSON, KML)", type=["csv", "geojson", "kml"])
227
-
228
- # if file_upload is not None:
229
- # # Read the user-uploaded file
230
- # if shape_type.lower() == "point":
231
- # # Handle different file types for Point data
232
- # if file_upload.name.endswith('.csv'):
233
- # locations_df = pd.read_csv(file_upload)
234
- # elif file_upload.name.endswith('.geojson'):
235
- # locations_df = gpd.read_file(file_upload)
236
- # elif file_upload.name.endswith('.kml'):
237
- # locations_df = gpd.read_file(file_upload)
238
- # else:
239
- # st.error("Unsupported file format. Please upload CSV, GeoJSON, or KML.")
240
- # locations_df = pd.DataFrame()
241
-
242
- # # Check if the file contains polygons when the user selected "Point"
243
- # if 'geometry' in locations_df.columns:
244
- # # Check if the geometry type is Polygon or MultiPolygon
245
- # if locations_df.geometry.geom_type.isin(['Polygon', 'MultiPolygon']).any():
246
- # st.warning("The uploaded file contains polygon data. Please select 'Polygon' for processing.")
247
- # st.stop() # Stop further processing if polygons are detected
248
-
249
- # # Processing the point data
250
- # with st.spinner('Processing Map...'):
251
- # if locations_df is not None and not locations_df.empty:
252
- # # For GeoJSON data, the coordinates are in the geometry column
253
- # if 'geometry' in locations_df.columns:
254
- # # Extract latitude and longitude from the geometry column
255
- # locations_df['latitude'] = locations_df['geometry'].y
256
- # locations_df['longitude'] = locations_df['geometry'].x
257
-
258
- # # Ensure the necessary columns exist in the dataframe
259
- # if 'latitude' not in locations_df.columns or 'longitude' not in locations_df.columns:
260
- # st.error("Uploaded file is missing required 'latitude' or 'longitude' columns.")
261
- # else:
262
- # # Display a preview of the points data
263
- # st.write("Preview of the uploaded points data:")
264
- # st.dataframe(locations_df.head())
265
-
266
- # # Create a LeafMap object to display the points
267
- # m = leafmap.Map(center=[locations_df['latitude'].mean(), locations_df['longitude'].mean()], zoom=10)
268
-
269
- # # Add points to the map using a loop
270
- # for _, row in locations_df.iterrows():
271
- # latitude = row['latitude']
272
- # longitude = row['longitude']
273
-
274
- # # Check if latitude or longitude are NaN and skip if they are
275
- # if pd.isna(latitude) or pd.isna(longitude):
276
- # continue # Skip this row and move to the next one
277
-
278
- # m.add_marker(location=[latitude, longitude], popup=row.get('name', 'No Name'))
279
-
280
- # # Display map
281
- # st.write("Map of Uploaded Points:")
282
- # m.to_streamlit()
283
-
284
- # # Store the map in session_state
285
- # st.session_state.map_data = m
286
-
287
- # elif shape_type.lower() == "polygon":
288
- # # Handle different file types for Polygon data:
289
- # if file_upload.name.endswith('.csv'):
290
- # locations_df = pd.read_csv(file_upload)
291
- # elif file_upload.name.endswith('.geojson'):
292
- # locations_df = gpd.read_file(file_upload)
293
- # elif file_upload.name.endswith('.kml'):
294
- # locations_df = gpd.read_file(file_upload)
295
- # else:
296
- # st.error("Unsupported file format. Please upload CSV, GeoJSON, or KML.")
297
- # locations_df = pd.DataFrame()
298
-
299
- # # Check if the file contains points when the user selected "Polygon"
300
- # if 'geometry' in locations_df.columns:
301
- # # Check if the geometry type is Point or MultiPoint
302
- # if locations_df.geometry.geom_type.isin(['Point', 'MultiPoint']).any():
303
- # st.warning("The uploaded file contains point data. Please select 'Point' for processing.")
304
- # st.stop() # Stop further processing if point data is detected
305
-
306
- # # Processing the polygon data
307
- # with st.spinner('Processing Map...'):
308
- # if locations_df is not None and not locations_df.empty:
309
- # # Ensure the 'geometry' column exists in the dataframe
310
- # if 'geometry' not in locations_df.columns:
311
- # st.error("Uploaded file is missing required 'geometry' column.")
312
- # else:
313
- # # Display a preview of the polygons data
314
- # st.write("Preview of the uploaded polygons data:")
315
- # st.dataframe(locations_df.head())
316
-
317
- # # Create a LeafMap object to display the polygons
318
- # # Calculate the centroid of the polygons for the map center
319
- # centroid_lat = locations_df.geometry.centroid.y.mean()
320
- # centroid_lon = locations_df.geometry.centroid.x.mean()
321
-
322
- # m = leafmap.Map(center=[centroid_lat, centroid_lon], zoom=10)
323
-
324
- # # Add polygons to the map using a loop
325
- # for _, row in locations_df.iterrows():
326
- # polygon = row['geometry']
327
- # if polygon.is_valid: # Check if polygon is valid
328
- # # Create a GeoDataFrame for this polygon
329
- # gdf = gpd.GeoDataFrame([row], geometry=[polygon], crs=locations_df.crs)
330
- # m.add_gdf(gdf=gdf, layer_name=row.get('name', 'Unnamed Polygon'))
331
-
332
- # # Display map
333
- # st.write("Map of Uploaded Polygons:")
334
- # m.to_streamlit()
335
-
336
- # # Store the map in session_state
337
- # st.session_state.map_data = m
338
-
339
- # # Initialize session state for storing results if not already done
340
- # if 'results' not in st.session_state:
341
- # st.session_state.results = []
342
- # if 'last_params' not in st.session_state:
343
- # st.session_state.last_params = {}
344
- # if 'map_data' not in st.session_state:
345
- # st.session_state.map_data = None # Initialize map_data
346
-
347
- # # Function to check if parameters have changed
348
- # def parameters_changed():
349
- # return (
350
- # st.session_state.last_params.get('main_selection') != main_selection or
351
- # st.session_state.last_params.get('dataset_id') != dataset_id or
352
- # st.session_state.last_params.get('index_choice') != index_choice or
353
- # st.session_state.last_params.get('start_date_str') != start_date_str or
354
- # st.session_state.last_params.get('end_date_str') != end_date_str or
355
- # st.session_state.last_params.get('shape_type') != shape_type or
356
- # st.session_state.last_params.get('file_upload') != file_upload
357
- # )
358
-
359
- # # If parameters have changed, reset the results
360
- # if parameters_changed():
361
- # st.session_state.results = [] # Clear the previous results
362
- # st.session_state.last_params = {
363
- # 'main_selection': main_selection,
364
- # 'dataset_id': dataset_id,
365
- # 'index_choice': index_choice,
366
- # 'start_date_str': start_date_str,
367
- # 'end_date_str': end_date_str,
368
- # 'shape_type': shape_type,
369
- # 'file_upload': file_upload
370
- # }
371
-
372
- # # Function to calculate NDVI with the selected reducer
373
- # def calculate_ndvi(image, geometry, reducer_choice):
374
- # ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI')
375
- # return ndvi
376
-
377
- # # Function to calculate NDWI
378
- # def calculate_ndwi(image, geometry, reducer_choice):
379
- # ndwi = image.normalizedDifference(['B3', 'B8']).rename('NDWI')
380
- # return ndwi
381
-
382
- # def calculate_custom_formula(image, geometry, custom_formula, reducer_choice, scale=30):
383
- # try:
384
- # if "," in custom_formula:
385
- # band1, band2 = [b.strip() for b in custom_formula.split(",")]
386
- # band_names = image.bandNames().getInfo()
387
- # if band1 not in band_names or band2 not in band_names:
388
- # raise ValueError(f"One or both bands ({band1}, {band2}) do not exist in the image.")
389
- # result = image.normalizedDifference([band1, band2]).rename('custom_formula')
390
- # else:
391
- # band = custom_formula.strip()
392
- # band_names = image.bandNames().getInfo()
393
- # if band not in band_names:
394
- # raise ValueError(f"The band '{band}' does not exist in the image.")
395
- # result = image.select(band).rename('custom_formula')
396
- # return result
397
- # except Exception as e:
398
- # return ee.Image(0).rename('custom_formula').set('error', str(e))
399
-
400
- # # Modify aggregation functions to return the correct time period and aggregated results
401
- # def aggregate_data_daily(collection):
402
- # # Extract day from the image date (using the exact date)
403
- # collection = collection.map(lambda image: image.set('day', ee.Date(image.get('system:time_start')).format('YYYY-MM-dd')))
404
-
405
- # # Group images by day (distinct days)
406
- # grouped_by_day = collection.aggregate_array('day').distinct()
407
-
408
- # def calculate_daily_mean(day):
409
- # # Filter the collection by the specific day
410
- # daily_collection = collection.filter(ee.Filter.eq('day', day))
411
- # daily_mean = daily_collection.mean() # Calculate mean for the day
412
- # return daily_mean.set('day', day)
413
-
414
- # # Calculate the daily mean for each day
415
- # daily_images = ee.List(grouped_by_day.map(calculate_daily_mean))
416
-
417
- # return ee.ImageCollection(daily_images)
418
-
419
- # def aggregate_data_weekly(collection):
420
- # # Extract the start date of the week from the image date
421
- # collection = collection.map(lambda image: image.set(
422
- # 'week_start', ee.Date(image.get('system:time_start'))
423
- # .advance(-ee.Date(image.get('system:time_start')).getRelative('day', 'week'), 'day')
424
- # ))
425
- # # Group images by week start date
426
- # grouped_by_week = collection.aggregate_array('week_start').distinct()
427
-
428
- # def calculate_weekly_mean(week_start):
429
- # # Filter the collection by the specific week start date
430
- # weekly_collection = collection.filter(ee.Filter.eq('week_start', week_start))
431
- # weekly_mean = weekly_collection.mean() # Calculate mean for the week
432
- # return weekly_mean.set('week_start', week_start)
433
-
434
- # # Calculate the weekly mean for each week
435
- # weekly_images = ee.List(grouped_by_week.map(calculate_weekly_mean))
436
- # return ee.ImageCollection(weekly_images)
437
-
438
- # def aggregate_data_monthly(collection, start_date, end_date):
439
- # # Filter the collection for the specific date range
440
- # collection = collection.filterDate(start_date, end_date)
441
-
442
- # # Extract month and year from the image date
443
- # collection = collection.map(lambda image: image.set('month', ee.Date(image.get('system:time_start')).format('YYYY-MM')))
444
-
445
- # # Group images by month
446
- # grouped_by_month = collection.aggregate_array('month').distinct()
447
-
448
- # def calculate_monthly_mean(month):
449
- # monthly_collection = collection.filter(ee.Filter.eq('month', month))
450
- # monthly_mean = monthly_collection.mean()
451
- # return monthly_mean.set('month', month)
452
-
453
- # # Calculate the monthly mean for each month
454
- # monthly_images = ee.List(grouped_by_month.map(calculate_monthly_mean))
455
-
456
- # return ee.ImageCollection(monthly_images)
457
-
458
- # def aggregate_data_yearly(collection):
459
- # # Extract year from the image date
460
- # collection = collection.map(lambda image: image.set('year', ee.Date(image.get('system:time_start')).format('YYYY')))
461
-
462
- # # Group images by year
463
- # grouped_by_year = collection.aggregate_array('year').distinct()
464
-
465
- # def calculate_yearly_mean(year):
466
- # yearly_collection = collection.filter(ee.Filter.eq('year', year))
467
- # yearly_mean = yearly_collection.mean()
468
- # return yearly_mean.set('year', year)
469
-
470
- # # Calculate the yearly mean for each year
471
- # yearly_images = ee.List(grouped_by_year.map(calculate_yearly_mean))
472
-
473
- # return ee.ImageCollection(yearly_images)
474
-
475
- # # Function to calculate index based on the selected choice
476
- # def calculate_index_for_period(image, roi, index_choice, reducer_choice, custom_formula):
477
- # if index_choice.lower() == 'ndvi':
478
- # return calculate_ndvi(image, roi, reducer_choice)
479
- # elif index_choice.lower() == 'ndwi':
480
- # return calculate_ndwi(image, roi, reducer_choice)
481
- # elif index_choice.lower() == 'average no₂':
482
- # mean_no2 = image.select('NO2').mean().rename('Average NO₂')
483
- # return mean_no2
484
- # elif index_choice.lower() == 'custom formula':
485
- # # Pass the custom formula here, not the index_choice
486
- # return calculate_custom_formula(image, roi, custom_formula, reducer_choice)
487
- # else:
488
- # st.write("Please Select any one option...."+ index_choice.lower())
489
-
490
- # def aggregate_data_weekly(collection):
491
- # def set_week_start(image):
492
- # # Get the image timestamp
493
- # date = ee.Date(image.get('system:time_start'))
494
- # # Calculate days since the start of the week (0 = Monday, 6 = Sunday)
495
- # days_since_week_start = date.getRelative('day', 'week')
496
- # # Convert to ee.Number and negate it to get the offset to the week start
497
- # offset = ee.Number(days_since_week_start).multiply(-1)
498
- # # Advance the date by the negative offset to get the week start
499
- # week_start = date.advance(offset, 'day')
500
- # return image.set('week_start', week_start.format('YYYY-MM-dd')) # Ensure string format
501
-
502
- # # Apply the week start calculation to each image
503
- # collection = collection.map(set_week_start)
504
-
505
- # # Group images by week start date
506
- # grouped_by_week = collection.aggregate_array('week_start').distinct()
507
-
508
- # def calculate_weekly_mean(week_start):
509
- # # Filter the collection by the specific week start date
510
- # weekly_collection = collection.filter(ee.Filter.eq('week_start', week_start))
511
- # weekly_mean = weekly_collection.mean() # Calculate mean for the week
512
- # return weekly_mean.set('week_start', week_start)
513
-
514
- # # Calculate the weekly mean for each week
515
- # weekly_images = ee.List(grouped_by_week.map(calculate_weekly_mean))
516
- # return ee.ImageCollection(weekly_images)
517
-
518
- # def process_aggregation(locations_df, start_date_str, end_date_str, dataset_id, index_choice, reducer_choice, shape_type, aggregation_period, custom_formula=""):
519
- # aggregated_results = []
520
-
521
- # if index_choice.lower() == 'custom_formula' and not custom_formula:
522
- # st.error("Custom formula cannot be empty. Please provide a formula.")
523
- # return aggregated_results
524
-
525
- # total_steps = len(locations_df)
526
- # progress_bar = st.progress(0)
527
- # progress_text = st.empty()
528
-
529
- # with st.spinner('Processing data...'):
530
- # if shape_type.lower() == "point":
531
- # for idx, row in locations_df.iterrows():
532
- # latitude = row.get('latitude')
533
- # longitude = row.get('longitude')
534
- # if pd.isna(latitude) or pd.isna(longitude):
535
- # st.warning(f"Skipping location {idx} with missing latitude or longitude")
536
- # continue
537
-
538
- # location_name = row.get('name', f"Location_{idx}")
539
- # roi = ee.Geometry.Point([longitude, latitude])
540
-
541
- # collection = ee.ImageCollection(dataset_id) \
542
- # .filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \
543
- # .filterBounds(roi)
544
-
545
- # # Aggregate data based on the selected period
546
- # if aggregation_period.lower() == 'daily':
547
- # collection = aggregate_data_daily(collection)
548
- # elif aggregation_period.lower() == 'weekly':
549
- # collection = aggregate_data_weekly(collection)
550
- # elif aggregation_period.lower() == 'monthly':
551
- # collection = aggregate_data_monthly(collection, start_date_str, end_date_str)
552
- # elif aggregation_period.lower() == 'yearly':
553
- # collection = aggregate_data_yearly(collection)
554
-
555
- # # Process each image in the collection
556
- # image_list = collection.toList(collection.size())
557
- # processed_weeks = set() # Track processed weeks to avoid duplicates
558
- # for i in range(image_list.size().getInfo()):
559
- # image = ee.Image(image_list.get(i))
560
-
561
- # if aggregation_period.lower() == 'daily':
562
- # timestamp = image.get('day')
563
- # period_label = 'Date'
564
- # date = ee.Date(timestamp).format('YYYY-MM-dd').getInfo()
565
- # elif aggregation_period.lower() == 'weekly':
566
- # timestamp = image.get('week_start')
567
- # period_label = 'Week'
568
- # date = ee.String(timestamp).getInfo() # Already formatted as YYYY-MM-dd
569
- # # Skip if week is outside the date range or already processed
570
- # if (pd.to_datetime(date) < pd.to_datetime(start_date_str) or
571
- # pd.to_datetime(date) > pd.to_datetime(end_date_str) or
572
- # date in processed_weeks):
573
- # continue
574
- # processed_weeks.add(date)
575
- # elif aggregation_period.lower() == 'monthly':
576
- # timestamp = image.get('month')
577
- # period_label = 'Month'
578
- # date = ee.Date(timestamp).format('YYYY-MM').getInfo()
579
- # elif aggregation_period.lower() == 'yearly':
580
- # timestamp = image.get('year')
581
- # period_label = 'Year'
582
- # date = ee.Date(timestamp).format('YYYY').getInfo()
583
-
584
- # index_image = calculate_index_for_period(image, roi, index_choice, reducer_choice, custom_formula)
585
-
586
- # try:
587
- # index_value = index_image.reduceRegion(
588
- # reducer=get_reducer(reducer_choice),
589
- # geometry=roi,
590
- # scale=30
591
- # ).get(index_image.bandNames().get(0))
592
-
593
- # calculated_value = index_value.getInfo()
594
-
595
- # if isinstance(calculated_value, (int, float)):
596
- # aggregated_results.append({
597
- # 'Location Name': location_name,
598
- # 'Latitude': latitude,
599
- # 'Longitude': longitude,
600
- # period_label: date,
601
- # 'Start Date': start_date_str,
602
- # 'End Date': end_date_str,
603
- # 'Calculated Value': calculated_value
604
- # })
605
- # else:
606
- # st.warning(f"Skipping invalid value for {location_name} on {date}")
607
- # except Exception as e:
608
- # st.error(f"Error retrieving value for {location_name}: {e}")
609
-
610
- # progress_percentage = (idx + 1) / total_steps
611
- # progress_bar.progress(progress_percentage)
612
- # progress_text.markdown(f"Processing: {int(progress_percentage * 100)}%")
613
-
614
- # elif shape_type.lower() == "polygon":
615
- # for idx, row in locations_df.iterrows():
616
- # polygon_name = row.get('name', f"Polygon_{idx}")
617
- # polygon_geometry = row.get('geometry')
618
- # location_name = polygon_name
619
-
620
- # try:
621
- # roi = convert_to_ee_geometry(polygon_geometry)
622
- # except ValueError as e:
623
- # st.warning(f"Skipping invalid polygon {polygon_name}: {e}")
624
- # continue
625
-
626
- # collection = ee.ImageCollection(dataset_id) \
627
- # .filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \
628
- # .filterBounds(roi)
629
-
630
- # # Aggregate data based on the selected period
631
- # if aggregation_period.lower() == 'daily':
632
- # collection = aggregate_data_daily(collection)
633
- # elif aggregation_period.lower() == 'weekly':
634
- # collection = aggregate_data_weekly(collection)
635
- # elif aggregation_period.lower() == 'monthly':
636
- # collection = aggregate_data_monthly(collection, start_date_str, end_date_str)
637
- # elif aggregation_period.lower() == 'yearly':
638
- # collection = aggregate_data_yearly(collection)
639
-
640
- # # Process each image in the collection
641
- # image_list = collection.toList(collection.size())
642
- # processed_weeks = set() # Track processed weeks to avoid duplicates
643
- # for i in range(image_list.size().getInfo()):
644
- # image = ee.Image(image_list.get(i))
645
-
646
- # if aggregation_period.lower() == 'daily':
647
- # timestamp = image.get('day')
648
- # period_label = 'Date'
649
- # date = ee.Date(timestamp).format('YYYY-MM-dd').getInfo()
650
- # elif aggregation_period.lower() == 'weekly':
651
- # timestamp = image.get('week_start')
652
- # period_label = 'Week'
653
- # date = ee.String(timestamp).getInfo() # Already formatted as YYYY-MM-dd
654
- # # Skip if week is outside the date range or already processed
655
- # if (pd.to_datetime(date) < pd.to_datetime(start_date_str) or
656
- # pd.to_datetime(date) > pd.to_datetime(end_date_str) or
657
- # date in processed_weeks):
658
- # continue
659
- # processed_weeks.add(date)
660
- # elif aggregation_period.lower() == 'monthly':
661
- # timestamp = image.get('month')
662
- # period_label = 'Month'
663
- # date = ee.Date(timestamp).format('YYYY-MM').getInfo()
664
- # elif aggregation_period.lower() == 'yearly':
665
- # timestamp = image.get('year')
666
- # period_label = 'Year'
667
- # date = ee.Date(timestamp).format('YYYY').getInfo()
668
-
669
- # index_image = calculate_index_for_period(image, roi, index_choice, reducer_choice, custom_formula)
670
-
671
- # try:
672
- # index_value = index_image.reduceRegion(
673
- # reducer=get_reducer(reducer_choice),
674
- # geometry=roi,
675
- # scale=30
676
- # ).get(index_image.bandNames().get(0))
677
-
678
- # calculated_value = index_value.getInfo()
679
-
680
- # if isinstance(calculated_value, (int, float)):
681
- # aggregated_results.append({
682
- # 'Location Name': location_name,
683
- # period_label: date,
684
- # 'Start Date': start_date_str,
685
- # 'End Date': end_date_str,
686
- # 'Calculated Value': calculated_value
687
- # })
688
- # else:
689
- # st.warning(f"Skipping invalid value for {location_name} on {date}")
690
- # except Exception as e:
691
- # st.error(f"Error retrieving value for {location_name}: {e}")
692
-
693
- # progress_percentage = (idx + 1) / total_steps
694
- # progress_bar.progress(progress_percentage)
695
- # progress_text.markdown(f"Processing: {int(progress_percentage * 100)}%")
696
-
697
- # # if aggregated_results:
698
- # # result_df = pd.DataFrame(aggregated_results)
699
- # # if aggregation_period.lower() == 'daily':
700
- # # aggregated_output = result_df.groupby('Location Name').agg({
701
- # # 'Latitude': 'first' if shape_type.lower() == 'point' else None,
702
- # # 'Longitude': 'first' if shape_type.lower() == 'point' else None,
703
- # # 'Start Date': 'first',
704
- # # 'End Date': 'first',
705
- # # 'Calculated Value': 'mean'
706
- # # }).reset_index()
707
- # # # Remove None columns (for polygons)
708
- # # aggregated_output = aggregated_output[[col for col in aggregated_output.columns if col is not None]]
709
- # # aggregated_output.rename(columns={'Calculated Value': 'Aggregated Value'}, inplace=True)
710
- # # return aggregated_output.to_dict(orient='records')
711
- # # else:
712
- # # return result_df.to_dict(orient='records')
713
-
714
- # # return []
715
-
716
- # if aggregated_results:
717
- # result_df = pd.DataFrame(aggregated_results)
718
- # if aggregation_period.lower() == 'daily':
719
- # # Define aggregation dictionary based on shape_type
720
- # agg_dict = {
721
- # 'Start Date': 'first',
722
- # 'End Date': 'first',
723
- # 'Calculated Value': 'mean'
724
- # }
725
- # if shape_type.lower() == 'point':
726
- # agg_dict['Latitude'] = 'first'
727
- # agg_dict['Longitude'] = 'first'
728
-
729
- # aggregated_output = result_df.groupby('Location Name').agg(agg_dict).reset_index()
730
- # aggregated_output.rename(columns={'Calculated Value': 'Aggregated Value'}, inplace=True)
731
- # return aggregated_output.to_dict(orient='records')
732
- # else:
733
- # return result_df.to_dict(orient='records')
734
-
735
- # return []
736
-
737
- # # When the user clicks the process button, start the calculation
738
- # if st.button(f"Calculate ({index_choice})"):
739
- # if file_upload is not None:
740
- # if shape_type.lower() == "point":
741
- # results = process_aggregation(
742
- # locations_df,
743
- # start_date_str,
744
- # end_date_str,
745
- # dataset_id,
746
- # index_choice,
747
- # reducer_choice,
748
- # shape_type,
749
- # aggregation_period,
750
- # custom_formula
751
- # )
752
- # if results:
753
- # result_df = pd.DataFrame(results)
754
- # st.write(f"Processed Results Table ({aggregation_period}):")
755
- # st.dataframe(result_df)
756
- # filename = f"{main_selection}_{dataset_id}_{start_date.strftime('%Y/%m/%d')}_{end_date.strftime('%Y/%m/%d')}_{aggregation_period.lower()}.csv"
757
- # st.download_button(
758
- # label="Download results as CSV",
759
- # data=result_df.to_csv(index=False).encode('utf-8'),
760
- # file_name=filename,
761
- # mime='text/csv'
762
- # )
763
- # st.spinner('')
764
- # st.success('Processing complete!')
765
- # else:
766
- # st.warning("No results were generated.")
767
-
768
- # elif shape_type.lower() == "polygon":
769
- # results = process_aggregation(
770
- # locations_df,
771
- # start_date_str,
772
- # end_date_str,
773
- # dataset_id,
774
- # index_choice,
775
- # reducer_choice,
776
- # shape_type,
777
- # aggregation_period,
778
- # custom_formula
779
- # )
780
- # if results:
781
- # result_df = pd.DataFrame(results)
782
- # st.write(f"Processed Results Table ({aggregation_period}):")
783
- # st.dataframe(result_df)
784
- # filename = f"{main_selection}_{dataset_id}_{start_date.strftime('%Y/%m/%d')}_{end_date.strftime('%Y/%m/%d')}_{aggregation_period.lower()}.csv"
785
- # st.download_button(
786
- # label="Download results as CSV",
787
- # data=result_df.to_csv(index=False).encode('utf-8'),
788
- # file_name=filename,
789
- # mime='text/csv'
790
- # )
791
- # st.spinner('')
792
- # st.success('Processing complete!')
793
- # else:
794
- # st.warning("No results were generated.")
795
-
796
- # else:
797
- # st.warning("Please upload a file.")
798
-
799
-
800
-
801
  import streamlit as st
802
  import json
803
  import ee
@@ -993,9 +193,6 @@ aggregation_period = st.selectbox("Select Aggregation Period", ["Daily", "Weekly
993
  # Ask user whether they want to process 'Point' or 'Polygon' data
994
  shape_type = st.selectbox("Do you want to process 'Point' or 'Polygon' data?", ["Point", "Polygon"])
995
 
996
- # Ask user to upload a file based on shape type
997
- file_upload = st.file_uploader(f"Upload your {shape_type} data (CSV, GeoJSON, KML)", type=["csv", "geojson", "kml"])
998
-
999
  # Additional options based on shape type
1000
  kernel_size = None
1001
  include_boundary = None
@@ -1012,6 +209,10 @@ elif shape_type.lower() == "polygon":
1012
  value=True,
1013
  help="Check to include pixels on the polygon boundary; uncheck to exclude them."
1014
  )
 
 
 
 
1015
 
1016
  if file_upload is not None:
1017
  # Read the user-uploaded file
@@ -1430,7 +631,7 @@ def process_aggregation(locations_df, start_date_str, end_date_str, dataset_id,
1430
  return []
1431
 
1432
  # Button to trigger calculation
1433
- if st.button("Calculate"):
1434
  if file_upload is not None:
1435
  if shape_type.lower() in ["point", "polygon"]:
1436
  results = process_aggregation(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import json
3
  import ee
 
193
  # Ask user whether they want to process 'Point' or 'Polygon' data
194
  shape_type = st.selectbox("Do you want to process 'Point' or 'Polygon' data?", ["Point", "Polygon"])
195
 
 
 
 
196
  # Additional options based on shape type
197
  kernel_size = None
198
  include_boundary = None
 
209
  value=True,
210
  help="Check to include pixels on the polygon boundary; uncheck to exclude them."
211
  )
212
+
213
+ # Ask user to upload a file based on shape type
214
+ file_upload = st.file_uploader(f"Upload your {shape_type} data (CSV, GeoJSON, KML)", type=["csv", "geojson", "kml"])
215
+
216
 
217
  if file_upload is not None:
218
  # Read the user-uploaded file
 
631
  return []
632
 
633
  # Button to trigger calculation
634
+ if st.button(f"Calculate({custom_formula})"):
635
  if file_upload is not None:
636
  if shape_type.lower() in ["point", "polygon"]:
637
  results = process_aggregation(