onfarmview commited on
Commit
6bed31d
·
1 Parent(s): 3581926

Add application file

Browse files
Files changed (1) hide show
  1. pages/1_📷_Timelapse.py +1527 -0
pages/1_📷_Timelapse.py ADDED
@@ -0,0 +1,1527 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ee
2
+ import os
3
+ import warnings
4
+ import datetime
5
+ import fiona
6
+ import geopandas as gpd
7
+ import folium
8
+ import streamlit as st
9
+ import geemap.colormaps as cm
10
+ import geemap.foliumap as geemap
11
+ from datetime import date
12
+ from shapely.geometry import Polygon
13
+
14
+ st.set_page_config(layout="wide")
15
+ warnings.filterwarnings("ignore")
16
+
17
+
18
+ @st.cache(allow_output_mutation=True)
19
+ def ee_authenticate(token_name="EARTHENGINE_TOKEN"):
20
+ geemap.ee_initialize(token_name=token_name)
21
+
22
+
23
+ st.sidebar.info(
24
+ """
25
+ - Web App URL: <https://streamlit.gishub.org>
26
+ - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
27
+ """
28
+ )
29
+
30
+ st.sidebar.title("Contact")
31
+ st.sidebar.info(
32
+ """
33
+ Qiusheng Wu at [wetlands.io](https://wetlands.io) | [GitHub](https://github.com/giswqs) | [Twitter](https://twitter.com/giswqs) | [YouTube](https://www.youtube.com/c/QiushengWu) | [LinkedIn](https://www.linkedin.com/in/qiushengwu)
34
+ """
35
+ )
36
+
37
+ goes_rois = {
38
+ "Creek Fire, CA (2020-09-05)": {
39
+ "region": Polygon(
40
+ [
41
+ [-121.003418, 36.848857],
42
+ [-121.003418, 39.049052],
43
+ [-117.905273, 39.049052],
44
+ [-117.905273, 36.848857],
45
+ [-121.003418, 36.848857],
46
+ ]
47
+ ),
48
+ "start_time": "2020-09-05T15:00:00",
49
+ "end_time": "2020-09-06T02:00:00",
50
+ },
51
+ "Bomb Cyclone (2021-10-24)": {
52
+ "region": Polygon(
53
+ [
54
+ [-159.5954, 60.4088],
55
+ [-159.5954, 24.5178],
56
+ [-114.2438, 24.5178],
57
+ [-114.2438, 60.4088],
58
+ ]
59
+ ),
60
+ "start_time": "2021-10-24T14:00:00",
61
+ "end_time": "2021-10-25T01:00:00",
62
+ },
63
+ "Hunga Tonga Volcanic Eruption (2022-01-15)": {
64
+ "region": Polygon(
65
+ [
66
+ [-192.480469, -32.546813],
67
+ [-192.480469, -8.754795],
68
+ [-157.587891, -8.754795],
69
+ [-157.587891, -32.546813],
70
+ [-192.480469, -32.546813],
71
+ ]
72
+ ),
73
+ "start_time": "2022-01-15T03:00:00",
74
+ "end_time": "2022-01-15T07:00:00",
75
+ },
76
+ "Hunga Tonga Volcanic Eruption Closer Look (2022-01-15)": {
77
+ "region": Polygon(
78
+ [
79
+ [-178.901367, -22.958393],
80
+ [-178.901367, -17.85329],
81
+ [-171.452637, -17.85329],
82
+ [-171.452637, -22.958393],
83
+ [-178.901367, -22.958393],
84
+ ]
85
+ ),
86
+ "start_time": "2022-01-15T03:00:00",
87
+ "end_time": "2022-01-15T07:00:00",
88
+ },
89
+ }
90
+
91
+
92
+ landsat_rois = {
93
+ "Aral Sea": Polygon(
94
+ [
95
+ [57.667236, 43.834527],
96
+ [57.667236, 45.996962],
97
+ [61.12793, 45.996962],
98
+ [61.12793, 43.834527],
99
+ [57.667236, 43.834527],
100
+ ]
101
+ ),
102
+ "Dubai": Polygon(
103
+ [
104
+ [54.541626, 24.763044],
105
+ [54.541626, 25.427152],
106
+ [55.632019, 25.427152],
107
+ [55.632019, 24.763044],
108
+ [54.541626, 24.763044],
109
+ ]
110
+ ),
111
+ "Hong Kong International Airport": Polygon(
112
+ [
113
+ [113.825226, 22.198849],
114
+ [113.825226, 22.349758],
115
+ [114.085121, 22.349758],
116
+ [114.085121, 22.198849],
117
+ [113.825226, 22.198849],
118
+ ]
119
+ ),
120
+ "Las Vegas, NV": Polygon(
121
+ [
122
+ [-115.554199, 35.804449],
123
+ [-115.554199, 36.558188],
124
+ [-113.903503, 36.558188],
125
+ [-113.903503, 35.804449],
126
+ [-115.554199, 35.804449],
127
+ ]
128
+ ),
129
+ "Pucallpa, Peru": Polygon(
130
+ [
131
+ [-74.672699, -8.600032],
132
+ [-74.672699, -8.254983],
133
+ [-74.279938, -8.254983],
134
+ [-74.279938, -8.600032],
135
+ ]
136
+ ),
137
+ "Sierra Gorda, Chile": Polygon(
138
+ [
139
+ [-69.315491, -22.837104],
140
+ [-69.315491, -22.751488],
141
+ [-69.190006, -22.751488],
142
+ [-69.190006, -22.837104],
143
+ [-69.315491, -22.837104],
144
+ ]
145
+ ),
146
+ }
147
+
148
+ modis_rois = {
149
+ "World": Polygon(
150
+ [
151
+ [-171.210938, -57.136239],
152
+ [-171.210938, 79.997168],
153
+ [177.539063, 79.997168],
154
+ [177.539063, -57.136239],
155
+ [-171.210938, -57.136239],
156
+ ]
157
+ ),
158
+ "Africa": Polygon(
159
+ [
160
+ [-18.6983, 38.1446],
161
+ [-18.6983, -36.1630],
162
+ [52.2293, -36.1630],
163
+ [52.2293, 38.1446],
164
+ ]
165
+ ),
166
+ "USA": Polygon(
167
+ [
168
+ [-127.177734, 23.725012],
169
+ [-127.177734, 50.792047],
170
+ [-66.269531, 50.792047],
171
+ [-66.269531, 23.725012],
172
+ [-127.177734, 23.725012],
173
+ ]
174
+ ),
175
+ }
176
+
177
+ ocean_rois = {
178
+ "Gulf of Mexico": Polygon(
179
+ [
180
+ [-101.206055, 15.496032],
181
+ [-101.206055, 32.361403],
182
+ [-75.673828, 32.361403],
183
+ [-75.673828, 15.496032],
184
+ [-101.206055, 15.496032],
185
+ ]
186
+ ),
187
+ "North Atlantic Ocean": Polygon(
188
+ [
189
+ [-85.341797, 24.046464],
190
+ [-85.341797, 45.02695],
191
+ [-55.810547, 45.02695],
192
+ [-55.810547, 24.046464],
193
+ [-85.341797, 24.046464],
194
+ ]
195
+ ),
196
+ "World": Polygon(
197
+ [
198
+ [-171.210938, -57.136239],
199
+ [-171.210938, 79.997168],
200
+ [177.539063, 79.997168],
201
+ [177.539063, -57.136239],
202
+ [-171.210938, -57.136239],
203
+ ]
204
+ ),
205
+ }
206
+
207
+
208
+ @st.cache(allow_output_mutation=True)
209
+ def uploaded_file_to_gdf(data):
210
+ import tempfile
211
+ import os
212
+ import uuid
213
+
214
+ _, file_extension = os.path.splitext(data.name)
215
+ file_id = str(uuid.uuid4())
216
+ file_path = os.path.join(tempfile.gettempdir(), f"{file_id}{file_extension}")
217
+
218
+ with open(file_path, "wb") as file:
219
+ file.write(data.getbuffer())
220
+
221
+ if file_path.lower().endswith(".kml"):
222
+ fiona.drvsupport.supported_drivers["KML"] = "rw"
223
+ gdf = gpd.read_file(file_path, driver="KML")
224
+ else:
225
+ gdf = gpd.read_file(file_path)
226
+
227
+ return gdf
228
+
229
+
230
+ def app():
231
+
232
+ today = date.today()
233
+
234
+ st.title("Create Satellite Timelapse")
235
+
236
+ st.markdown(
237
+ """
238
+ An interactive web app for creating [Landsat](https://developers.google.com/earth-engine/datasets/catalog/landsat)/[GOES](https://jstnbraaten.medium.com/goes-in-earth-engine-53fbc8783c16) timelapse for any location around the globe.
239
+ The app was built using [streamlit](https://streamlit.io), [geemap](https://geemap.org), and [Google Earth Engine](https://earthengine.google.com). For more info, check out my streamlit [blog post](https://blog.streamlit.io/creating-satellite-timelapse-with-streamlit-and-earth-engine).
240
+ """
241
+ )
242
+
243
+ row1_col1, row1_col2 = st.columns([2, 1])
244
+
245
+ if st.session_state.get("zoom_level") is None:
246
+ st.session_state["zoom_level"] = 4
247
+
248
+ st.session_state["ee_asset_id"] = None
249
+ st.session_state["bands"] = None
250
+ st.session_state["palette"] = None
251
+ st.session_state["vis_params"] = None
252
+
253
+ with row1_col1:
254
+ ee_authenticate(token_name="EARTHENGINE_TOKEN")
255
+ m = geemap.Map(
256
+ basemap="HYBRID",
257
+ plugin_Draw=True,
258
+ Draw_export=True,
259
+ locate_control=True,
260
+ plugin_LatLngPopup=False,
261
+ )
262
+ m.add_basemap("ROADMAP")
263
+
264
+ with row1_col2:
265
+
266
+ keyword = st.text_input("Search for a location:", "")
267
+ if keyword:
268
+ locations = geemap.geocode(keyword)
269
+ if locations is not None and len(locations) > 0:
270
+ str_locations = [str(g)[1:-1] for g in locations]
271
+ location = st.selectbox("Select a location:", str_locations)
272
+ loc_index = str_locations.index(location)
273
+ selected_loc = locations[loc_index]
274
+ lat, lng = selected_loc.lat, selected_loc.lng
275
+ folium.Marker(location=[lat, lng], popup=location).add_to(m)
276
+ m.set_center(lng, lat, 12)
277
+ st.session_state["zoom_level"] = 12
278
+
279
+ collection = st.selectbox(
280
+ "Select a satellite image collection: ",
281
+ [
282
+ "Any Earth Engine ImageCollection",
283
+ "Landsat TM-ETM-OLI Surface Reflectance",
284
+ "Sentinel-2 MSI Surface Reflectance",
285
+ "Geostationary Operational Environmental Satellites (GOES)",
286
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
287
+ "MODIS Gap filled Land Surface Temperature Daily",
288
+ "MODIS Ocean Color SMI",
289
+ "USDA National Agriculture Imagery Program (NAIP)",
290
+ ],
291
+ index=1,
292
+ )
293
+
294
+ if collection in [
295
+ "Landsat TM-ETM-OLI Surface Reflectance",
296
+ "Sentinel-2 MSI Surface Reflectance",
297
+ ]:
298
+ roi_options = ["Uploaded GeoJSON"] + list(landsat_rois.keys())
299
+
300
+ elif collection == "Geostationary Operational Environmental Satellites (GOES)":
301
+ roi_options = ["Uploaded GeoJSON"] + list(goes_rois.keys())
302
+
303
+ elif collection in [
304
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
305
+ "MODIS Gap filled Land Surface Temperature Daily",
306
+ ]:
307
+ roi_options = ["Uploaded GeoJSON"] + list(modis_rois.keys())
308
+ elif collection == "MODIS Ocean Color SMI":
309
+ roi_options = ["Uploaded GeoJSON"] + list(ocean_rois.keys())
310
+ else:
311
+ roi_options = ["Uploaded GeoJSON"]
312
+
313
+ if collection == "Any Earth Engine ImageCollection":
314
+ keyword = st.text_input("Enter a keyword to search (e.g., MODIS):", "")
315
+ if keyword:
316
+
317
+ assets = geemap.search_ee_data(keyword)
318
+ ee_assets = []
319
+ for asset in assets:
320
+ if asset["ee_id_snippet"].startswith("ee.ImageCollection"):
321
+ ee_assets.append(asset)
322
+
323
+ asset_titles = [x["title"] for x in ee_assets]
324
+ dataset = st.selectbox("Select a dataset:", asset_titles)
325
+ if len(ee_assets) > 0:
326
+ st.session_state["ee_assets"] = ee_assets
327
+ st.session_state["asset_titles"] = asset_titles
328
+ index = asset_titles.index(dataset)
329
+ ee_id = ee_assets[index]["id"]
330
+ else:
331
+ ee_id = ""
332
+
333
+ if dataset is not None:
334
+ with st.expander("Show dataset details", False):
335
+ index = asset_titles.index(dataset)
336
+ html = geemap.ee_data_html(st.session_state["ee_assets"][index])
337
+ st.markdown(html, True)
338
+ # elif collection == "MODIS Gap filled Land Surface Temperature Daily":
339
+ # ee_id = ""
340
+ else:
341
+ ee_id = ""
342
+
343
+ asset_id = st.text_input("Enter an ee.ImageCollection asset ID:", ee_id)
344
+
345
+ if asset_id:
346
+ with st.expander("Customize band combination and color palette", True):
347
+ try:
348
+ col = ee.ImageCollection.load(asset_id)
349
+ st.session_state["ee_asset_id"] = asset_id
350
+ except:
351
+ st.error("Invalid Earth Engine asset ID.")
352
+ st.session_state["ee_asset_id"] = None
353
+ return
354
+
355
+ img_bands = col.first().bandNames().getInfo()
356
+ if len(img_bands) >= 3:
357
+ default_bands = img_bands[:3][::-1]
358
+ else:
359
+ default_bands = img_bands[:]
360
+ bands = st.multiselect(
361
+ "Select one or three bands (RGB):", img_bands, default_bands
362
+ )
363
+ st.session_state["bands"] = bands
364
+
365
+ if len(bands) == 1:
366
+ palette_options = st.selectbox(
367
+ "Color palette",
368
+ cm.list_colormaps(),
369
+ index=2,
370
+ )
371
+ palette_values = cm.get_palette(palette_options, 15)
372
+ palette = st.text_area(
373
+ "Enter a custom palette:",
374
+ palette_values,
375
+ )
376
+ st.write(
377
+ cm.plot_colormap(cmap=palette_options, return_fig=True)
378
+ )
379
+ st.session_state["palette"] = eval(palette)
380
+
381
+ if bands:
382
+ vis_params = st.text_area(
383
+ "Enter visualization parameters",
384
+ "{'bands': ["
385
+ + ", ".join([f"'{band}'" for band in bands])
386
+ + "]}",
387
+ )
388
+ else:
389
+ vis_params = st.text_area(
390
+ "Enter visualization parameters",
391
+ "{}",
392
+ )
393
+ try:
394
+ st.session_state["vis_params"] = eval(vis_params)
395
+ st.session_state["vis_params"]["palette"] = st.session_state[
396
+ "palette"
397
+ ]
398
+ except Exception as e:
399
+ st.session_state["vis_params"] = None
400
+ st.error(
401
+ f"Invalid visualization parameters. It must be a dictionary."
402
+ )
403
+
404
+ elif collection == "MODIS Gap filled Land Surface Temperature Daily":
405
+ with st.expander("Show dataset details", False):
406
+ st.markdown(
407
+ """
408
+ See the [Awesome GEE Community Datasets](https://samapriya.github.io/awesome-gee-community-datasets/projects/daily_lst/).
409
+ """
410
+ )
411
+
412
+ MODIS_options = ["Daytime (1:30 pm)", "Nighttime (1:30 am)"]
413
+ MODIS_option = st.selectbox("Select a MODIS dataset:", MODIS_options)
414
+ if MODIS_option == "Daytime (1:30 pm)":
415
+ st.session_state[
416
+ "ee_asset_id"
417
+ ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_day_1km"
418
+ else:
419
+ st.session_state[
420
+ "ee_asset_id"
421
+ ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_night_1km"
422
+
423
+ palette_options = st.selectbox(
424
+ "Color palette",
425
+ cm.list_colormaps(),
426
+ index=90,
427
+ )
428
+ palette_values = cm.get_palette(palette_options, 15)
429
+ palette = st.text_area(
430
+ "Enter a custom palette:",
431
+ palette_values,
432
+ )
433
+ st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
434
+ st.session_state["palette"] = eval(palette)
435
+ elif collection == "MODIS Ocean Color SMI":
436
+ with st.expander("Show dataset details", False):
437
+ st.markdown(
438
+ """
439
+ See the [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets/catalog/NASA_OCEANDATA_MODIS-Aqua_L3SMI).
440
+ """
441
+ )
442
+
443
+ MODIS_options = ["Aqua", "Terra"]
444
+ MODIS_option = st.selectbox("Select a satellite:", MODIS_options)
445
+ st.session_state["ee_asset_id"] = MODIS_option
446
+ # if MODIS_option == "Daytime (1:30 pm)":
447
+ # st.session_state[
448
+ # "ee_asset_id"
449
+ # ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_day_1km"
450
+ # else:
451
+ # st.session_state[
452
+ # "ee_asset_id"
453
+ # ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_night_1km"
454
+
455
+ band_dict = {
456
+ "Chlorophyll a concentration": "chlor_a",
457
+ "Normalized fluorescence line height": "nflh",
458
+ "Particulate organic carbon": "poc",
459
+ "Sea surface temperature": "sst",
460
+ "Remote sensing reflectance at band 412nm": "Rrs_412",
461
+ "Remote sensing reflectance at band 443nm": "Rrs_443",
462
+ "Remote sensing reflectance at band 469nm": "Rrs_469",
463
+ "Remote sensing reflectance at band 488nm": "Rrs_488",
464
+ "Remote sensing reflectance at band 531nm": "Rrs_531",
465
+ "Remote sensing reflectance at band 547nm": "Rrs_547",
466
+ "Remote sensing reflectance at band 555nm": "Rrs_555",
467
+ "Remote sensing reflectance at band 645nm": "Rrs_645",
468
+ "Remote sensing reflectance at band 667nm": "Rrs_667",
469
+ "Remote sensing reflectance at band 678nm": "Rrs_678",
470
+ }
471
+
472
+ band_options = list(band_dict.keys())
473
+ band = st.selectbox(
474
+ "Select a band",
475
+ band_options,
476
+ band_options.index("Sea surface temperature"),
477
+ )
478
+ st.session_state["band"] = band_dict[band]
479
+
480
+ colors = cm.list_colormaps()
481
+ palette_options = st.selectbox(
482
+ "Color palette",
483
+ colors,
484
+ index=colors.index("coolwarm"),
485
+ )
486
+ palette_values = cm.get_palette(palette_options, 15)
487
+ palette = st.text_area(
488
+ "Enter a custom palette:",
489
+ palette_values,
490
+ )
491
+ st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
492
+ st.session_state["palette"] = eval(palette)
493
+
494
+ sample_roi = st.selectbox(
495
+ "Select a sample ROI or upload a GeoJSON file:",
496
+ roi_options,
497
+ index=0,
498
+ )
499
+
500
+ add_outline = st.checkbox(
501
+ "Overlay an administrative boundary on timelapse", False
502
+ )
503
+
504
+ if add_outline:
505
+
506
+ with st.expander("Customize administrative boundary", True):
507
+
508
+ overlay_options = {
509
+ "User-defined": None,
510
+ "Continents": "continents",
511
+ "Countries": "countries",
512
+ "US States": "us_states",
513
+ "China": "china",
514
+ }
515
+
516
+ overlay = st.selectbox(
517
+ "Select an administrative boundary:",
518
+ list(overlay_options.keys()),
519
+ index=2,
520
+ )
521
+
522
+ overlay_data = overlay_options[overlay]
523
+
524
+ if overlay_data is None:
525
+ overlay_data = st.text_input(
526
+ "Enter an HTTP URL to a GeoJSON file or an ee.FeatureCollection asset id:",
527
+ "https://raw.githubusercontent.com/giswqs/geemap/master/examples/data/countries.geojson",
528
+ )
529
+
530
+ overlay_color = st.color_picker(
531
+ "Select a color for the administrative boundary:", "#000000"
532
+ )
533
+ overlay_width = st.slider(
534
+ "Select a line width for the administrative boundary:", 1, 20, 1
535
+ )
536
+ overlay_opacity = st.slider(
537
+ "Select an opacity for the administrative boundary:",
538
+ 0.0,
539
+ 1.0,
540
+ 1.0,
541
+ 0.05,
542
+ )
543
+ else:
544
+ overlay_data = None
545
+ overlay_color = "black"
546
+ overlay_width = 1
547
+ overlay_opacity = 1
548
+
549
+ with row1_col1:
550
+
551
+ with st.expander(
552
+ "Steps: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Expand this tab to see a demo 👉"
553
+ ):
554
+ video_empty = st.empty()
555
+
556
+ data = st.file_uploader(
557
+ "Upload a GeoJSON file to use as an ROI. Customize timelapse parameters and then click the Submit button 😇👇",
558
+ type=["geojson", "kml", "zip"],
559
+ )
560
+
561
+ crs = "epsg:4326"
562
+ if sample_roi == "Uploaded GeoJSON":
563
+ if data is None:
564
+ # st.info(
565
+ # "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click Submit button"
566
+ # )
567
+ if collection in [
568
+ "Geostationary Operational Environmental Satellites (GOES)",
569
+ "USDA National Agriculture Imagery Program (NAIP)",
570
+ ] and (not keyword):
571
+ m.set_center(-100, 40, 3)
572
+ # else:
573
+ # m.set_center(4.20, 18.63, zoom=2)
574
+ else:
575
+ if collection in [
576
+ "Landsat TM-ETM-OLI Surface Reflectance",
577
+ "Sentinel-2 MSI Surface Reflectance",
578
+ ]:
579
+ gdf = gpd.GeoDataFrame(
580
+ index=[0], crs=crs, geometry=[landsat_rois[sample_roi]]
581
+ )
582
+ elif (
583
+ collection
584
+ == "Geostationary Operational Environmental Satellites (GOES)"
585
+ ):
586
+ gdf = gpd.GeoDataFrame(
587
+ index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
588
+ )
589
+ elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
590
+ gdf = gpd.GeoDataFrame(
591
+ index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
592
+ )
593
+
594
+ if sample_roi != "Uploaded GeoJSON":
595
+
596
+ if collection in [
597
+ "Landsat TM-ETM-OLI Surface Reflectance",
598
+ "Sentinel-2 MSI Surface Reflectance",
599
+ ]:
600
+ gdf = gpd.GeoDataFrame(
601
+ index=[0], crs=crs, geometry=[landsat_rois[sample_roi]]
602
+ )
603
+ elif (
604
+ collection
605
+ == "Geostationary Operational Environmental Satellites (GOES)"
606
+ ):
607
+ gdf = gpd.GeoDataFrame(
608
+ index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
609
+ )
610
+ elif collection in [
611
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
612
+ "MODIS Gap filled Land Surface Temperature Daily",
613
+ ]:
614
+ gdf = gpd.GeoDataFrame(
615
+ index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
616
+ )
617
+ elif collection == "MODIS Ocean Color SMI":
618
+ gdf = gpd.GeoDataFrame(
619
+ index=[0], crs=crs, geometry=[ocean_rois[sample_roi]]
620
+ )
621
+ try:
622
+ st.session_state["roi"] = geemap.gdf_to_ee(gdf, geodesic=False)
623
+ except Exception as e:
624
+ st.error(e)
625
+ st.error("Please draw another ROI and try again.")
626
+ return
627
+ m.add_gdf(gdf, "ROI")
628
+
629
+ elif data:
630
+ gdf = uploaded_file_to_gdf(data)
631
+ try:
632
+ st.session_state["roi"] = geemap.gdf_to_ee(gdf, geodesic=False)
633
+ m.add_gdf(gdf, "ROI")
634
+ except Exception as e:
635
+ st.error(e)
636
+ st.error("Please draw another ROI and try again.")
637
+ return
638
+
639
+ m.to_streamlit(height=600)
640
+
641
+ with row1_col2:
642
+
643
+ if collection in [
644
+ "Landsat TM-ETM-OLI Surface Reflectance",
645
+ "Sentinel-2 MSI Surface Reflectance",
646
+ ]:
647
+
648
+ if collection == "Landsat TM-ETM-OLI Surface Reflectance":
649
+ sensor_start_year = 1984
650
+ timelapse_title = "Landsat Timelapse"
651
+ timelapse_speed = 5
652
+ elif collection == "Sentinel-2 MSI Surface Reflectance":
653
+ sensor_start_year = 2015
654
+ timelapse_title = "Sentinel-2 Timelapse"
655
+ timelapse_speed = 5
656
+ video_empty.video("https://youtu.be/VVRK_-dEjR4")
657
+
658
+ with st.form("submit_landsat_form"):
659
+
660
+ roi = None
661
+ if st.session_state.get("roi") is not None:
662
+ roi = st.session_state.get("roi")
663
+ out_gif = geemap.temp_file_path(".gif")
664
+
665
+ title = st.text_input(
666
+ "Enter a title to show on the timelapse: ", timelapse_title
667
+ )
668
+ RGB = st.selectbox(
669
+ "Select an RGB band combination:",
670
+ [
671
+ "Red/Green/Blue",
672
+ "NIR/Red/Green",
673
+ "SWIR2/SWIR1/NIR",
674
+ "NIR/SWIR1/Red",
675
+ "SWIR2/NIR/Red",
676
+ "SWIR2/SWIR1/Red",
677
+ "SWIR1/NIR/Blue",
678
+ "NIR/SWIR1/Blue",
679
+ "SWIR2/NIR/Green",
680
+ "SWIR1/NIR/Red",
681
+ "SWIR2/NIR/SWIR1",
682
+ "SWIR1/NIR/SWIR2",
683
+ ],
684
+ index=9,
685
+ )
686
+
687
+ frequency = st.selectbox(
688
+ "Select a temporal frequency:",
689
+ ["year", "quarter", "month"],
690
+ index=0,
691
+ )
692
+
693
+ with st.expander("Customize timelapse"):
694
+
695
+ speed = st.slider("Frames per second:", 1, 30, timelapse_speed)
696
+ dimensions = st.slider(
697
+ "Maximum dimensions (Width*Height) in pixels", 768, 2000, 768
698
+ )
699
+ progress_bar_color = st.color_picker(
700
+ "Progress bar color:", "#0000ff"
701
+ )
702
+ years = st.slider(
703
+ "Start and end year:",
704
+ sensor_start_year,
705
+ today.year,
706
+ (sensor_start_year, today.year),
707
+ )
708
+ months = st.slider("Start and end month:", 1, 12, (1, 12))
709
+ font_size = st.slider("Font size:", 10, 50, 30)
710
+ font_color = st.color_picker("Font color:", "#ffffff")
711
+ apply_fmask = st.checkbox(
712
+ "Apply fmask (remove clouds, shadows, snow)", True
713
+ )
714
+ font_type = st.selectbox(
715
+ "Select the font type for the title:",
716
+ ["arial.ttf", "alibaba.otf"],
717
+ index=0,
718
+ )
719
+ fading = st.slider(
720
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
721
+ )
722
+ mp4 = st.checkbox("Save timelapse as MP4", True)
723
+
724
+ empty_text = st.empty()
725
+ empty_image = st.empty()
726
+ empty_fire_image = st.empty()
727
+ empty_video = st.container()
728
+ submitted = st.form_submit_button("Submit")
729
+ if submitted:
730
+
731
+ if sample_roi == "Uploaded GeoJSON" and data is None:
732
+ empty_text.warning(
733
+ "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
734
+ )
735
+ else:
736
+
737
+ empty_text.text("Computing... Please wait...")
738
+
739
+ start_year = years[0]
740
+ end_year = years[1]
741
+ start_date = str(months[0]).zfill(2) + "-01"
742
+ end_date = str(months[1]).zfill(2) + "-30"
743
+ bands = RGB.split("/")
744
+
745
+ try:
746
+ if collection == "Landsat TM-ETM-OLI Surface Reflectance":
747
+ out_gif = geemap.landsat_timelapse(
748
+ roi=roi,
749
+ out_gif=out_gif,
750
+ start_year=start_year,
751
+ end_year=end_year,
752
+ start_date=start_date,
753
+ end_date=end_date,
754
+ bands=bands,
755
+ apply_fmask=apply_fmask,
756
+ frames_per_second=speed,
757
+ # dimensions=dimensions,
758
+ dimensions=768,
759
+ overlay_data=overlay_data,
760
+ overlay_color=overlay_color,
761
+ overlay_width=overlay_width,
762
+ overlay_opacity=overlay_opacity,
763
+ frequency=frequency,
764
+ date_format=None,
765
+ title=title,
766
+ title_xy=("2%", "90%"),
767
+ add_text=True,
768
+ text_xy=("2%", "2%"),
769
+ text_sequence=None,
770
+ font_type=font_type,
771
+ font_size=font_size,
772
+ font_color=font_color,
773
+ add_progress_bar=True,
774
+ progress_bar_color=progress_bar_color,
775
+ progress_bar_height=5,
776
+ loop=0,
777
+ mp4=mp4,
778
+ fading=fading,
779
+ )
780
+ elif collection == "Sentinel-2 MSI Surface Reflectance":
781
+ out_gif = geemap.sentinel2_timelapse(
782
+ roi=roi,
783
+ out_gif=out_gif,
784
+ start_year=start_year,
785
+ end_year=end_year,
786
+ start_date=start_date,
787
+ end_date=end_date,
788
+ bands=bands,
789
+ apply_fmask=apply_fmask,
790
+ frames_per_second=speed,
791
+ dimensions=768,
792
+ # dimensions=dimensions,
793
+ overlay_data=overlay_data,
794
+ overlay_color=overlay_color,
795
+ overlay_width=overlay_width,
796
+ overlay_opacity=overlay_opacity,
797
+ frequency=frequency,
798
+ date_format=None,
799
+ title=title,
800
+ title_xy=("2%", "90%"),
801
+ add_text=True,
802
+ text_xy=("2%", "2%"),
803
+ text_sequence=None,
804
+ font_type=font_type,
805
+ font_size=font_size,
806
+ font_color=font_color,
807
+ add_progress_bar=True,
808
+ progress_bar_color=progress_bar_color,
809
+ progress_bar_height=5,
810
+ loop=0,
811
+ mp4=mp4,
812
+ fading=fading,
813
+ )
814
+ except:
815
+ empty_text.error(
816
+ "An error occurred while computing the timelapse. Your probably requested too much data. Try reducing the ROI or timespan."
817
+ )
818
+ st.stop()
819
+
820
+ if out_gif is not None and os.path.exists(out_gif):
821
+
822
+ empty_text.text(
823
+ "Right click the GIF to save it to your computer👇"
824
+ )
825
+ empty_image.image(out_gif)
826
+
827
+ out_mp4 = out_gif.replace(".gif", ".mp4")
828
+ if mp4 and os.path.exists(out_mp4):
829
+ with empty_video:
830
+ st.text(
831
+ "Right click the MP4 to save it to your computer👇"
832
+ )
833
+ st.video(out_gif.replace(".gif", ".mp4"))
834
+
835
+ else:
836
+ empty_text.error(
837
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
838
+ )
839
+
840
+ elif collection == "Geostationary Operational Environmental Satellites (GOES)":
841
+
842
+ video_empty.video("https://youtu.be/16fA2QORG4A")
843
+
844
+ with st.form("submit_goes_form"):
845
+
846
+ roi = None
847
+ if st.session_state.get("roi") is not None:
848
+ roi = st.session_state.get("roi")
849
+ out_gif = geemap.temp_file_path(".gif")
850
+
851
+ satellite = st.selectbox("Select a satellite:", ["GOES-17", "GOES-16"])
852
+ earliest_date = datetime.date(2017, 7, 10)
853
+ latest_date = datetime.date.today()
854
+
855
+ if sample_roi == "Uploaded GeoJSON":
856
+ roi_start_date = today - datetime.timedelta(days=2)
857
+ roi_end_date = today - datetime.timedelta(days=1)
858
+ roi_start_time = datetime.time(14, 00)
859
+ roi_end_time = datetime.time(1, 00)
860
+ else:
861
+ roi_start = goes_rois[sample_roi]["start_time"]
862
+ roi_end = goes_rois[sample_roi]["end_time"]
863
+ roi_start_date = datetime.datetime.strptime(
864
+ roi_start[:10], "%Y-%m-%d"
865
+ )
866
+ roi_end_date = datetime.datetime.strptime(roi_end[:10], "%Y-%m-%d")
867
+ roi_start_time = datetime.time(
868
+ int(roi_start[11:13]), int(roi_start[14:16])
869
+ )
870
+ roi_end_time = datetime.time(
871
+ int(roi_end[11:13]), int(roi_end[14:16])
872
+ )
873
+
874
+ start_date = st.date_input("Select the start date:", roi_start_date)
875
+ end_date = st.date_input("Select the end date:", roi_end_date)
876
+
877
+ with st.expander("Customize timelapse"):
878
+
879
+ add_fire = st.checkbox("Add Fire/Hotspot Characterization", False)
880
+
881
+ scan_type = st.selectbox(
882
+ "Select a scan type:", ["Full Disk", "CONUS", "Mesoscale"]
883
+ )
884
+
885
+ start_time = st.time_input(
886
+ "Select the start time of the start date:", roi_start_time
887
+ )
888
+
889
+ end_time = st.time_input(
890
+ "Select the end time of the end date:", roi_end_time
891
+ )
892
+
893
+ start = (
894
+ start_date.strftime("%Y-%m-%d")
895
+ + "T"
896
+ + start_time.strftime("%H:%M:%S")
897
+ )
898
+ end = (
899
+ end_date.strftime("%Y-%m-%d")
900
+ + "T"
901
+ + end_time.strftime("%H:%M:%S")
902
+ )
903
+
904
+ speed = st.slider("Frames per second:", 1, 30, 5)
905
+ add_progress_bar = st.checkbox("Add a progress bar", True)
906
+ progress_bar_color = st.color_picker(
907
+ "Progress bar color:", "#0000ff"
908
+ )
909
+ font_size = st.slider("Font size:", 10, 50, 20)
910
+ font_color = st.color_picker("Font color:", "#ffffff")
911
+ fading = st.slider(
912
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
913
+ )
914
+ mp4 = st.checkbox("Save timelapse as MP4", True)
915
+
916
+ empty_text = st.empty()
917
+ empty_image = st.empty()
918
+ empty_video = st.container()
919
+ empty_fire_text = st.empty()
920
+ empty_fire_image = st.empty()
921
+
922
+ submitted = st.form_submit_button("Submit")
923
+ if submitted:
924
+ if sample_roi == "Uploaded GeoJSON" and data is None:
925
+ empty_text.warning(
926
+ "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
927
+ )
928
+ else:
929
+ empty_text.text("Computing... Please wait...")
930
+
931
+ geemap.goes_timelapse(
932
+ roi,
933
+ out_gif,
934
+ start_date=start,
935
+ end_date=end,
936
+ data=satellite,
937
+ scan=scan_type.replace(" ", "_").lower(),
938
+ dimensions=768,
939
+ framesPerSecond=speed,
940
+ date_format="YYYY-MM-dd HH:mm",
941
+ xy=("3%", "3%"),
942
+ text_sequence=None,
943
+ font_type="arial.ttf",
944
+ font_size=font_size,
945
+ font_color=font_color,
946
+ add_progress_bar=add_progress_bar,
947
+ progress_bar_color=progress_bar_color,
948
+ progress_bar_height=5,
949
+ loop=0,
950
+ overlay_data=overlay_data,
951
+ overlay_color=overlay_color,
952
+ overlay_width=overlay_width,
953
+ overlay_opacity=overlay_opacity,
954
+ mp4=mp4,
955
+ fading=fading,
956
+ )
957
+
958
+ if out_gif is not None and os.path.exists(out_gif):
959
+ empty_text.text(
960
+ "Right click the GIF to save it to your computer👇"
961
+ )
962
+ empty_image.image(out_gif)
963
+
964
+ out_mp4 = out_gif.replace(".gif", ".mp4")
965
+ if mp4 and os.path.exists(out_mp4):
966
+ with empty_video:
967
+ st.text(
968
+ "Right click the MP4 to save it to your computer👇"
969
+ )
970
+ st.video(out_gif.replace(".gif", ".mp4"))
971
+
972
+ if add_fire:
973
+ out_fire_gif = geemap.temp_file_path(".gif")
974
+ empty_fire_text.text(
975
+ "Delineating Fire Hotspot... Please wait..."
976
+ )
977
+ geemap.goes_fire_timelapse(
978
+ out_fire_gif,
979
+ start_date=start,
980
+ end_date=end,
981
+ data=satellite,
982
+ scan=scan_type.replace(" ", "_").lower(),
983
+ region=roi,
984
+ dimensions=768,
985
+ framesPerSecond=speed,
986
+ date_format="YYYY-MM-dd HH:mm",
987
+ xy=("3%", "3%"),
988
+ text_sequence=None,
989
+ font_type="arial.ttf",
990
+ font_size=font_size,
991
+ font_color=font_color,
992
+ add_progress_bar=add_progress_bar,
993
+ progress_bar_color=progress_bar_color,
994
+ progress_bar_height=5,
995
+ loop=0,
996
+ )
997
+ if os.path.exists(out_fire_gif):
998
+ empty_fire_image.image(out_fire_gif)
999
+ else:
1000
+ empty_text.text(
1001
+ "Something went wrong, either the ROI is too big or there are no data available for the specified date range. Please try a smaller ROI or different date range."
1002
+ )
1003
+
1004
+ elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
1005
+
1006
+ video_empty.video("https://youtu.be/16fA2QORG4A")
1007
+
1008
+ satellite = st.selectbox("Select a satellite:", ["Terra", "Aqua"])
1009
+ band = st.selectbox("Select a band:", ["NDVI", "EVI"])
1010
+
1011
+ with st.form("submit_modis_form"):
1012
+
1013
+ roi = None
1014
+ if st.session_state.get("roi") is not None:
1015
+ roi = st.session_state.get("roi")
1016
+ out_gif = geemap.temp_file_path(".gif")
1017
+
1018
+ with st.expander("Customize timelapse"):
1019
+
1020
+ start = st.date_input(
1021
+ "Select a start date:", datetime.date(2000, 2, 8)
1022
+ )
1023
+ end = st.date_input("Select an end date:", datetime.date.today())
1024
+
1025
+ start_date = start.strftime("%Y-%m-%d")
1026
+ end_date = end.strftime("%Y-%m-%d")
1027
+
1028
+ speed = st.slider("Frames per second:", 1, 30, 5)
1029
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1030
+ progress_bar_color = st.color_picker(
1031
+ "Progress bar color:", "#0000ff"
1032
+ )
1033
+ font_size = st.slider("Font size:", 10, 50, 20)
1034
+ font_color = st.color_picker("Font color:", "#ffffff")
1035
+
1036
+ font_type = st.selectbox(
1037
+ "Select the font type for the title:",
1038
+ ["arial.ttf", "alibaba.otf"],
1039
+ index=0,
1040
+ )
1041
+ fading = st.slider(
1042
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1043
+ )
1044
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1045
+
1046
+ empty_text = st.empty()
1047
+ empty_image = st.empty()
1048
+ empty_video = st.container()
1049
+
1050
+ submitted = st.form_submit_button("Submit")
1051
+ if submitted:
1052
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1053
+ empty_text.warning(
1054
+ "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
1055
+ )
1056
+ else:
1057
+
1058
+ empty_text.text("Computing... Please wait...")
1059
+
1060
+ geemap.modis_ndvi_timelapse(
1061
+ roi,
1062
+ out_gif,
1063
+ satellite,
1064
+ band,
1065
+ start_date,
1066
+ end_date,
1067
+ 768,
1068
+ speed,
1069
+ overlay_data=overlay_data,
1070
+ overlay_color=overlay_color,
1071
+ overlay_width=overlay_width,
1072
+ overlay_opacity=overlay_opacity,
1073
+ mp4=mp4,
1074
+ fading=fading,
1075
+ )
1076
+
1077
+ geemap.reduce_gif_size(out_gif)
1078
+
1079
+ empty_text.text(
1080
+ "Right click the GIF to save it to your computer👇"
1081
+ )
1082
+ empty_image.image(out_gif)
1083
+
1084
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1085
+ if mp4 and os.path.exists(out_mp4):
1086
+ with empty_video:
1087
+ st.text(
1088
+ "Right click the MP4 to save it to your computer👇"
1089
+ )
1090
+ st.video(out_gif.replace(".gif", ".mp4"))
1091
+
1092
+ elif collection == "Any Earth Engine ImageCollection":
1093
+
1094
+ with st.form("submit_ts_form"):
1095
+ with st.expander("Customize timelapse"):
1096
+
1097
+ title = st.text_input(
1098
+ "Enter a title to show on the timelapse: ", "Timelapse"
1099
+ )
1100
+ start_date = st.date_input(
1101
+ "Select the start date:", datetime.date(2020, 1, 1)
1102
+ )
1103
+ end_date = st.date_input(
1104
+ "Select the end date:", datetime.date.today()
1105
+ )
1106
+ frequency = st.selectbox(
1107
+ "Select a temporal frequency:",
1108
+ ["year", "quarter", "month", "day", "hour", "minute", "second"],
1109
+ index=0,
1110
+ )
1111
+ reducer = st.selectbox(
1112
+ "Select a reducer for aggregating data:",
1113
+ ["median", "mean", "min", "max", "sum", "variance", "stdDev"],
1114
+ index=0,
1115
+ )
1116
+ data_format = st.selectbox(
1117
+ "Select a date format to show on the timelapse:",
1118
+ [
1119
+ "YYYY-MM-dd",
1120
+ "YYYY",
1121
+ "YYMM-MM",
1122
+ "YYYY-MM-dd HH:mm",
1123
+ "YYYY-MM-dd HH:mm:ss",
1124
+ "HH:mm",
1125
+ "HH:mm:ss",
1126
+ "w",
1127
+ "M",
1128
+ "d",
1129
+ "D",
1130
+ ],
1131
+ index=0,
1132
+ )
1133
+
1134
+ speed = st.slider("Frames per second:", 1, 30, 5)
1135
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1136
+ progress_bar_color = st.color_picker(
1137
+ "Progress bar color:", "#0000ff"
1138
+ )
1139
+ font_size = st.slider("Font size:", 10, 50, 30)
1140
+ font_color = st.color_picker("Font color:", "#ffffff")
1141
+ font_type = st.selectbox(
1142
+ "Select the font type for the title:",
1143
+ ["arial.ttf", "alibaba.otf"],
1144
+ index=0,
1145
+ )
1146
+ fading = st.slider(
1147
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1148
+ )
1149
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1150
+
1151
+ empty_text = st.empty()
1152
+ empty_image = st.empty()
1153
+ empty_video = st.container()
1154
+ empty_fire_image = st.empty()
1155
+
1156
+ roi = None
1157
+ if st.session_state.get("roi") is not None:
1158
+ roi = st.session_state.get("roi")
1159
+ out_gif = geemap.temp_file_path(".gif")
1160
+
1161
+ submitted = st.form_submit_button("Submit")
1162
+ if submitted:
1163
+
1164
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1165
+ empty_text.warning(
1166
+ "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
1167
+ )
1168
+ else:
1169
+
1170
+ empty_text.text("Computing... Please wait...")
1171
+ try:
1172
+ geemap.create_timelapse(
1173
+ st.session_state.get("ee_asset_id"),
1174
+ start_date=start_date.strftime("%Y-%m-%d"),
1175
+ end_date=end_date.strftime("%Y-%m-%d"),
1176
+ region=roi,
1177
+ frequency=frequency,
1178
+ reducer=reducer,
1179
+ date_format=data_format,
1180
+ out_gif=out_gif,
1181
+ bands=st.session_state.get("bands"),
1182
+ palette=st.session_state.get("palette"),
1183
+ vis_params=st.session_state.get("vis_params"),
1184
+ dimensions=768,
1185
+ frames_per_second=speed,
1186
+ crs="EPSG:3857",
1187
+ overlay_data=overlay_data,
1188
+ overlay_color=overlay_color,
1189
+ overlay_width=overlay_width,
1190
+ overlay_opacity=overlay_opacity,
1191
+ title=title,
1192
+ title_xy=("2%", "90%"),
1193
+ add_text=True,
1194
+ text_xy=("2%", "2%"),
1195
+ text_sequence=None,
1196
+ font_type=font_type,
1197
+ font_size=font_size,
1198
+ font_color=font_color,
1199
+ add_progress_bar=add_progress_bar,
1200
+ progress_bar_color=progress_bar_color,
1201
+ progress_bar_height=5,
1202
+ loop=0,
1203
+ mp4=mp4,
1204
+ fading=fading,
1205
+ )
1206
+ except:
1207
+ empty_text.error(
1208
+ "An error occurred while computing the timelapse. You probably requested too much data. Try reducing the ROI or timespan."
1209
+ )
1210
+
1211
+ empty_text.text(
1212
+ "Right click the GIF to save it to your computer👇"
1213
+ )
1214
+ empty_image.image(out_gif)
1215
+
1216
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1217
+ if mp4 and os.path.exists(out_mp4):
1218
+ with empty_video:
1219
+ st.text(
1220
+ "Right click the MP4 to save it to your computer👇"
1221
+ )
1222
+ st.video(out_gif.replace(".gif", ".mp4"))
1223
+
1224
+ elif collection in [
1225
+ "MODIS Gap filled Land Surface Temperature Daily",
1226
+ "MODIS Ocean Color SMI",
1227
+ ]:
1228
+
1229
+ with st.form("submit_ts_form"):
1230
+ with st.expander("Customize timelapse"):
1231
+
1232
+ title = st.text_input(
1233
+ "Enter a title to show on the timelapse: ",
1234
+ "Surface Temperature",
1235
+ )
1236
+ start_date = st.date_input(
1237
+ "Select the start date:", datetime.date(2018, 1, 1)
1238
+ )
1239
+ end_date = st.date_input(
1240
+ "Select the end date:", datetime.date(2020, 12, 31)
1241
+ )
1242
+ frequency = st.selectbox(
1243
+ "Select a temporal frequency:",
1244
+ ["year", "quarter", "month", "week", "day"],
1245
+ index=2,
1246
+ )
1247
+ reducer = st.selectbox(
1248
+ "Select a reducer for aggregating data:",
1249
+ ["median", "mean", "min", "max", "sum", "variance", "stdDev"],
1250
+ index=0,
1251
+ )
1252
+
1253
+ vis_params = st.text_area(
1254
+ "Enter visualization parameters",
1255
+ "",
1256
+ help="Enter a string in the format of a dictionary, such as '{'min': 23, 'max': 32}'",
1257
+ )
1258
+
1259
+ speed = st.slider("Frames per second:", 1, 30, 5)
1260
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1261
+ progress_bar_color = st.color_picker(
1262
+ "Progress bar color:", "#0000ff"
1263
+ )
1264
+ font_size = st.slider("Font size:", 10, 50, 30)
1265
+ font_color = st.color_picker("Font color:", "#ffffff")
1266
+ font_type = st.selectbox(
1267
+ "Select the font type for the title:",
1268
+ ["arial.ttf", "alibaba.otf"],
1269
+ index=0,
1270
+ )
1271
+ add_colorbar = st.checkbox("Add a colorbar", True)
1272
+ colorbar_label = st.text_input(
1273
+ "Enter the colorbar label:", "Surface Temperature (°C)"
1274
+ )
1275
+ fading = st.slider(
1276
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1277
+ )
1278
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1279
+
1280
+ empty_text = st.empty()
1281
+ empty_image = st.empty()
1282
+ empty_video = st.container()
1283
+
1284
+ roi = None
1285
+ if st.session_state.get("roi") is not None:
1286
+ roi = st.session_state.get("roi")
1287
+ out_gif = geemap.temp_file_path(".gif")
1288
+
1289
+ submitted = st.form_submit_button("Submit")
1290
+ if submitted:
1291
+
1292
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1293
+ empty_text.warning(
1294
+ "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
1295
+ )
1296
+ else:
1297
+
1298
+ empty_text.text("Computing... Please wait...")
1299
+ try:
1300
+ if (
1301
+ collection
1302
+ == "MODIS Gap filled Land Surface Temperature Daily"
1303
+ ):
1304
+ out_gif = geemap.create_timelapse(
1305
+ st.session_state.get("ee_asset_id"),
1306
+ start_date=start_date.strftime("%Y-%m-%d"),
1307
+ end_date=end_date.strftime("%Y-%m-%d"),
1308
+ region=roi,
1309
+ bands=None,
1310
+ frequency=frequency,
1311
+ reducer=reducer,
1312
+ date_format=None,
1313
+ out_gif=out_gif,
1314
+ palette=st.session_state.get("palette"),
1315
+ vis_params=None,
1316
+ dimensions=768,
1317
+ frames_per_second=speed,
1318
+ crs="EPSG:3857",
1319
+ overlay_data=overlay_data,
1320
+ overlay_color=overlay_color,
1321
+ overlay_width=overlay_width,
1322
+ overlay_opacity=overlay_opacity,
1323
+ title=title,
1324
+ title_xy=("2%", "90%"),
1325
+ add_text=True,
1326
+ text_xy=("2%", "2%"),
1327
+ text_sequence=None,
1328
+ font_type=font_type,
1329
+ font_size=font_size,
1330
+ font_color=font_color,
1331
+ add_progress_bar=add_progress_bar,
1332
+ progress_bar_color=progress_bar_color,
1333
+ progress_bar_height=5,
1334
+ add_colorbar=add_colorbar,
1335
+ colorbar_label=colorbar_label,
1336
+ loop=0,
1337
+ mp4=mp4,
1338
+ fading=fading,
1339
+ )
1340
+ elif collection == "MODIS Ocean Color SMI":
1341
+ if vis_params.startswith("{") and vis_params.endswith(
1342
+ "}"
1343
+ ):
1344
+ vis_params = eval(vis_params)
1345
+ else:
1346
+ vis_params = None
1347
+ out_gif = geemap.modis_ocean_color_timelapse(
1348
+ st.session_state.get("ee_asset_id"),
1349
+ start_date=start_date.strftime("%Y-%m-%d"),
1350
+ end_date=end_date.strftime("%Y-%m-%d"),
1351
+ region=roi,
1352
+ bands=st.session_state["band"],
1353
+ frequency=frequency,
1354
+ reducer=reducer,
1355
+ date_format=None,
1356
+ out_gif=out_gif,
1357
+ palette=st.session_state.get("palette"),
1358
+ vis_params=vis_params,
1359
+ dimensions=768,
1360
+ frames_per_second=speed,
1361
+ crs="EPSG:3857",
1362
+ overlay_data=overlay_data,
1363
+ overlay_color=overlay_color,
1364
+ overlay_width=overlay_width,
1365
+ overlay_opacity=overlay_opacity,
1366
+ title=title,
1367
+ title_xy=("2%", "90%"),
1368
+ add_text=True,
1369
+ text_xy=("2%", "2%"),
1370
+ text_sequence=None,
1371
+ font_type=font_type,
1372
+ font_size=font_size,
1373
+ font_color=font_color,
1374
+ add_progress_bar=add_progress_bar,
1375
+ progress_bar_color=progress_bar_color,
1376
+ progress_bar_height=5,
1377
+ add_colorbar=add_colorbar,
1378
+ colorbar_label=colorbar_label,
1379
+ loop=0,
1380
+ mp4=mp4,
1381
+ fading=fading,
1382
+ )
1383
+ except:
1384
+ empty_text.error(
1385
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1386
+ )
1387
+
1388
+ if out_gif is not None and os.path.exists(out_gif):
1389
+
1390
+ geemap.reduce_gif_size(out_gif)
1391
+
1392
+ empty_text.text(
1393
+ "Right click the GIF to save it to your computer👇"
1394
+ )
1395
+ empty_image.image(out_gif)
1396
+
1397
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1398
+ if mp4 and os.path.exists(out_mp4):
1399
+ with empty_video:
1400
+ st.text(
1401
+ "Right click the MP4 to save it to your computer👇"
1402
+ )
1403
+ st.video(out_gif.replace(".gif", ".mp4"))
1404
+
1405
+ else:
1406
+ st.error(
1407
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1408
+ )
1409
+
1410
+ elif collection == "USDA National Agriculture Imagery Program (NAIP)":
1411
+
1412
+ with st.form("submit_naip_form"):
1413
+ with st.expander("Customize timelapse"):
1414
+
1415
+ title = st.text_input(
1416
+ "Enter a title to show on the timelapse: ", "NAIP Timelapse"
1417
+ )
1418
+
1419
+ years = st.slider(
1420
+ "Start and end year:",
1421
+ 2003,
1422
+ today.year,
1423
+ (2003, today.year),
1424
+ )
1425
+
1426
+ bands = st.selectbox(
1427
+ "Select a band combination:", ["N/R/G", "R/G/B"], index=0
1428
+ )
1429
+
1430
+ speed = st.slider("Frames per second:", 1, 30, 3)
1431
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1432
+ progress_bar_color = st.color_picker(
1433
+ "Progress bar color:", "#0000ff"
1434
+ )
1435
+ font_size = st.slider("Font size:", 10, 50, 30)
1436
+ font_color = st.color_picker("Font color:", "#ffffff")
1437
+ font_type = st.selectbox(
1438
+ "Select the font type for the title:",
1439
+ ["arial.ttf", "alibaba.otf"],
1440
+ index=0,
1441
+ )
1442
+ fading = st.slider(
1443
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1444
+ )
1445
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1446
+
1447
+ empty_text = st.empty()
1448
+ empty_image = st.empty()
1449
+ empty_video = st.container()
1450
+ empty_fire_image = st.empty()
1451
+
1452
+ roi = None
1453
+ if st.session_state.get("roi") is not None:
1454
+ roi = st.session_state.get("roi")
1455
+ out_gif = geemap.temp_file_path(".gif")
1456
+
1457
+ submitted = st.form_submit_button("Submit")
1458
+ if submitted:
1459
+
1460
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1461
+ empty_text.warning(
1462
+ "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
1463
+ )
1464
+ else:
1465
+
1466
+ empty_text.text("Computing... Please wait...")
1467
+ try:
1468
+ geemap.naip_timelapse(
1469
+ roi,
1470
+ years[0],
1471
+ years[1],
1472
+ out_gif,
1473
+ bands=bands.split("/"),
1474
+ palette=st.session_state.get("palette"),
1475
+ vis_params=None,
1476
+ dimensions=768,
1477
+ frames_per_second=speed,
1478
+ crs="EPSG:3857",
1479
+ overlay_data=overlay_data,
1480
+ overlay_color=overlay_color,
1481
+ overlay_width=overlay_width,
1482
+ overlay_opacity=overlay_opacity,
1483
+ title=title,
1484
+ title_xy=("2%", "90%"),
1485
+ add_text=True,
1486
+ text_xy=("2%", "2%"),
1487
+ text_sequence=None,
1488
+ font_type=font_type,
1489
+ font_size=font_size,
1490
+ font_color=font_color,
1491
+ add_progress_bar=add_progress_bar,
1492
+ progress_bar_color=progress_bar_color,
1493
+ progress_bar_height=5,
1494
+ loop=0,
1495
+ mp4=mp4,
1496
+ fading=fading,
1497
+ )
1498
+ except:
1499
+ empty_text.error(
1500
+ "Something went wrong. You either requested too much data or the ROI is outside the U.S."
1501
+ )
1502
+
1503
+ if out_gif is not None and os.path.exists(out_gif):
1504
+
1505
+ empty_text.text(
1506
+ "Right click the GIF to save it to your computer👇"
1507
+ )
1508
+ empty_image.image(out_gif)
1509
+
1510
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1511
+ if mp4 and os.path.exists(out_mp4):
1512
+ with empty_video:
1513
+ st.text(
1514
+ "Right click the MP4 to save it to your computer👇"
1515
+ )
1516
+ st.video(out_gif.replace(".gif", ".mp4"))
1517
+
1518
+ else:
1519
+ st.error(
1520
+ "Something went wrong. You either requested too much data or the ROI is outside the U.S."
1521
+ )
1522
+
1523
+
1524
+ try:
1525
+ app()
1526
+ except Exception as e:
1527
+ pass