YashMK89 commited on
Commit
64eee83
·
verified ·
1 Parent(s): 23a1500

update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -19
app.py CHANGED
@@ -106,34 +106,59 @@ def convert_to_ee_geometry(geometry):
106
  else:
107
  raise ValueError("Unsupported geometry input type. Supported types are Shapely, GeoJSON, and KML.")
108
 
109
- # Function to calculate custom formula
110
  def calculate_custom_formula(image, geometry, selected_bands, custom_formula, reducer_choice, dataset_id, user_scale=None):
111
  try:
112
- # Determine the scale: Use user-defined scale if provided, otherwise use dataset's native resolution
113
- default_scale = ee.ImageCollection(dataset_id).first().select(0).projection().nominalScale().getInfo()
 
 
 
 
 
 
 
 
114
  scale = user_scale if user_scale is not None else default_scale
115
- band_values = {}
116
- band_names = image.bandNames().getInfo()
 
117
  for band in selected_bands:
118
- if band not in band_names:
119
- raise ValueError(f"Band '{band}' not found in the dataset.")
120
- band_values[band] = image.select(band)
121
- reducer = get_reducer(reducer_choice)
 
 
 
 
 
 
 
 
 
122
  reduced_values = {}
 
123
  for band in selected_bands:
124
- value = band_values[band].reduceRegion(
125
  reducer=reducer,
126
  geometry=geometry,
127
- scale=scale
128
  ).get(band).getInfo()
129
  reduced_values[band] = float(value if value is not None else 0)
 
 
130
  formula = custom_formula
131
  for band in selected_bands:
132
  formula = formula.replace(band, str(reduced_values[band]))
133
  result = eval(formula, {"__builtins__": {}}, reduced_values)
 
 
134
  if not isinstance(result, (int, float)):
135
  raise ValueError("Formula did not result in a numeric value.")
 
136
  return ee.Image.constant(result).rename('custom_result')
 
137
  except ZeroDivisionError:
138
  st.error("Error: Division by zero in the formula.")
139
  return ee.Image(0).rename('custom_result').set('error', 'Division by zero')
@@ -438,7 +463,6 @@ elif imagery_base == "Custom Input":
438
  if not data:
439
  st.error("No valid dataset available. Please check your inputs.")
440
  st.stop()
441
-
442
  st.markdown("<hr><h5><b>{}</b></h5>".format(imagery_base), unsafe_allow_html=True)
443
  main_selection = st.selectbox(f"Select {imagery_base} Dataset Category", list(data.keys()))
444
  sub_selection = None
@@ -450,7 +474,6 @@ if main_selection:
450
  st.write(f"You selected: {main_selection} -> {sub_options[sub_selection]}")
451
  st.write(f"Dataset ID: {sub_selection}")
452
  dataset_id = sub_selection
453
-
454
  st.markdown("<hr><h5><b>Earth Engine Index Calculator</b></h5>", unsafe_allow_html=True)
455
  if main_selection and sub_selection:
456
  dataset_bands = data[main_selection]["bands"].get(sub_selection, [])
@@ -493,7 +516,6 @@ if main_selection and sub_selection:
493
  st.warning("Please enter a custom formula to proceed.")
494
  st.stop()
495
  st.write(f"Custom Formula: {custom_formula}")
