Spaces:
Sleeping
Sleeping
Added MODIS timelapse
Browse files- apps/home.py +1 -1
- apps/rois.py +71 -6
- apps/timelapse.py +96 -25
apps/home.py
CHANGED
@@ -7,7 +7,7 @@ def app():
|
|
7 |
|
8 |
st.markdown(
|
9 |
"""
|
10 |
-
This multi-page web app demonstrates various
|
11 |
such as [leafmap](https://leafmap.org), [geemap](https://geemap.org), [pydeck](https://deckgl.readthedocs.io), and [kepler.gl](https://docs.kepler.gl/docs/keplergl-jupyter).
|
12 |
This is an open-source project and you are very welcome to contribute your comments, questions, resources, and apps as [issues](https://github.com/giswqs/streamlit-geospatial/issues) or
|
13 |
[pull requests](https://github.com/giswqs/streamlit-geospatial/pulls) to the [GitHub repository](https://github.com/giswqs/streamlit-geospatial).
|
|
|
7 |
|
8 |
st.markdown(
|
9 |
"""
|
10 |
+
This multi-page web app demonstrates various interactive web apps created using [streamlit](https://streamlit.io) and open-source mapping libraries,
|
11 |
such as [leafmap](https://leafmap.org), [geemap](https://geemap.org), [pydeck](https://deckgl.readthedocs.io), and [kepler.gl](https://docs.kepler.gl/docs/keplergl-jupyter).
|
12 |
This is an open-source project and you are very welcome to contribute your comments, questions, resources, and apps as [issues](https://github.com/giswqs/streamlit-geospatial/issues) or
|
13 |
[pull requests](https://github.com/giswqs/streamlit-geospatial/pulls) to the [GitHub repository](https://github.com/giswqs/streamlit-geospatial).
|
apps/rois.py
CHANGED
@@ -5,12 +5,27 @@ from shapely.geometry import Polygon
|
|
5 |
|
6 |
goes_rois = {
|
7 |
"Creek Fire, CA (2020-09-05)": {
|
8 |
-
"region": Polygon(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
"start_time": "2020-09-05T15:00:00",
|
10 |
"end_time": "2020-09-06T02:00:00",
|
11 |
},
|
12 |
"Bomb Cyclone (2021-10-24)": {
|
13 |
-
"region": Polygon(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
"start_time": "2021-10-24T14:00:00",
|
15 |
"end_time": "2021-10-25T01:00:00",
|
16 |
},
|
@@ -18,9 +33,59 @@ goes_rois = {
|
|
18 |
|
19 |
|
20 |
landsat_rois = {
|
21 |
-
"Aral Sea": Polygon(
|
22 |
-
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
}
|
|
|
5 |
|
6 |
goes_rois = {
|
7 |
"Creek Fire, CA (2020-09-05)": {
|
8 |
+
"region": Polygon(
|
9 |
+
[
|
10 |
+
[-121.003418, 36.848857],
|
11 |
+
[-121.003418, 39.049052],
|
12 |
+
[-117.905273, 39.049052],
|
13 |
+
[-117.905273, 36.848857],
|
14 |
+
[-121.003418, 36.848857],
|
15 |
+
]
|
16 |
+
),
|
17 |
"start_time": "2020-09-05T15:00:00",
|
18 |
"end_time": "2020-09-06T02:00:00",
|
19 |
},
|
20 |
"Bomb Cyclone (2021-10-24)": {
|
21 |
+
"region": Polygon(
|
22 |
+
[
|
23 |
+
[-159.5954, 60.4088],
|
24 |
+
[-159.5954, 24.5178],
|
25 |
+
[-114.2438, 24.5178],
|
26 |
+
[-114.2438, 60.4088],
|
27 |
+
]
|
28 |
+
),
|
29 |
"start_time": "2021-10-24T14:00:00",
|
30 |
"end_time": "2021-10-25T01:00:00",
|
31 |
},
|
|
|
33 |
|
34 |
|
35 |
landsat_rois = {
|
36 |
+
"Aral Sea": Polygon(
|
37 |
+
[
|
38 |
+
[57.667236, 43.834527],
|
39 |
+
[57.667236, 45.996962],
|
40 |
+
[61.12793, 45.996962],
|
41 |
+
[61.12793, 43.834527],
|
42 |
+
[57.667236, 43.834527],
|
43 |
+
]
|
44 |
+
),
|
45 |
+
"Dubai": Polygon(
|
46 |
+
[
|
47 |
+
[54.541626, 24.763044],
|
48 |
+
[54.541626, 25.427152],
|
49 |
+
[55.632019, 25.427152],
|
50 |
+
[55.632019, 24.763044],
|
51 |
+
[54.541626, 24.763044],
|
52 |
+
]
|
53 |
+
),
|
54 |
+
"Las Vegas, NV": Polygon(
|
55 |
+
[
|
56 |
+
[-115.554199, 35.804449],
|
57 |
+
[-115.554199, 36.558188],
|
58 |
+
[-113.903503, 36.558188],
|
59 |
+
[-113.903503, 35.804449],
|
60 |
+
[-115.554199, 35.804449],
|
61 |
+
]
|
62 |
+
),
|
63 |
+
"Pucallpa, Peru": Polygon(
|
64 |
+
[
|
65 |
+
[-74.672699, -8.600032],
|
66 |
+
[-74.672699, -8.254983],
|
67 |
+
[-74.279938, -8.254983],
|
68 |
+
[-74.279938, -8.600032],
|
69 |
+
]
|
70 |
+
),
|
71 |
+
}
|
72 |
|
73 |
+
modis_rois = {
|
74 |
+
"Africa": Polygon(
|
75 |
+
[
|
76 |
+
[-18.6983, 38.1446],
|
77 |
+
[-18.6983, -36.1630],
|
78 |
+
[52.2293, -36.1630],
|
79 |
+
[52.2293, 38.1446],
|
80 |
+
]
|
81 |
+
),
|
82 |
+
"USA": Polygon(
|
83 |
+
[
|
84 |
+
[-127.177734, 23.725012],
|
85 |
+
[-127.177734, 50.792047],
|
86 |
+
[-66.269531, 50.792047],
|
87 |
+
[-66.269531, 23.725012],
|
88 |
+
[-127.177734, 23.725012],
|
89 |
+
]
|
90 |
+
),
|
91 |
}
|
apps/timelapse.py
CHANGED
@@ -5,8 +5,7 @@ import folium
|
|
5 |
import streamlit as st
|
6 |
import geemap.foliumap as geemap
|
7 |
from datetime import date
|
8 |
-
from
|
9 |
-
from .rois import goes_rois, landsat_rois
|
10 |
|
11 |
|
12 |
@st.cache
|
@@ -17,8 +16,7 @@ def uploaded_file_to_gdf(data):
|
|
17 |
|
18 |
_, file_extension = os.path.splitext(data.name)
|
19 |
file_id = str(uuid.uuid4())
|
20 |
-
file_path = os.path.join(tempfile.gettempdir(),
|
21 |
-
f"{file_id}{file_extension}")
|
22 |
|
23 |
with open(file_path, "wb") as file:
|
24 |
file.write(data.getbuffer())
|
@@ -70,6 +68,7 @@ def app():
|
|
70 |
[
|
71 |
"Landsat TM-ETM-OLI Surface Reflectance",
|
72 |
"Geostationary Operational Environmental Satellites (GOES)",
|
|
|
73 |
],
|
74 |
index=0,
|
75 |
)
|
@@ -78,9 +77,11 @@ def app():
|
|
78 |
roi_options = ["Uploaded GeoJSON"] + list(landsat_rois.keys())
|
79 |
|
80 |
elif collection == "Geostationary Operational Environmental Satellites (GOES)":
|
81 |
-
|
82 |
roi_options = ["Uploaded GeoJSON"] + list(goes_rois.keys())
|
83 |
|
|
|
|
|
|
|
84 |
sample_roi = st.selectbox(
|
85 |
"Select a sample ROI or upload a GeoJSON file:",
|
86 |
roi_options,
|
@@ -91,7 +92,9 @@ def app():
|
|
91 |
# m = geemap.Map(basemap="HYBRID", plugin_Draw=True, draw_export=True)
|
92 |
# m.add_basemap("ROADMAP")
|
93 |
|
94 |
-
with st.expander(
|
|
|
|
|
95 |
video_empty = st.empty()
|
96 |
|
97 |
data = st.file_uploader(
|
@@ -105,12 +108,14 @@ def app():
|
|
105 |
# st.info(
|
106 |
# "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"
|
107 |
# )
|
108 |
-
if
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
114 |
else:
|
115 |
if collection == "Landsat TM-ETM-OLI Surface Reflectance":
|
116 |
gdf = gpd.GeoDataFrame(
|
@@ -123,6 +128,10 @@ def app():
|
|
123 |
gdf = gpd.GeoDataFrame(
|
124 |
index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
|
125 |
)
|
|
|
|
|
|
|
|
|
126 |
|
127 |
if sample_roi != "Uploaded GeoJSON":
|
128 |
|
@@ -137,6 +146,10 @@ def app():
|
|
137 |
gdf = gpd.GeoDataFrame(
|
138 |
index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
|
139 |
)
|
|
|
|
|
|
|
|
|
140 |
st.session_state["roi"] = geemap.geopandas_to_ee(gdf)
|
141 |
m.add_gdf(gdf, "ROI")
|
142 |
elif data:
|
@@ -186,8 +199,7 @@ def app():
|
|
186 |
"Progress bar color:", "#0000ff"
|
187 |
)
|
188 |
years = st.slider(
|
189 |
-
"Start and end year:", 1984, today.year, (
|
190 |
-
1984, today.year - 1)
|
191 |
)
|
192 |
months = st.slider("Start and end month:", 1, 12, (5, 10))
|
193 |
font_size = st.slider("Font size:", 10, 50, 30)
|
@@ -271,8 +283,7 @@ def app():
|
|
271 |
roi = st.session_state.get("roi")
|
272 |
out_gif = geemap.temp_file_path(".gif")
|
273 |
|
274 |
-
satellite = st.selectbox("Select a satellite:", [
|
275 |
-
"GOES-17", "GOES-16"])
|
276 |
earliest_date = datetime.date(2017, 7, 10)
|
277 |
latest_date = datetime.date.today()
|
278 |
|
@@ -287,8 +298,7 @@ def app():
|
|
287 |
roi_start_date = datetime.datetime.strptime(
|
288 |
roi_start[:10], "%Y-%m-%d"
|
289 |
)
|
290 |
-
roi_end_date = datetime.datetime.strptime(
|
291 |
-
roi_end[:10], "%Y-%m-%d")
|
292 |
roi_start_time = datetime.time(
|
293 |
int(roi_start[11:13]), int(roi_start[14:16])
|
294 |
)
|
@@ -296,18 +306,15 @@ def app():
|
|
296 |
int(roi_end[11:13]), int(roi_end[14:16])
|
297 |
)
|
298 |
|
299 |
-
start_date = st.date_input(
|
300 |
-
"Select the start date:", roi_start_date)
|
301 |
end_date = st.date_input("Select the end date:", roi_end_date)
|
302 |
|
303 |
with st.expander("Customize timelapse"):
|
304 |
|
305 |
-
add_fire = st.checkbox(
|
306 |
-
"Add Fire/Hotspot Characterization", False)
|
307 |
|
308 |
scan_type = st.selectbox(
|
309 |
-
"Select a scan type:", [
|
310 |
-
"Full Disk", "CONUS", "Mesoscale"]
|
311 |
)
|
312 |
|
313 |
start_time = st.time_input(
|
@@ -379,7 +386,8 @@ def app():
|
|
379 |
if add_fire:
|
380 |
out_fire_gif = geemap.temp_file_path(".gif")
|
381 |
empty_fire_text.text(
|
382 |
-
"Delineating Fire Hotspot... Please wait..."
|
|
|
383 |
geemap.goes_fire_timelapse(
|
384 |
out_fire_gif,
|
385 |
start_date=start,
|
@@ -406,3 +414,66 @@ def app():
|
|
406 |
empty_text.text(
|
407 |
"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."
|
408 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
import streamlit as st
|
6 |
import geemap.foliumap as geemap
|
7 |
from datetime import date
|
8 |
+
from .rois import *
|
|
|
9 |
|
10 |
|
11 |
@st.cache
|
|
|
16 |
|
17 |
_, file_extension = os.path.splitext(data.name)
|
18 |
file_id = str(uuid.uuid4())
|
19 |
+
file_path = os.path.join(tempfile.gettempdir(), f"{file_id}{file_extension}")
|
|
|
20 |
|
21 |
with open(file_path, "wb") as file:
|
22 |
file.write(data.getbuffer())
|
|
|
68 |
[
|
69 |
"Landsat TM-ETM-OLI Surface Reflectance",
|
70 |
"Geostationary Operational Environmental Satellites (GOES)",
|
71 |
+
"MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
|
72 |
],
|
73 |
index=0,
|
74 |
)
|
|
|
77 |
roi_options = ["Uploaded GeoJSON"] + list(landsat_rois.keys())
|
78 |
|
79 |
elif collection == "Geostationary Operational Environmental Satellites (GOES)":
|
|
|
80 |
roi_options = ["Uploaded GeoJSON"] + list(goes_rois.keys())
|
81 |
|
82 |
+
elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
|
83 |
+
roi_options = ["Uploaded GeoJSON"] + list(modis_rois.keys())
|
84 |
+
|
85 |
sample_roi = st.selectbox(
|
86 |
"Select a sample ROI or upload a GeoJSON file:",
|
87 |
roi_options,
|
|
|
92 |
# m = geemap.Map(basemap="HYBRID", plugin_Draw=True, draw_export=True)
|
93 |
# m.add_basemap("ROADMAP")
|
94 |
|
95 |
+
with st.expander(
|
96 |
+
"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 👉"
|
97 |
+
):
|
98 |
video_empty = st.empty()
|
99 |
|
100 |
data = st.file_uploader(
|
|
|
108 |
# st.info(
|
109 |
# "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"
|
110 |
# )
|
111 |
+
if (
|
112 |
+
collection
|
113 |
+
== "Geostationary Operational Environmental Satellites (GOES)"
|
114 |
+
and (not keyword)
|
115 |
+
):
|
116 |
+
m.set_center(-100, 40, 3)
|
117 |
+
else:
|
118 |
+
m.set_center(4.20, 18.63, zoom=2)
|
119 |
else:
|
120 |
if collection == "Landsat TM-ETM-OLI Surface Reflectance":
|
121 |
gdf = gpd.GeoDataFrame(
|
|
|
128 |
gdf = gpd.GeoDataFrame(
|
129 |
index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
|
130 |
)
|
131 |
+
elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
|
132 |
+
gdf = gpd.GeoDataFrame(
|
133 |
+
index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
|
134 |
+
)
|
135 |
|
136 |
if sample_roi != "Uploaded GeoJSON":
|
137 |
|
|
|
146 |
gdf = gpd.GeoDataFrame(
|
147 |
index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
|
148 |
)
|
149 |
+
elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
|
150 |
+
gdf = gpd.GeoDataFrame(
|
151 |
+
index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
|
152 |
+
)
|
153 |
st.session_state["roi"] = geemap.geopandas_to_ee(gdf)
|
154 |
m.add_gdf(gdf, "ROI")
|
155 |
elif data:
|
|
|
199 |
"Progress bar color:", "#0000ff"
|
200 |
)
|
201 |
years = st.slider(
|
202 |
+
"Start and end year:", 1984, today.year, (1984, today.year)
|
|
|
203 |
)
|
204 |
months = st.slider("Start and end month:", 1, 12, (5, 10))
|
205 |
font_size = st.slider("Font size:", 10, 50, 30)
|
|
|
283 |
roi = st.session_state.get("roi")
|
284 |
out_gif = geemap.temp_file_path(".gif")
|
285 |
|
286 |
+
satellite = st.selectbox("Select a satellite:", ["GOES-17", "GOES-16"])
|
|
|
287 |
earliest_date = datetime.date(2017, 7, 10)
|
288 |
latest_date = datetime.date.today()
|
289 |
|
|
|
298 |
roi_start_date = datetime.datetime.strptime(
|
299 |
roi_start[:10], "%Y-%m-%d"
|
300 |
)
|
301 |
+
roi_end_date = datetime.datetime.strptime(roi_end[:10], "%Y-%m-%d")
|
|
|
302 |
roi_start_time = datetime.time(
|
303 |
int(roi_start[11:13]), int(roi_start[14:16])
|
304 |
)
|
|
|
306 |
int(roi_end[11:13]), int(roi_end[14:16])
|
307 |
)
|
308 |
|
309 |
+
start_date = st.date_input("Select the start date:", roi_start_date)
|
|
|
310 |
end_date = st.date_input("Select the end date:", roi_end_date)
|
311 |
|
312 |
with st.expander("Customize timelapse"):
|
313 |
|
314 |
+
add_fire = st.checkbox("Add Fire/Hotspot Characterization", False)
|
|
|
315 |
|
316 |
scan_type = st.selectbox(
|
317 |
+
"Select a scan type:", ["Full Disk", "CONUS", "Mesoscale"]
|
|
|
318 |
)
|
319 |
|
320 |
start_time = st.time_input(
|
|
|
386 |
if add_fire:
|
387 |
out_fire_gif = geemap.temp_file_path(".gif")
|
388 |
empty_fire_text.text(
|
389 |
+
"Delineating Fire Hotspot... Please wait..."
|
390 |
+
)
|
391 |
geemap.goes_fire_timelapse(
|
392 |
out_fire_gif,
|
393 |
start_date=start,
|
|
|
414 |
empty_text.text(
|
415 |
"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."
|
416 |
)
|
417 |
+
|
418 |
+
elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
|
419 |
+
|
420 |
+
video_empty.video("https://youtu.be/16fA2QORG4A")
|
421 |
+
|
422 |
+
satellite = st.selectbox("Select a satellite:", ["Terra", "Aqua"])
|
423 |
+
band = st.selectbox("Select a band:", ["NDVI", "EVI"])
|
424 |
+
|
425 |
+
with st.form("submit_modis_form"):
|
426 |
+
|
427 |
+
roi = None
|
428 |
+
if st.session_state.get("roi") is not None:
|
429 |
+
roi = st.session_state.get("roi")
|
430 |
+
out_gif = geemap.temp_file_path(".gif")
|
431 |
+
|
432 |
+
with st.expander("Customize timelapse"):
|
433 |
+
|
434 |
+
start = st.date_input(
|
435 |
+
"Select a start date:", datetime.date(2000, 2, 8)
|
436 |
+
)
|
437 |
+
end = st.date_input("Select an end date:", datetime.date.today())
|
438 |
+
|
439 |
+
start_date = start.strftime("%Y-%m-%d")
|
440 |
+
end_date = end.strftime("%Y-%m-%d")
|
441 |
+
|
442 |
+
speed = st.slider("Frames per second:", 1, 30, 10)
|
443 |
+
add_progress_bar = st.checkbox("Add a progress bar", True)
|
444 |
+
progress_bar_color = st.color_picker(
|
445 |
+
"Progress bar color:", "#0000ff"
|
446 |
+
)
|
447 |
+
font_size = st.slider("Font size:", 10, 50, 20)
|
448 |
+
font_color = st.color_picker("Font color:", "#ffffff")
|
449 |
+
empty_text = st.empty()
|
450 |
+
empty_image = st.empty()
|
451 |
+
|
452 |
+
submitted = st.form_submit_button("Submit")
|
453 |
+
if submitted:
|
454 |
+
if sample_roi == "Uploaded GeoJSON" and data is None:
|
455 |
+
empty_text.warning(
|
456 |
+
"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."
|
457 |
+
)
|
458 |
+
else:
|
459 |
+
|
460 |
+
empty_text.text("Computing... Please wait...")
|
461 |
+
|
462 |
+
print(roi.getInfo())
|
463 |
+
geemap.modis_ndvi_timelapse(
|
464 |
+
out_gif,
|
465 |
+
satellite,
|
466 |
+
band,
|
467 |
+
start_date,
|
468 |
+
end_date,
|
469 |
+
roi,
|
470 |
+
768,
|
471 |
+
speed,
|
472 |
+
)
|
473 |
+
|
474 |
+
geemap.reduce_gif_size(out_gif)
|
475 |
+
|
476 |
+
empty_text.text(
|
477 |
+
"Right click the GIF to save it to your computer👇"
|
478 |
+
)
|
479 |
+
empty_image.image(out_gif)
|