Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -175,6 +175,7 @@ def aggregate_data_daily(collection):
|
|
175 |
daily_images = ee.List(grouped_by_day.map(calculate_daily_mean))
|
176 |
return ee.ImageCollection(daily_images)
|
177 |
|
|
|
178 |
def aggregate_data_weekly(collection, start_date_str, end_date_str):
|
179 |
"""
|
180 |
Aggregates data on a weekly basis, starting from the exact start date provided by the user.
|
@@ -199,6 +200,7 @@ def aggregate_data_weekly(collection, start_date_str, end_date_str):
|
|
199 |
|
200 |
return ee.ImageCollection.fromImages(weekly_images)
|
201 |
|
|
|
202 |
def aggregate_data_monthly(collection, start_date, end_date):
|
203 |
collection = collection.filterDate(start_date, end_date)
|
204 |
collection = collection.map(lambda image: image.set('month', ee.Date(image.get('system:time_start')).format('YYYY-MM')))
|
@@ -210,6 +212,7 @@ def aggregate_data_monthly(collection, start_date, end_date):
|
|
210 |
monthly_images = ee.List(grouped_by_month.map(calculate_monthly_mean))
|
211 |
return ee.ImageCollection(monthly_images)
|
212 |
|
|
|
213 |
def aggregate_data_yearly(collection):
|
214 |
collection = collection.map(lambda image: image.set('year', ee.Date(image.get('system:time_start')).format('YYYY')))
|
215 |
grouped_by_year = collection.aggregate_array('year').distinct()
|
@@ -252,6 +255,7 @@ def calculate_cloud_percentage(image, cloud_band='QA60'):
|
|
252 |
return 0 # Avoid division by zero
|
253 |
return ee.Number(cloudy_pixels).divide(ee.Number(total_pixels)).multiply(100).getInfo()
|
254 |
|
|
|
255 |
def preprocess_collection(collection, cloud_threshold):
|
256 |
"""
|
257 |
Apply cloud filtering to the image collection using the QA60 bitmask.
|
@@ -283,109 +287,106 @@ def preprocess_collection(collection, cloud_threshold):
|
|
283 |
masked_collection = filtered_collection.map(mask_cloudy_pixels)
|
284 |
return masked_collection
|
285 |
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
|
|
305 |
roi = convert_to_ee_geometry(polygon_geometry)
|
306 |
if not include_boundary:
|
307 |
roi = roi.buffer(-30).bounds()
|
|
|
|
|
308 |
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
if aggregation_period.lower() == 'custom (start date to end date)':
|
320 |
-
|
|
|
|
|
321 |
elif aggregation_period.lower() == 'daily':
|
322 |
-
|
|
|
|
|
323 |
elif aggregation_period.lower() == 'weekly':
|
324 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
elif aggregation_period.lower() == 'monthly':
|
326 |
-
|
|
|
|
|
327 |
elif aggregation_period.lower() == 'yearly':
|
328 |
-
|
|
|
|
|
329 |
|
330 |
-
|
331 |
-
|
332 |
-
n_images = image_list.size().getInfo()
|
333 |
-
|
334 |
-
aggregated_results = []
|
335 |
-
for i in range(n_images):
|
336 |
-
image = ee.Image(image_list.get(i))
|
337 |
-
|
338 |
-
# Get the timestamp based on aggregation period
|
339 |
-
if aggregation_period.lower() == 'custom (start date to end date)':
|
340 |
-
timestamp = image.get('day')
|
341 |
-
period_label = 'Date'
|
342 |
-
date = ee.Date(timestamp).format('YYYY-MM-dd').getInfo()
|
343 |
-
elif aggregation_period.lower() == 'daily':
|
344 |
-
timestamp = image.get('day_start')
|
345 |
-
period_label = 'Date'
|
346 |
-
date = ee.String(timestamp).getInfo()
|
347 |
-
elif aggregation_period.lower() == 'weekly':
|
348 |
-
timestamp = image.get('week_start')
|
349 |
-
period_label = 'Week'
|
350 |
-
date = ee.String(timestamp).getInfo()
|
351 |
-
elif aggregation_period.lower() == 'monthly':
|
352 |
-
timestamp = image.get('month')
|
353 |
-
period_label = 'Month'
|
354 |
-
date = ee.Date(timestamp).format('YYYY-MM').getInfo()
|
355 |
-
elif aggregation_period.lower() == 'yearly':
|
356 |
-
timestamp = image.get('year')
|
357 |
-
period_label = 'Year'
|
358 |
-
date = ee.Date(timestamp).format('YYYY').getInfo()
|
359 |
-
|
360 |
-
# Calculate the custom formula
|
361 |
-
index_image = calculate_custom_formula(image, roi, selected_bands, custom_formula, reducer_choice, scale=30)
|
362 |
-
|
363 |
-
# Get the reduced value
|
364 |
index_value = index_image.reduceRegion(
|
365 |
reducer=get_reducer(reducer_choice),
|
366 |
geometry=roi,
|
367 |
scale=30
|
368 |
-
).get('custom_result')
|
369 |
-
|
370 |
-
if isinstance(
|
371 |
result = {
|
372 |
'Location Name': location_name,
|
373 |
period_label: date,
|
374 |
'Start Date': start_date_str,
|
375 |
'End Date': end_date_str,
|
376 |
-
'Calculated Value':
|
377 |
}
|
378 |
if shape_type.lower() == 'point':
|
379 |
-
result[original_lat_col] = latitude
|
380 |
-
result[original_lon_col] = longitude
|
381 |
aggregated_results.append(result)
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
st.error(f"Error processing {location_name if 'location_name' in locals() else 'location'}: {str(e)}")
|
387 |
-
return None
|
388 |
|
|
|
389 |
def process_aggregation(locations_df, start_date_str, end_date_str, dataset_id, selected_bands, reducer_choice, shape_type, aggregation_period, original_lat_col, original_lon_col, custom_formula="", kernel_size=None, include_boundary=None, cloud_threshold=0):
|
390 |
aggregated_results = []
|
391 |
total_steps = len(locations_df)
|
@@ -393,6 +394,20 @@ def process_aggregation(locations_df, start_date_str, end_date_str, dataset_id,
|
|
393 |
progress_text = st.empty()
|
394 |
start_time = time.time() # Start timing the process
|
395 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
396 |
with ThreadPoolExecutor(max_workers=10) as executor:
|
397 |
futures = []
|
398 |
for idx, row in locations_df.iterrows():
|
@@ -410,8 +425,7 @@ def process_aggregation(locations_df, start_date_str, end_date_str, dataset_id,
|
|
410 |
original_lat_col,
|
411 |
original_lon_col,
|
412 |
kernel_size,
|
413 |
-
include_boundary
|
414 |
-
cloud_threshold
|
415 |
)
|
416 |
futures.append(future)
|
417 |
completed = 0
|
@@ -435,6 +449,7 @@ def process_aggregation(locations_df, start_date_str, end_date_str, dataset_id,
|
|
435 |
'Start Date': 'first',
|
436 |
'End Date': 'first',
|
437 |
'Calculated Value': 'mean'
|
|
|
438 |
}
|
439 |
if shape_type.lower() == 'point':
|
440 |
agg_dict[original_lat_col] = 'first'
|
@@ -578,6 +593,7 @@ cloud_threshold = st.slider(
|
|
578 |
help="Tiles with cloud coverage exceeding this threshold will be excluded. Individual cloudy pixels will also be masked."
|
579 |
)
|
580 |
|
|
|
581 |
aggregation_period = st.selectbox(
|
582 |
"Select Aggregation Period (e.g, Custom(Start Date to End Date) , Daily , Weekly , Monthly , Yearly)",
|
583 |
["Custom (Start Date to End Date)", "Daily", "Weekly", "Monthly", "Yearly"],
|
@@ -730,113 +746,44 @@ if file_upload is not None:
|
|
730 |
st.write("Map of Uploaded Polygons:")
|
731 |
m.to_streamlit()
|
732 |
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
#
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
'min': 0,
|
772 |
-
'max': 1,
|
773 |
-
'palette': ['white', 'blue'] # White = clear, Blue = cloudy
|
774 |
-
}
|
775 |
-
|
776 |
-
return cloud_mask, cloud_vis
|
777 |
-
|
778 |
-
# In the cloud preview button section:
|
779 |
-
if st.button("Preview Cloud Coverage"):
|
780 |
-
if not locations_df.empty:
|
781 |
-
with st.spinner("Loading Cloud Coverage Preview..."):
|
782 |
-
try:
|
783 |
-
# Debug prints (properly indented)
|
784 |
-
st.write(f"Leafmap version: {leafmap.__version__}")
|
785 |
-
|
786 |
-
# Filter the collection for the uploaded geometry
|
787 |
-
if shape_type.lower() == "point":
|
788 |
-
latitude = locations_df.iloc[0]['latitude']
|
789 |
-
longitude = locations_df.iloc[0]['longitude']
|
790 |
-
roi = ee.Geometry.Point([longitude, latitude])
|
791 |
-
elif shape_type.lower() == "polygon":
|
792 |
-
polygon_geometry = locations_df.iloc[0]['geometry']
|
793 |
-
roi = convert_to_ee_geometry(polygon_geometry)
|
794 |
-
|
795 |
-
# Load the image collection
|
796 |
-
raw_collection = ee.ImageCollection(dataset_id) \
|
797 |
-
.filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \
|
798 |
-
.filterBounds(roi)
|
799 |
-
|
800 |
-
# Debug prints (properly indented)
|
801 |
-
st.write(f"Collection size: {raw_collection.size().getInfo()}")
|
802 |
-
st.write(f"Available bands: {raw_collection.first().bandNames().getInfo()}")
|
803 |
-
|
804 |
-
if raw_collection.size().getInfo() == 0:
|
805 |
-
st.warning("No images found for the selected date range and location.")
|
806 |
-
st.stop()
|
807 |
-
|
808 |
-
# Visualize cloud coverage
|
809 |
-
cloud_mask, cloud_vis = visualize_clouds(raw_collection, roi, cloud_band='QA60')
|
810 |
-
|
811 |
-
# Create a new map centered on the ROI
|
812 |
-
centroid = roi.centroid().coordinates().getInfo()
|
813 |
-
m = leafmap.Map(center=[centroid[1], centroid[0]], zoom=10)
|
814 |
-
|
815 |
-
# Add the layers using the proper Leafmap methods
|
816 |
-
m.add_layer(cloud_mask, cloud_vis, "Cloud Mask")
|
817 |
-
m.add_layer(roi, {'color': 'red'}, "Region of Interest")
|
818 |
-
|
819 |
-
st.write("Cloud Coverage Preview:")
|
820 |
-
m.to_streamlit()
|
821 |
-
except Exception as e:
|
822 |
-
st.error(f"Error visualizing cloud coverage: {str(e)}")
|
823 |
-
else:
|
824 |
-
st.warning("Please upload a valid file to proceed.")
|
825 |
-
|
826 |
-
# After visualizing cloud coverage
|
827 |
-
st.markdown("<h5>Adjust Cloud Threshold</h5>", unsafe_allow_html=True)
|
828 |
-
new_cloud_threshold = st.slider(
|
829 |
-
"Select Maximum Cloud Coverage Threshold (%)",
|
830 |
-
min_value=0,
|
831 |
-
max_value=50,
|
832 |
-
value=cloud_threshold, # Start with the current threshold
|
833 |
-
step=5,
|
834 |
-
help="Lower the threshold to exclude more cloudy images."
|
835 |
-
)
|
836 |
-
|
837 |
-
if st.button("Apply New Cloud Threshold"):
|
838 |
-
cloud_threshold = new_cloud_threshold
|
839 |
-
st.success(f"New cloud threshold applied: {cloud_threshold}%")
|
840 |
|
841 |
if st.button(f"Calculate {custom_formula}"):
|
842 |
if not locations_df.empty:
|
|
|
175 |
daily_images = ee.List(grouped_by_day.map(calculate_daily_mean))
|
176 |
return ee.ImageCollection(daily_images)
|
177 |
|
178 |
+
|
179 |
def aggregate_data_weekly(collection, start_date_str, end_date_str):
|
180 |
"""
|
181 |
Aggregates data on a weekly basis, starting from the exact start date provided by the user.
|
|
|
200 |
|
201 |
return ee.ImageCollection.fromImages(weekly_images)
|
202 |
|
203 |
+
|
204 |
def aggregate_data_monthly(collection, start_date, end_date):
|
205 |
collection = collection.filterDate(start_date, end_date)
|
206 |
collection = collection.map(lambda image: image.set('month', ee.Date(image.get('system:time_start')).format('YYYY-MM')))
|
|
|
212 |
monthly_images = ee.List(grouped_by_month.map(calculate_monthly_mean))
|
213 |
return ee.ImageCollection(monthly_images)
|
214 |
|
215 |
+
|
216 |
def aggregate_data_yearly(collection):
|
217 |
collection = collection.map(lambda image: image.set('year', ee.Date(image.get('system:time_start')).format('YYYY')))
|
218 |
grouped_by_year = collection.aggregate_array('year').distinct()
|
|
|
255 |
return 0 # Avoid division by zero
|
256 |
return ee.Number(cloudy_pixels).divide(ee.Number(total_pixels)).multiply(100).getInfo()
|
257 |
|
258 |
+
# Preprocessing function with cloud filtering
|
259 |
def preprocess_collection(collection, cloud_threshold):
|
260 |
"""
|
261 |
Apply cloud filtering to the image collection using the QA60 bitmask.
|
|
|
287 |
masked_collection = filtered_collection.map(mask_cloudy_pixels)
|
288 |
return masked_collection
|
289 |
|
290 |
+
# Worker function for processing a single geometry
|
291 |
+
def process_single_geometry(row, start_date_str, end_date_str, dataset_id, selected_bands, reducer_choice, shape_type, aggregation_period, custom_formula, original_lat_col, original_lon_col, kernel_size=None, include_boundary=None):
|
292 |
+
if shape_type.lower() == "point":
|
293 |
+
latitude = row.get('latitude')
|
294 |
+
longitude = row.get('longitude')
|
295 |
+
if pd.isna(latitude) or pd.isna(longitude):
|
296 |
+
return None # Skip invalid points
|
297 |
+
location_name = row.get('name', f"Location_{row.name}")
|
298 |
+
if kernel_size == "3x3 Kernel":
|
299 |
+
buffer_size = 45 # 90m x 90m
|
300 |
+
roi = ee.Geometry.Point([longitude, latitude]).buffer(buffer_size).bounds()
|
301 |
+
elif kernel_size == "5x5 Kernel":
|
302 |
+
buffer_size = 75 # 150m x 150m
|
303 |
+
roi = ee.Geometry.Point([longitude, latitude]).buffer(buffer_size).bounds()
|
304 |
+
else: # Point
|
305 |
+
roi = ee.Geometry.Point([longitude, latitude])
|
306 |
+
elif shape_type.lower() == "polygon":
|
307 |
+
polygon_geometry = row.get('geometry')
|
308 |
+
location_name = row.get('name', f"Polygon_{row.name}")
|
309 |
+
try:
|
310 |
roi = convert_to_ee_geometry(polygon_geometry)
|
311 |
if not include_boundary:
|
312 |
roi = roi.buffer(-30).bounds()
|
313 |
+
except ValueError:
|
314 |
+
return None # Skip invalid polygons
|
315 |
|
316 |
+
# Filter and aggregate the image collection
|
317 |
+
collection = ee.ImageCollection(dataset_id) \
|
318 |
+
.filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \
|
319 |
+
.filterBounds(roi)
|
320 |
+
|
321 |
+
if aggregation_period.lower() == 'custom (start date to end date)':
|
322 |
+
collection = aggregate_data_custom(collection)
|
323 |
+
elif aggregation_period.lower() == 'daily':
|
324 |
+
collection = aggregate_data_daily(collection)
|
325 |
+
elif aggregation_period.lower() == 'weekly':
|
326 |
+
collection = aggregate_data_weekly(collection, start_date_str, end_date_str)
|
327 |
+
elif aggregation_period.lower() == 'monthly':
|
328 |
+
collection = aggregate_data_monthly(collection, start_date_str, end_date_str)
|
329 |
+
elif aggregation_period.lower() == 'yearly':
|
330 |
+
collection = aggregate_data_yearly(collection)
|
331 |
+
|
332 |
+
# Process each image in the collection
|
333 |
+
image_list = collection.toList(collection.size())
|
334 |
+
processed_weeks = set()
|
335 |
+
aggregated_results = []
|
336 |
+
for i in range(image_list.size().getInfo()):
|
337 |
+
image = ee.Image(image_list.get(i))
|
338 |
if aggregation_period.lower() == 'custom (start date to end date)':
|
339 |
+
timestamp = image.get('day')
|
340 |
+
period_label = 'Date'
|
341 |
+
date = ee.Date(timestamp).format('YYYY-MM-dd').getInfo()
|
342 |
elif aggregation_period.lower() == 'daily':
|
343 |
+
timestamp = image.get('day_start')
|
344 |
+
period_label = 'Date'
|
345 |
+
date = ee.String(timestamp).getInfo()
|
346 |
elif aggregation_period.lower() == 'weekly':
|
347 |
+
timestamp = image.get('week_start')
|
348 |
+
period_label = 'Week'
|
349 |
+
date = ee.String(timestamp).getInfo()
|
350 |
+
if (pd.to_datetime(date) < pd.to_datetime(start_date_str) or
|
351 |
+
pd.to_datetime(date) > pd.to_datetime(end_date_str) or
|
352 |
+
date in processed_weeks):
|
353 |
+
continue
|
354 |
+
processed_weeks.add(date)
|
355 |
elif aggregation_period.lower() == 'monthly':
|
356 |
+
timestamp = image.get('month')
|
357 |
+
period_label = 'Month'
|
358 |
+
date = ee.Date(timestamp).format('YYYY-MM').getInfo()
|
359 |
elif aggregation_period.lower() == 'yearly':
|
360 |
+
timestamp = image.get('year')
|
361 |
+
period_label = 'Year'
|
362 |
+
date = ee.Date(timestamp).format('YYYY').getInfo()
|
363 |
|
364 |
+
index_image = calculate_custom_formula(image, roi, selected_bands, custom_formula, reducer_choice, scale=30)
|
365 |
+
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
366 |
index_value = index_image.reduceRegion(
|
367 |
reducer=get_reducer(reducer_choice),
|
368 |
geometry=roi,
|
369 |
scale=30
|
370 |
+
).get('custom_result')
|
371 |
+
calculated_value = index_value.getInfo()
|
372 |
+
if isinstance(calculated_value, (int, float)):
|
373 |
result = {
|
374 |
'Location Name': location_name,
|
375 |
period_label: date,
|
376 |
'Start Date': start_date_str,
|
377 |
'End Date': end_date_str,
|
378 |
+
'Calculated Value': calculated_value
|
379 |
}
|
380 |
if shape_type.lower() == 'point':
|
381 |
+
result[original_lat_col] = latitude # Use original column name
|
382 |
+
result[original_lon_col] = longitude # Use original column name
|
383 |
aggregated_results.append(result)
|
384 |
+
except Exception as e:
|
385 |
+
st.error(f"Error retrieving value for {location_name}: {e}")
|
386 |
+
return aggregated_results
|
387 |
+
|
|
|
|
|
388 |
|
389 |
+
# Main processing function
|
390 |
def process_aggregation(locations_df, start_date_str, end_date_str, dataset_id, selected_bands, reducer_choice, shape_type, aggregation_period, original_lat_col, original_lon_col, custom_formula="", kernel_size=None, include_boundary=None, cloud_threshold=0):
|
391 |
aggregated_results = []
|
392 |
total_steps = len(locations_df)
|
|
|
394 |
progress_text = st.empty()
|
395 |
start_time = time.time() # Start timing the process
|
396 |
|
397 |
+
# Preprocess the image collection with cloud filtering
|
398 |
+
raw_collection = ee.ImageCollection(dataset_id) \
|
399 |
+
.filterDate(ee.Date(start_date_str), ee.Date(end_date_str))
|
400 |
+
|
401 |
+
# Print the size of the original collection
|
402 |
+
st.write(f"Original Collection Size: {raw_collection.size().getInfo()}")
|
403 |
+
|
404 |
+
# Apply cloud filtering if threshold > 0
|
405 |
+
if cloud_threshold > 0:
|
406 |
+
raw_collection = preprocess_collection(raw_collection, cloud_threshold)
|
407 |
+
|
408 |
+
# Print the size of the preprocessed collection
|
409 |
+
st.write(f"Preprocessed Collection Size: {raw_collection.size().getInfo()}")
|
410 |
+
|
411 |
with ThreadPoolExecutor(max_workers=10) as executor:
|
412 |
futures = []
|
413 |
for idx, row in locations_df.iterrows():
|
|
|
425 |
original_lat_col,
|
426 |
original_lon_col,
|
427 |
kernel_size,
|
428 |
+
include_boundary
|
|
|
429 |
)
|
430 |
futures.append(future)
|
431 |
completed = 0
|
|
|
449 |
'Start Date': 'first',
|
450 |
'End Date': 'first',
|
451 |
'Calculated Value': 'mean'
|
452 |
+
# 'Date Range': 'first' # Include Date Range in aggregation
|
453 |
}
|
454 |
if shape_type.lower() == 'point':
|
455 |
agg_dict[original_lat_col] = 'first'
|
|
|
593 |
help="Tiles with cloud coverage exceeding this threshold will be excluded. Individual cloudy pixels will also be masked."
|
594 |
)
|
595 |
|
596 |
+
|
597 |
aggregation_period = st.selectbox(
|
598 |
"Select Aggregation Period (e.g, Custom(Start Date to End Date) , Daily , Weekly , Monthly , Yearly)",
|
599 |
["Custom (Start Date to End Date)", "Daily", "Weekly", "Monthly", "Yearly"],
|
|
|
746 |
st.write("Map of Uploaded Polygons:")
|
747 |
m.to_streamlit()
|
748 |
|
749 |
+
# if st.button(f"Calculate {custom_formula}"):
|
750 |
+
# if not locations_df.empty:
|
751 |
+
# with st.spinner("Processing Data..."):
|
752 |
+
# try:
|
753 |
+
# results, processing_time = process_aggregation(
|
754 |
+
# locations_df,
|
755 |
+
# start_date_str,
|
756 |
+
# end_date_str,
|
757 |
+
# dataset_id,
|
758 |
+
# selected_bands,
|
759 |
+
# reducer_choice,
|
760 |
+
# shape_type,
|
761 |
+
# aggregation_period,
|
762 |
+
# original_lat_col,
|
763 |
+
# original_lon_col,
|
764 |
+
# custom_formula,
|
765 |
+
# kernel_size,
|
766 |
+
# include_boundary
|
767 |
+
# )
|
768 |
+
# if results:
|
769 |
+
# result_df = pd.DataFrame(results)
|
770 |
+
# st.write(f"Processed Results Table ({aggregation_period}) for Formula: {custom_formula}")
|
771 |
+
# st.dataframe(result_df)
|
772 |
+
# filename = f"{main_selection}_{dataset_id}_{start_date.strftime('%Y%m%d')}_{end_date.strftime('%Y%m%d')}_{aggregation_period.lower()}.csv"
|
773 |
+
# st.download_button(
|
774 |
+
# label="Download results as CSV",
|
775 |
+
# data=result_df.to_csv(index=False).encode('utf-8'),
|
776 |
+
# file_name=filename,
|
777 |
+
# mime='text/csv'
|
778 |
+
# )
|
779 |
+
# st.success(f"Processing complete! Total processing time: {processing_time:.2f} seconds.")
|
780 |
+
# else:
|
781 |
+
# st.warning("No results were generated. Check your inputs or formula.")
|
782 |
+
# st.info(f"Total processing time: {processing_time:.2f} seconds.")
|
783 |
+
# except Exception as e:
|
784 |
+
# st.error(f"An error occurred during processing: {str(e)}")
|
785 |
+
# else:
|
786 |
+
# st.warning("Please upload a valid file to proceed.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
787 |
|
788 |
if st.button(f"Calculate {custom_formula}"):
|
789 |
if not locations_df.empty:
|