496
-
497
  reducer_choice = st.selectbox(
498
  "Select Reducer (e.g, mean , sum , median , min , max , count)",
499
  ['mean', 'sum', 'median', 'min', 'max', 'count'],
@@ -503,7 +525,6 @@ start_date = st.date_input("Start Date", value=pd.to_datetime('2024-11-01'))
503
  end_date = st.date_input("End Date", value=pd.to_datetime('2024-12-01'))
504
  start_date_str = start_date.strftime('%Y-%m-%d')
505
  end_date_str = end_date.strftime('%Y-%m-%d')
506
-
507
  if imagery_base == "Sentinel" and "Sentinel-2" in sub_options[sub_selection]:
508
  st.markdown("<h5>Cloud Filtering</h5>", unsafe_allow_html=True)
509
  tile_cloud_threshold = st.slider(
@@ -522,7 +543,6 @@ if imagery_base == "Sentinel" and "Sentinel-2" in sub_options[sub_selection]:
522
  step=5,
523
  help="Individual pixels with cloud coverage exceeding this threshold will be masked."
524
  )
525
-
526
  aggregation_period = st.selectbox(
527
  "Select Aggregation Period (e.g, Custom(Start Date to End Date) , Daily , Weekly , Monthly , Yearly)",
528
  ["Custom (Start Date to End Date)", "Daily", "Weekly", "Monthly", "Yearly"],
@@ -544,7 +564,6 @@ elif shape_type.lower() == "polygon":
544
  value=True,
545
  help="Check to include pixels on the polygon boundary; uncheck to exclude them."
546
  )
547
-
548
  st.markdown("<h5>Calculation Scale</h5>", unsafe_allow_html=True)
549
  default_scale = ee.ImageCollection(dataset_id).first().select(0).projection().nominalScale().getInfo()
550
  user_scale = st.number_input(
@@ -553,7 +572,6 @@ user_scale = st.number_input(
553
  value=float(default_scale),
554
  help=f"Default scale for this dataset is {default_scale} meters. Adjust if needed."
555
  )
556
-
557
  file_upload = st.file_uploader(f"Upload your {shape_type} data (CSV, GeoJSON, KML)", type=["csv", "geojson", "kml"])
558
  locations_df = pd.DataFrame()
559
  original_lat_col = None
@@ -672,7 +690,6 @@ if file_upload is not None:
672
  m.add_gdf(gdf=gdf, layer_name=row.get('name', 'Unnamed Polygon'))
673
  st.write("Map of Uploaded Polygons:")
674
  m.to_streamlit()
675
-
676
  if st.button(f"Calculate {custom_formula}"):
677
  if not locations_df.empty:
678
  with st.spinner("Processing Data..."):
 
106
  else:
107
  raise ValueError("Unsupported geometry input type. Supported types are Shapely, GeoJSON, and KML.")
108
 
109
+ # Function to calculate custom formula with dynamic scale handling and normalization
110
  def calculate_custom_formula(image, geometry, selected_bands, custom_formula, reducer_choice, dataset_id, user_scale=None):
111
  try:
112
+ # Fetch the nominal scales of the selected bands
113
+ band_scales = []
114
+ for band in selected_bands:
115
+ band_scale = image.select(band).projection().nominalScale().getInfo()
116
+ band_scales.append(band_scale)
117
+
118
+ # Determine the finest (smallest) scale among the selected bands
119
+ default_scale = min(band_scales) if band_scales else 30 # Default to 30m if no bands are found
120
+
121
+ # Use user-defined scale if provided, otherwise use the finest scale
122
  scale = user_scale if user_scale is not None else default_scale
123
+
124
+ # Rescale all bands to the chosen scale
125
+ rescaled_bands = {}
126
  for band in selected_bands:
127
+ band_image = image.select(band)
128
+ band_scale = band_image.projection().nominalScale().getInfo()
129
+ if band_scale != scale:
130
+ # Resample the band to match the target scale
131
+ rescaled_band = band_image.resample('bilinear').reproject(
132
+ crs=band_image.projection().crs(),
133
+ scale=scale
134
+ )
135
+ rescaled_bands[band] = rescaled_band
136
+ else:
137
+ rescaled_bands[band] = band_image
138
+
139
+ # Validate and extract band values
140
  reduced_values = {}
141
+ reducer = get_reducer(reducer_choice)
142
  for band in selected_bands:
143
+ value = rescaled_bands[band].reduceRegion(
144
  reducer=reducer,
145
  geometry=geometry,
146
+ scale=scale # Use the determined scale here
147
  ).get(band).getInfo()
148
  reduced_values[band] = float(value if value is not None else 0)
149
+
150
+ # Evaluate the custom formula
151
  formula = custom_formula
152
  for band in selected_bands:
153
  formula = formula.replace(band, str(reduced_values[band]))
154
  result = eval(formula, {"__builtins__": {}}, reduced_values)
155
+
156
+ # Validate the result
157
  if not isinstance(result, (int, float)):
158
  raise ValueError("Formula did not result in a numeric value.")
159
+
160
  return ee.Image.constant(result).rename('custom_result')
161
+
162
  except ZeroDivisionError:
163
  st.error("Error: Division by zero in the formula.")
164
  return ee.Image(0).rename('custom_result').set('error', 'Division by zero')
 
463
  if not data:
464
  st.error("No valid dataset available. Please check your inputs.")
465
  st.stop()
 
466
  st.markdown("<hr><h5><b>{}</b></h5>".format(imagery_base), unsafe_allow_html=True)
467
  main_selection = st.selectbox(f"Select {imagery_base} Dataset Category", list(data.keys()))
468
  sub_selection = None
 
474
  st.write(f"You selected: {main_selection} -> {sub_options[sub_selection]}")
475
  st.write(f"Dataset ID: {sub_selection}")
476
  dataset_id = sub_selection
 
477
  st.markdown("<hr><h5><b>Earth Engine Index Calculator</b></h5>", unsafe_allow_html=True)
478
  if main_selection and sub_selection:
479
  dataset_bands = data[main_selection]["bands"].get(sub_selection, [])
 
516
  st.warning("Please enter a custom formula to proceed.")
517
  st.stop()
518
  st.write(f"Custom Formula: {custom_formula}")
 
519
  reducer_choice = st.selectbox(
520
  "Select Reducer (e.g, mean , sum , median , min , max , count)",
521
  ['mean', 'sum', 'median', 'min', 'max', 'count'],
 
525
  end_date = st.date_input("End Date", value=pd.to_datetime('2024-12-01'))
526
  start_date_str = start_date.strftime('%Y-%m-%d')
527
  end_date_str = end_date.strftime('%Y-%m-%d')
 
528
  if imagery_base == "Sentinel" and "Sentinel-2" in sub_options[sub_selection]:
529
  st.markdown("<h5>Cloud Filtering</h5>", unsafe_allow_html=True)
530
  tile_cloud_threshold = st.slider(
 
543
  step=5,
544
  help="Individual pixels with cloud coverage exceeding this threshold will be masked."
545
  )
 
546
  aggregation_period = st.selectbox(
547
  "Select Aggregation Period (e.g, Custom(Start Date to End Date) , Daily , Weekly , Monthly , Yearly)",
548
  ["Custom (Start Date to End Date)", "Daily", "Weekly", "Monthly", "Yearly"],
 
564
  value=True,
565
  help="Check to include pixels on the polygon boundary; uncheck to exclude them."
566
  )
 
567
  st.markdown("<h5>Calculation Scale</h5>", unsafe_allow_html=True)
568
  default_scale = ee.ImageCollection(dataset_id).first().select(0).projection().nominalScale().getInfo()
569
  user_scale = st.number_input(
 
572
  value=float(default_scale),
573
  help=f"Default scale for this dataset is {default_scale} meters. Adjust if needed."
574
  )
 
575
  file_upload = st.file_uploader(f"Upload your {shape_type} data (CSV, GeoJSON, KML)", type=["csv", "geojson", "kml"])
576
  locations_df = pd.DataFrame()
577
  original_lat_col = None
 
690
  m.add_gdf(gdf=gdf, layer_name=row.get('name', 'Unnamed Polygon'))
691
  st.write("Map of Uploaded Polygons:")
692
  m.to_streamlit()
 
693
  if st.button(f"Calculate {custom_formula}"):
694
  if not locations_df.empty:
695
  with st.spinner("Processing Data..."):