Zeel commited on
Commit
522f037
1 Parent(s): b673a1f

Yearly variant

Browse files
Files changed (2) hide show
  1. app.py +48 -17
  2. sandbox.ipynb +74 -4
app.py CHANGED
@@ -1,8 +1,10 @@
1
  import os
 
2
  import ee
3
  import json
4
  import geojson
5
  import geemap
 
6
  import geemap.foliumap as gee_folium
7
  import leafmap.foliumap as leaf_folium
8
  import streamlit as st
@@ -36,11 +38,15 @@ def calculate_ndvi(image, nir_band, red_band):
36
  ndvi = (nir.subtract(red)).divide(nir.add(red)).rename("NDVI")
37
  return image.addBands(ndvi)
38
 
39
- def process_date(start_date, end_date, satellite):
40
  try:
41
  attrs = satellites[satellite]
42
  collection = attrs["collection"]
43
  collection = collection.filterBounds(ee_geometry)
 
 
 
 
44
  collection = collection.filterDate(start_date, end_date)
45
  mosaic = collection.qualityMosaic("NDVI")
46
  fc = geemap.zonal_stats(
@@ -169,12 +175,11 @@ st.markdown(
169
 
170
  # Input: Date and Cloud Cover
171
  col = st.columns(4)
172
- start_year = col[0].selectbox("Start Year", list(range(2014, 2027)), index=8)
173
- start_month = col[1].selectbox("Start Month", list(range(1, 13)), index=0)
174
- end_year = col[2].selectbox("End Year", list(range(2014, 2027)), index=8)
175
- end_month = col[3].selectbox("End Month", list(range(1, 13)), index=2)
176
- start_date = f"{start_year}-{start_month:02d}"
177
- end_date = f"{end_year}-{end_month:02d}"
178
 
179
  # Input: GeoJSON/KML file
180
  uploaded_file = st.file_uploader("Upload KML/GeoJSON file", type=["geojson", "kml"])
@@ -185,8 +190,8 @@ gdf = preprocess_gdf(gpd.read_file(uploaded_file))
185
 
186
  # Input: Geometry
187
  selected_geometry = st.selectbox("Select the geometry", gdf.Name.values)
188
-
189
- selected_geometry = gdf[gdf.Name == selected_geometry].iloc[0].geometry
190
  if selected_geometry.type != "Polygon":
191
  st.error(
192
  f"Selected geometry is of type {selected_geometry.type}. Please provide a polygon geometry."
@@ -196,8 +201,25 @@ if selected_geometry.type != "Polygon":
196
  # Derived Inputs
197
  selected_geometry = selected_geometry.__geo_interface__
198
  ee_geometry = ee.Geometry(selected_geometry)
 
 
199
  ee_feature_collection = ee.FeatureCollection(ee_geometry)
200
  feature_collection = geojson.FeatureCollection([{"type": "Feature", "geometry": selected_geometry, "properties": {"name": "Selected Geometry"}}])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
  # visualize the geometry
203
  m = leaf_folium.Map()
@@ -208,6 +230,11 @@ m.add_geojson(feature_collection)
208
  write_info(f"Visual Esri Wayback Basemap - {latest_date}")
209
  m.to_streamlit()
210
 
 
 
 
 
 
211
 
212
  # Input: Satellite Sources
213
  st.write("Select the satellite sources:")
@@ -223,7 +250,10 @@ if submit:
223
  st.stop()
224
 
225
  # Create month range
226
- dates = pd.date_range(start_date, end_date, freq="MS").strftime("%Y-%m").tolist()
 
 
 
227
  write_info(
228
  f"Start Date (inclusive): {start_date}, End Date (exclusive): {end_date}"
229
  )
@@ -234,14 +264,14 @@ if submit:
234
 
235
  with st.spinner(f"Processing {satellite} ..."):
236
  progress_bar = st.progress(0)
237
- for i, (start, end) in enumerate(zip(dates[:-1], dates[1:])):
238
- mosaic, mean_ndvi, cloud_proba = process_date(start, end, satellite)
239
- result[satellite][start] = {
240
  "mosaic": mosaic,
241
  "mean_ndvi": mean_ndvi,
242
  "cloud_mask_probability": cloud_proba,
243
  }
244
- progress_bar.progress((i + 1) / (len(dates) - 1))
245
 
246
  st.session_state.result = result
247
 
@@ -279,14 +309,15 @@ if "result" in st.session_state:
279
 
280
  df_numeric = df.select_dtypes(include=["float64"])
281
  st.write(df_numeric)
 
 
 
282
 
283
- fig = px.line(df, y=df_numeric.columns, title="Mean NDVI", markers=True)
284
  fig.update_yaxes(range=[-0.2, 1])
285
  st.plotly_chart(fig)
286
 
287
  st.subheader("Visual Inspection")
288
- _, lonlat = ee_geometry.centroid().getInfo().values()
289
- lon, lat = lonlat
290
  write_info(f"Centroid of the selected geometry (lat, lon): ({lat}, {lon})")
291
  cols = st.columns(2)
292
  df_dates = df.index.strftime("%Y-%m").tolist()
 
1
  import os
2
+ import utm
3
  import ee
4
  import json
5
  import geojson
6
  import geemap
7
+ import numpy as np
8
  import geemap.foliumap as gee_folium
9
  import leafmap.foliumap as leaf_folium
10
  import streamlit as st
 
38
  ndvi = (nir.subtract(red)).divide(nir.add(red)).rename("NDVI")
39
  return image.addBands(ndvi)
40
 
41
+ def process_date(date, satellite):
42
  try:
43
  attrs = satellites[satellite]
44
  collection = attrs["collection"]
45
  collection = collection.filterBounds(ee_geometry)
46
+ str_start_date = date+"-01"
47
+ start_date = pd.to_datetime(str_start_date)
48
+ end_date = start_date + pd.DateOffset(months=1)
49
+ write_info(f"Processing {satellite} - {start_date} to {end_date}")
50
  collection = collection.filterDate(start_date, end_date)
51
  mosaic = collection.qualityMosaic("NDVI")
52
  fc = geemap.zonal_stats(
 
175
 
176
  # Input: Date and Cloud Cover
177
  col = st.columns(4)
178
+ month_of_interest = col[0].selectbox("Month of Interest", list(range(1, 13)), index=11)
179
+ start_year = col[1].selectbox("Start Year", list(range(2014, 2027)), index=6)
180
+ end_year = col[2].selectbox("End Year", list(range(2014, 2027)), index=9) + 1
181
+ start_date = f"{start_year}-{month_of_interest:02d}"
182
+ end_date = f"{end_year}-{month_of_interest:02d}"
 
183
 
184
  # Input: GeoJSON/KML file
185
  uploaded_file = st.file_uploader("Upload KML/GeoJSON file", type=["geojson", "kml"])
 
190
 
191
  # Input: Geometry
192
  selected_geometry = st.selectbox("Select the geometry", gdf.Name.values)
193
+ selected_geometry_gdf = gdf[gdf.Name == selected_geometry]
194
+ selected_geometry = selected_geometry_gdf.iloc[0].geometry
195
  if selected_geometry.type != "Polygon":
196
  st.error(
197
  f"Selected geometry is of type {selected_geometry.type}. Please provide a polygon geometry."
 
201
  # Derived Inputs
202
  selected_geometry = selected_geometry.__geo_interface__
203
  ee_geometry = ee.Geometry(selected_geometry)
204
+ _, lonlat = ee_geometry.centroid().getInfo().values()
205
+ lon, lat = lonlat
206
  ee_feature_collection = ee.FeatureCollection(ee_geometry)
207
  feature_collection = geojson.FeatureCollection([{"type": "Feature", "geometry": selected_geometry, "properties": {"name": "Selected Geometry"}}])
208
+ x, y, zone, _ = utm.from_latlon(lat, lon)
209
+ epsg = f"EPSG:326{zone}"
210
+ selected_geometry_gdf = selected_geometry_gdf.to_crs(epsg)
211
+ area = selected_geometry_gdf.area.values[0]
212
+ perimeter = selected_geometry_gdf.length.values[0]
213
+
214
+ stats_df = pd.DataFrame(
215
+ {
216
+ "Area (m^2)": [area],
217
+ "Perimeter (m)": [perimeter],
218
+ "Centroid (lat, lon)": [f"{lat}, {lon}"],
219
+ "Points": np.array(selected_geometry['coordinates']).tolist(),
220
+ }
221
+ )
222
+
223
 
224
  # visualize the geometry
225
  m = leaf_folium.Map()
 
230
  write_info(f"Visual Esri Wayback Basemap - {latest_date}")
231
  m.to_streamlit()
232
 
233
+ st.write(stats_df)
234
+ # download option
235
+ stats_csv = stats_df.to_csv()
236
+ st.download_button("Download Geometry Stats", stats_csv, "geometry_stats.csv", "text/csv")
237
+
238
 
239
  # Input: Satellite Sources
240
  st.write("Select the satellite sources:")
 
250
  st.stop()
251
 
252
  # Create month range
253
+ # print(start_date, end_date)
254
+ dates = pd.date_range(start_date, end_date, freq="Y").strftime("%Y-%m").tolist()
255
+ # print(dates)
256
+ # asjasndjasndj
257
  write_info(
258
  f"Start Date (inclusive): {start_date}, End Date (exclusive): {end_date}"
259
  )
 
264
 
265
  with st.spinner(f"Processing {satellite} ..."):
266
  progress_bar = st.progress(0)
267
+ for i, date in enumerate(dates):
268
+ mosaic, mean_ndvi, cloud_proba = process_date(date, satellite)
269
+ result[satellite][date] = {
270
  "mosaic": mosaic,
271
  "mean_ndvi": mean_ndvi,
272
  "cloud_mask_probability": cloud_proba,
273
  }
274
+ progress_bar.progress((i + 1) / len(dates))
275
 
276
  st.session_state.result = result
277
 
 
309
 
310
  df_numeric = df.select_dtypes(include=["float64"])
311
  st.write(df_numeric)
312
+ # give streamlit option to download the data
313
+ csv = df_numeric.to_csv()
314
+ st.download_button("Download Time Series", csv, "data.csv", "text/csv")
315
 
316
+ fig = px.line(df, y=df_numeric.columns[0:1], title="Mean NDVI", markers=True)
317
  fig.update_yaxes(range=[-0.2, 1])
318
  st.plotly_chart(fig)
319
 
320
  st.subheader("Visual Inspection")
 
 
321
  write_info(f"Centroid of the selected geometry (lat, lon): ({lat}, {lon})")
322
  cols = st.columns(2)
323
  df_dates = df.index.strftime("%Y-%m").tolist()
sandbox.ipynb CHANGED
@@ -140,7 +140,7 @@
140
  },
141
  {
142
  "cell_type": "code",
143
- "execution_count": 24,
144
  "metadata": {},
145
  "outputs": [
146
  {
@@ -180,16 +180,16 @@
180
  {
181
  "data": {
182
  "text/plain": [
183
- "2.75e-05"
184
  ]
185
  },
186
- "execution_count": 24,
187
  "metadata": {},
188
  "output_type": "execute_result"
189
  }
190
  ],
191
  "source": [
192
- "2.75e-05"
193
  ]
194
  },
195
  {
@@ -2631,6 +2631,76 @@
2631
  "layers = [\"Esri.WorldTopoMap\", \"OpenTopoMap\"]\n",
2632
  "leafmap.linked_maps(rows=1, cols=2, height=\"400px\", layers=layers)"
2633
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2634
  }
2635
  ],
2636
  "metadata": {
 
140
  },
141
  {
142
  "cell_type": "code",
143
+ "execution_count": 26,
144
  "metadata": {},
145
  "outputs": [
146
  {
 
180
  {
181
  "data": {
182
  "text/plain": [
183
+ "7272.727272727272"
184
  ]
185
  },
186
+ "execution_count": 26,
187
  "metadata": {},
188
  "output_type": "execute_result"
189
  }
190
  ],
191
  "source": [
192
+ "1/2.75e-05 * 0.2"
193
  ]
194
  },
195
  {
 
2631
  "layers = [\"Esri.WorldTopoMap\", \"OpenTopoMap\"]\n",
2632
  "leafmap.linked_maps(rows=1, cols=2, height=\"400px\", layers=layers)"
2633
  ]
2634
+ },
2635
+ {
2636
+ "cell_type": "code",
2637
+ "execution_count": 1,
2638
+ "metadata": {},
2639
+ "outputs": [
2640
+ {
2641
+ "data": {
2642
+ "application/vnd.jupyter.widget-view+json": {
2643
+ "model_id": "1ce50feee5594597a06e1de0b80600b1",
2644
+ "version_major": 2,
2645
+ "version_minor": 0
2646
+ },
2647
+ "text/plain": [
2648
+ "Map(center=[45.8107, 8.6288], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zoom_in_title', 'zoo…"
2649
+ ]
2650
+ },
2651
+ "metadata": {},
2652
+ "output_type": "display_data"
2653
+ }
2654
+ ],
2655
+ "source": [
2656
+ "from ipyleaflet import Map, TileLayer, WidgetControl\n",
2657
+ "from ipywidgets import SelectionSlider\n",
2658
+ "\n",
2659
+ "# Prepare a slider widget to navigate the version history of the basemap\n",
2660
+ "# There doesn't seem to be any pattern between timeId and basemap date, so just a few couples manually extracted from\n",
2661
+ "# https://wayback.maptiles.arcgis.com/arcgis/rest/services/world_imagery/mapserver/wmts/1.0.0/wmtscapabilities.xml\n",
2662
+ "date_timeId_mapping = [('2016-01-13', 3515),\n",
2663
+ " ('2017-01-11', 577),\n",
2664
+ " ('2018-01-08', 13161),\n",
2665
+ " ('2019-01-09', 6036),\n",
2666
+ " ('2020-01-08', 23001),\n",
2667
+ " ('2021-01-13', 1049),\n",
2668
+ " ('2022-01-12', 42663),\n",
2669
+ " ('2023-01-11', 11475)]\n",
2670
+ "\n",
2671
+ "# Date slider widget\n",
2672
+ "wayback_slider = SelectionSlider(\n",
2673
+ " options=date_timeId_mapping,\n",
2674
+ " value=3515,\n",
2675
+ " description='Date',\n",
2676
+ " disabled=False,\n",
2677
+ " continuous_update=True,\n",
2678
+ " orientation='horizontal',\n",
2679
+ " readout=True\n",
2680
+ ")\n",
2681
+ "time_control = WidgetControl(widget=wayback_slider, position='topright')\n",
2682
+ "\n",
2683
+ "# Connect tile layer (wayback, not yet defined) with slider value\n",
2684
+ "def on_date_change(*args):\n",
2685
+ " wayback.url = 'https://wayback.maptiles.arcgis.com/arcgis/rest/services/world_imagery/wmts/1.0.0/default028mm/mapserver/tile/%d/{z}/{y}/{x}' % wayback_slider.value\n",
2686
+ " wayback.redraw()\n",
2687
+ " \n",
2688
+ "wayback_slider.observe(on_date_change, 'value')\n",
2689
+ "\n",
2690
+ "# Prepare map, tilelayer and draw it\n",
2691
+ "m = Map(center=(45.8107, 8.6288), zoom=16, scroll_wheel_zoom=True)\n",
2692
+ "wayback = TileLayer(url='https://wayback.maptiles.arcgis.com/arcgis/rest/services/world_imagery/wmts/1.0.0/default028mm/mapserver/tile/3515/{z}/{y}/{x}')\n",
2693
+ "m.add_layer(wayback)\n",
2694
+ "m.add_control(time_control)\n",
2695
+ "m"
2696
+ ]
2697
+ },
2698
+ {
2699
+ "cell_type": "code",
2700
+ "execution_count": null,
2701
+ "metadata": {},
2702
+ "outputs": [],
2703
+ "source": []
2704
  }
2705
  ],
2706
  "metadata": {