update app.py
Browse files
app.py
CHANGED
@@ -87,13 +87,6 @@ elif index_choice.lower() == 'custom formula':
|
|
87 |
custom_formula = st.text_input("Enter Custom Formula (e.g., '(B5 - B4) / (B5 + B4)')")
|
88 |
st.write(f"Custom Formula: {custom_formula}") # Display the custom formula after the user inputs it
|
89 |
|
90 |
-
# Reducer selection
|
91 |
-
reducer_choice = st.selectbox(
|
92 |
-
"Select Reducer",
|
93 |
-
['mean', 'sum', 'median', 'min', 'max', 'count'],
|
94 |
-
index=0 # Default to 'mean'
|
95 |
-
)
|
96 |
-
|
97 |
# Function to check if the polygon geometry is valid and convert it to the correct format
|
98 |
def convert_to_ee_geometry(geometry):
|
99 |
if geometry.is_valid:
|
@@ -164,29 +157,6 @@ if parameters_changed():
|
|
164 |
'file_upload': file_upload
|
165 |
}
|
166 |
|
167 |
-
# Function to get the corresponding reducer based on user input
|
168 |
-
def get_reducer(reducer_name):
|
169 |
-
"""
|
170 |
-
Map user-friendly reducer names to Earth Engine reducer objects.
|
171 |
-
|
172 |
-
Args:
|
173 |
-
reducer_name (str): The name of the reducer (e.g., 'mean', 'sum', 'median').
|
174 |
-
|
175 |
-
Returns:
|
176 |
-
ee.Reducer: The corresponding Earth Engine reducer.
|
177 |
-
"""
|
178 |
-
reducers = {
|
179 |
-
'mean': ee.Reducer.mean(),
|
180 |
-
'sum': ee.Reducer.sum(),
|
181 |
-
'median': ee.Reducer.median(),
|
182 |
-
'min': ee.Reducer.min(),
|
183 |
-
'max': ee.Reducer.max(),
|
184 |
-
'count': ee.Reducer.count(),
|
185 |
-
}
|
186 |
-
|
187 |
-
# Default to 'mean' if the reducer_name is not recognized
|
188 |
-
return reducers.get(reducer_name.lower(), ee.Reducer.mean())
|
189 |
-
|
190 |
# Function to perform index calculations
|
191 |
def calculate_ndvi(image, geometry):
|
192 |
ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI')
|
@@ -253,19 +223,22 @@ def get_most_recent_image(image_collection):
|
|
253 |
# Function to handle the custom formula choice and calculation
|
254 |
def process_custom_formula(image, roi, custom_formula):
|
255 |
if custom_formula:
|
|
|
256 |
result = calculate_custom_formula(image, roi, custom_formula)
|
257 |
if result:
|
258 |
-
|
|
|
|
|
|
|
|
|
|
|
259 |
return None
|
260 |
|
261 |
-
locations_df = None # Initialize locations_df to None
|
262 |
-
polygons_df = None # Ensure polygons_df is initialized at the beginning
|
263 |
-
|
264 |
# Process each point (with additional checks for file validity)
|
265 |
# Check the shape type and assign polygons_df only for Polygon data
|
266 |
if file_upload:
|
267 |
-
|
268 |
-
|
269 |
|
270 |
file_extension = os.path.splitext(file_upload.name)[1].lower()
|
271 |
|
@@ -336,8 +309,6 @@ if file_upload:
|
|
336 |
.filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \
|
337 |
.filterBounds(roi)
|
338 |
|
339 |
-
# # Apply frequency-based filtering and reduction
|
340 |
-
# result, result_date = calculate_index_by_frequency(collection, frequency_choice, roi, reducer)
|
341 |
image = get_most_recent_image(collection)
|
342 |
if not image:
|
343 |
st.warning(f"No images found for {location_name}.")
|
@@ -380,85 +351,90 @@ if file_upload:
|
|
380 |
'Latitude': latitude,
|
381 |
'Longitude': longitude,
|
382 |
'Calculated Value': calculated_value
|
383 |
-
# 'Date': result_date # Add the date of the calculation
|
384 |
})
|
385 |
else:
|
386 |
st.warning(f"No value calculated for {location_name}.")
|
387 |
else:
|
388 |
st.warning(f"No value calculated for {location_name}.")
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
result =
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
462 |
|
463 |
|
464 |
# After processing, show the results
|
@@ -479,5 +455,4 @@ if st.session_state.results:
|
|
479 |
data=result_df.to_csv(index=False).encode('utf-8'),
|
480 |
file_name=filename,
|
481 |
mime='text/csv'
|
482 |
-
)
|
483 |
-
|
|
|
87 |
custom_formula = st.text_input("Enter Custom Formula (e.g., '(B5 - B4) / (B5 + B4)')")
|
88 |
st.write(f"Custom Formula: {custom_formula}") # Display the custom formula after the user inputs it
|
89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
# Function to check if the polygon geometry is valid and convert it to the correct format
|
91 |
def convert_to_ee_geometry(geometry):
|
92 |
if geometry.is_valid:
|
|
|
157 |
'file_upload': file_upload
|
158 |
}
|
159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
# Function to perform index calculations
|
161 |
def calculate_ndvi(image, geometry):
|
162 |
ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI')
|
|
|
223 |
# Function to handle the custom formula choice and calculation
|
224 |
def process_custom_formula(image, roi, custom_formula):
|
225 |
if custom_formula:
|
226 |
+
# Call the calculate_custom_formula function which processes the custom formula
|
227 |
result = calculate_custom_formula(image, roi, custom_formula)
|
228 |
if result:
|
229 |
+
# If result is a dictionary (which is likely for custom formula), extract the value
|
230 |
+
if isinstance(result, dict) and 'CustomResult' in result:
|
231 |
+
return result['CustomResult'] # Directly return the value from the dictionary
|
232 |
+
# Otherwise, it's an Earth Engine object, so we get the value with getInfo()
|
233 |
+
else:
|
234 |
+
return result.getInfo() # Return the result for an Earth Engine object
|
235 |
return None
|
236 |
|
|
|
|
|
|
|
237 |
# Process each point (with additional checks for file validity)
|
238 |
# Check the shape type and assign polygons_df only for Polygon data
|
239 |
if file_upload:
|
240 |
+
locations_df = None # Initialize locations_df to None
|
241 |
+
polygons_df = None # Ensure polygons_df is initialized at the beginning
|
242 |
|
243 |
file_extension = os.path.splitext(file_upload.name)[1].lower()
|
244 |
|
|
|
309 |
.filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \
|
310 |
.filterBounds(roi)
|
311 |
|
|
|
|
|
312 |
image = get_most_recent_image(collection)
|
313 |
if not image:
|
314 |
st.warning(f"No images found for {location_name}.")
|
|
|
351 |
'Latitude': latitude,
|
352 |
'Longitude': longitude,
|
353 |
'Calculated Value': calculated_value
|
|
|
354 |
})
|
355 |
else:
|
356 |
st.warning(f"No value calculated for {location_name}.")
|
357 |
else:
|
358 |
st.warning(f"No value calculated for {location_name}.")
|
359 |
+
|
360 |
+
|
361 |
+
# Ensure st.session_state.results is initialized
|
362 |
+
if 'results' not in st.session_state:
|
363 |
+
st.session_state.results = []
|
364 |
+
|
365 |
+
# Check if polygons_df is populated for polygons
|
366 |
+
if polygons_df is not None and not polygons_df.empty:
|
367 |
+
st.write("Preview of the uploaded polygons data:")
|
368 |
+
st.dataframe(polygons_df.head())
|
369 |
+
|
370 |
+
# Initialize map and display polygons
|
371 |
+
m = leafmap.Map(center=[polygons_df.geometry.centroid.y.mean(), polygons_df.geometry.centroid.x.mean()], zoom=10)
|
372 |
+
for _, row in polygons_df.iterrows():
|
373 |
+
polygon = row['geometry']
|
374 |
+
if polygon.is_valid:
|
375 |
+
gdf = gpd.GeoDataFrame([row], geometry=[polygon], crs=polygons_df.crs)
|
376 |
+
m.add_gdf(gdf=gdf, layer_name=row.get('name', 'Unnamed Polygon'))
|
377 |
+
|
378 |
+
st.write("Map of Uploaded Polygons:")
|
379 |
+
m.to_streamlit()
|
380 |
+
st.session_state.map_data = m
|
381 |
+
|
382 |
+
# Process each polygon
|
383 |
+
for idx, row in polygons_df.iterrows():
|
384 |
+
polygon = row['geometry']
|
385 |
+
location_name = row.get('name', f"Polygon_{idx}")
|
386 |
+
|
387 |
+
try:
|
388 |
+
roi = convert_to_ee_geometry(polygon) # Convert to EE Geometry
|
389 |
+
except ValueError as e:
|
390 |
+
st.error(f"Error converting polygon {location_name}: {str(e)}")
|
391 |
+
continue
|
392 |
+
|
393 |
+
# Fetch image collection
|
394 |
+
collection = ee.ImageCollection(sub_options[sub_selection]) \
|
395 |
+
.filterDate(ee.Date(start_date_str), ee.Date(end_date_str)) \
|
396 |
+
.filterBounds(roi)
|
397 |
+
|
398 |
+
image = get_most_recent_image(collection)
|
399 |
+
|
400 |
+
if not image:
|
401 |
+
st.warning(f"No images found for {location_name}.")
|
402 |
+
else:
|
403 |
+
st.write(f"Found an image for {location_name}.")
|
404 |
+
result = None
|
405 |
+
|
406 |
+
# Calculate index based on user's choice
|
407 |
+
if index_choice.lower() == 'NDVI':
|
408 |
+
result = calculate_ndvi(image, roi)
|
409 |
+
elif index_choice.lower() == 'NDWI':
|
410 |
+
result = calculate_ndwi(image, roi)
|
411 |
+
elif index_choice.lower() == 'Average NO₂':
|
412 |
+
if 'NO2' in image.bandNames().getInfo():
|
413 |
+
result = calculate_avg_no2_sentinel5p(image, roi)
|
414 |
+
else:
|
415 |
+
st.warning(f"No NO2 band found for {location_name}. Please use Sentinel-5P for NO₂ data.")
|
416 |
+
elif index_choice.lower() == 'custom formula' and custom_formula:
|
417 |
+
result = process_custom_formula(image, roi, custom_formula)
|
418 |
+
|
419 |
+
# Ensure result is properly extracted and displayed
|
420 |
+
if result is not None:
|
421 |
+
calculated_value = None
|
422 |
+
|
423 |
+
if isinstance(result, ee.Dictionary):
|
424 |
+
# Extract the numeric value for custom formula results
|
425 |
+
calculated_value = result.get('constant').getInfo()
|
426 |
+
elif isinstance(result, ee.Number):
|
427 |
+
# Direct numeric result
|
428 |
+
calculated_value = result.getInfo()
|
429 |
+
|
430 |
+
if calculated_value is not None:
|
431 |
+
st.write(f"Calculated {index_choice.upper()} for {location_name}: {calculated_value}")
|
432 |
+
st.session_state.results.append({
|
433 |
+
'Location Name': location_name,
|
434 |
+
'Calculated Value': calculated_value
|
435 |
+
})
|
436 |
+
else:
|
437 |
+
st.error(f"Error extracting the result for {location_name}.")
|
438 |
|
439 |
|
440 |
# After processing, show the results
|
|
|
455 |
data=result_df.to_csv(index=False).encode('utf-8'),
|
456 |
file_name=filename,
|
457 |
mime='text/csv'
|
458 |
+
)
|
|