aassiiyAA123 commited on
Commit
1e932e0
·
verified ·
1 Parent(s): 9144f8c

Upload 469 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +5 -0
  2. y/.DS_Store +0 -0
  3. y/.gitignore +129 -0
  4. y/Home.py +2079 -0
  5. y/Interactive_Map.py +224 -0
  6. y/LICENSE +21 -0
  7. y/Timelapse.py +1534 -0
  8. y/__pycache__/Interactive_Map.cpython-312.pyc +0 -0
  9. y/__pycache__/Timelapse.cpython-312.pyc +0 -0
  10. y/custom.js +22 -0
  11. y/db.sqlite3 +0 -0
  12. y/djangoGEE/__init__.py +0 -0
  13. y/djangoGEE/__pycache__/__init__.cpython-311.pyc +0 -0
  14. y/djangoGEE/__pycache__/__init__.cpython-312.pyc +0 -0
  15. y/djangoGEE/__pycache__/__init__.cpython-39.pyc +0 -0
  16. y/djangoGEE/__pycache__/settings.cpython-311.pyc +0 -0
  17. y/djangoGEE/__pycache__/settings.cpython-312.pyc +0 -0
  18. y/djangoGEE/__pycache__/settings.cpython-39.pyc +0 -0
  19. y/djangoGEE/__pycache__/urls.cpython-311.pyc +0 -0
  20. y/djangoGEE/__pycache__/urls.cpython-312.pyc +0 -0
  21. y/djangoGEE/__pycache__/urls.cpython-39.pyc +0 -0
  22. y/djangoGEE/__pycache__/wsgi.cpython-311.pyc +0 -0
  23. y/djangoGEE/__pycache__/wsgi.cpython-312.pyc +0 -0
  24. y/djangoGEE/__pycache__/wsgi.cpython-39.pyc +0 -0
  25. y/djangoGEE/geoApp/__init__.py +0 -0
  26. y/djangoGEE/geoApp/__pycache__/__init__.cpython-310.pyc +0 -0
  27. y/djangoGEE/geoApp/__pycache__/__init__.cpython-39.pyc +0 -0
  28. y/djangoGEE/geoApp/__pycache__/admin.cpython-310.pyc +0 -0
  29. y/djangoGEE/geoApp/__pycache__/admin.cpython-39.pyc +0 -0
  30. y/djangoGEE/geoApp/__pycache__/apps.cpython-310.pyc +0 -0
  31. y/djangoGEE/geoApp/__pycache__/apps.cpython-39.pyc +0 -0
  32. y/djangoGEE/geoApp/__pycache__/models.cpython-310.pyc +0 -0
  33. y/djangoGEE/geoApp/__pycache__/models.cpython-39.pyc +0 -0
  34. y/djangoGEE/geoApp/__pycache__/urls.cpython-310.pyc +0 -0
  35. y/djangoGEE/geoApp/__pycache__/urls.cpython-39.pyc +0 -0
  36. y/djangoGEE/geoApp/__pycache__/views.cpython-310.pyc +0 -0
  37. y/djangoGEE/geoApp/__pycache__/views.cpython-39.pyc +0 -0
  38. y/djangoGEE/geoApp/admin.py +3 -0
  39. y/djangoGEE/geoApp/apps.py +6 -0
  40. y/djangoGEE/geoApp/geoApp/__init__.py +0 -0
  41. y/djangoGEE/geoApp/geoApp/admin.py +3 -0
  42. y/djangoGEE/geoApp/geoApp/apps.py +6 -0
  43. y/djangoGEE/geoApp/geoApp/migrations/__init__.py +0 -0
  44. y/djangoGEE/geoApp/geoApp/models.py +3 -0
  45. y/djangoGEE/geoApp/geoApp/tests.py +3 -0
  46. y/djangoGEE/geoApp/geoApp/views.py +3 -0
  47. y/djangoGEE/geoApp/manage.py +22 -0
  48. y/djangoGEE/geoApp/migrations/__init__.py +0 -0
  49. y/djangoGEE/geoApp/migrations/__pycache__/__init__.cpython-310.pyc +0 -0
  50. y/djangoGEE/geoApp/migrations/__pycache__/__init__.cpython-39.pyc +0 -0
.gitattributes CHANGED
@@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ y/media/shp/District_Boundary.shp filter=lfs diff=lfs merge=lfs -text
37
+ y/media/shp/hydro_basins.shp filter=lfs diff=lfs merge=lfs -text
38
+ y/media/shp/kenya_highland_roads.shp filter=lfs diff=lfs merge=lfs -text
39
+ y/media/shp/National_Constituency_with_Projected_2010_Population.shp filter=lfs diff=lfs merge=lfs -text
40
+ y/media/shp/Provincial_Constituency.shp filter=lfs diff=lfs merge=lfs -text
y/.DS_Store ADDED
Binary file (8.2 kB). View file
 
y/.gitignore ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
y/Home.py ADDED
@@ -0,0 +1,2079 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import folium
3
+ import geopandas as gpd
4
+ import json
5
+ import geemap.foliumap as geemap
6
+ import ee
7
+ import pandas as pd
8
+ import os
9
+ from google.auth.transport.requests import Request
10
+ import google.auth.exceptions
11
+ from streamlit.components.v1 import html
12
+ import ee
13
+ import json
14
+ import os
15
+ import datetime
16
+ import fiona
17
+ import geopandas as gpd
18
+ import folium
19
+ import streamlit as st
20
+ import geemap.colormaps as cm
21
+ import geemap.foliumap as geemap
22
+ from datetime import date
23
+ from shapely.geometry import Polygon
24
+ import leafmap.foliumap as leafmap
25
+
26
+
27
+
28
+ # Define the pages
29
+ def page_home():
30
+ st.title("Home Page")
31
+ st.write("Welcome to the Home Page!")
32
+
33
+ def page_about():
34
+ st.title("About Page")
35
+ st.write("The main purpose is to provide navigation to other pages/maps.")
36
+
37
+
38
+
39
+ # Path to your shapefiles and service account key
40
+ SHAPEFILE_DIR = 'C:/Users/piv/Desktop/y/media/shp'
41
+
42
+
43
+ #<-------------------------------------------------------------------- Google earth engine Authentication code-------------------------------------------------------------------------------->
44
+
45
+ def initialize_gee():
46
+ service = os.getenv('SA')
47
+ file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'gee', 'ee-muzzamil1-37ebc3dece52.json')
48
+ credentials = ee.ServiceAccountCredentials(service, file)
49
+ try:
50
+ ee.Initialize(credentials)
51
+ st.success("Google Earth Engine initialized successfully.")
52
+ except google.auth.exceptions.RefreshError:
53
+ try:
54
+ request = Request()
55
+ credentials.refresh(request)
56
+ ee.Initialize(credentials)
57
+ st.success("Google Earth Engine token refreshed and initialized successfully.")
58
+ except Exception as e:
59
+ st.error(f"Error refreshing Google Earth Engine token: {e}")
60
+ except Exception as e:
61
+ st.error(f"Error initializing Google Earth Engine: {e}")
62
+
63
+ #<---------------------------------------------------------------Interactive map code used to callin home page (Navigation purpose)---------------------------------------------------------------------------------->
64
+
65
+ def interactive_map_page():
66
+ st.title("Interactive Map")
67
+ create_sidebar_controls()
68
+
69
+ map_col, control_col = st.columns([3, 1]) # Adjust column width ratios as needed
70
+
71
+ with map_col:
72
+ if 'submitted' in st.session_state and st.session_state.submitted:
73
+ st.markdown("### Satellite Data Map")
74
+ st.components.v1.html(st.session_state.folium_map_html, height=600)
75
+
76
+ with control_col:
77
+ st.header("Map Controls")
78
+
79
+ def create_folium_map(selected_dataset, ee_object, start_date_str, end_date_str):
80
+ folium_map = folium.Map(location=[25.5973518, 65.54495724], zoom_start=7)
81
+
82
+ try:
83
+ if selected_dataset == "Modis":
84
+ dataset = ee.ImageCollection('MODIS/006/MOD13Q1') \
85
+ .filter(ee.Filter.date(start_date_str, end_date_str)) \
86
+ .filterBounds(ee_object)
87
+
88
+ def clip_image(img):
89
+ return img.clip(ee_object).select('NDVI')
90
+
91
+ clipped_collection = dataset.map(clip_image)
92
+ modis_ndvi = clipped_collection.mean()
93
+ vis_params_ndvi = {
94
+ 'min': 0,
95
+ 'max': 9000,
96
+ 'palette': ['FE8374', 'C0E5DE', '3A837C', '034B48']
97
+ }
98
+ modis_ndvi_map_id = modis_ndvi.getMapId(vis_params_ndvi)
99
+ folium.TileLayer(
100
+ tiles=modis_ndvi_map_id['tile_fetcher'].url_format,
101
+ attr='Google Earth Engine',
102
+ name='NDVI',
103
+ overlay=True,
104
+ control=True
105
+ ).add_to(folium_map)
106
+
107
+ elif selected_dataset == "dataset_nighttime":
108
+ dataset_nighttime = ee.ImageCollection('NOAA/VIIRS/DNB/MONTHLY_V1/VCMCFG') \
109
+ .filter(ee.Filter.date(start_date_str, end_date_str))
110
+
111
+ nighttime = dataset_nighttime.select('avg_rad').mosaic()
112
+ nighttime_clipped = nighttime.clip(ee_object)
113
+ nighttime_vis = {
114
+ 'min': 0.0,
115
+ 'max': 60.0,
116
+ 'palette': ['1a3678', '2955bc', '5699ff', '8dbae9', 'acd1ff', 'caebff', 'e5f9ff', 'fdffb4', 'ffe6a2', 'ffc969', 'ffa12d', 'ff7c1f', 'ca531a', 'ff0000', 'ab0000']
117
+ }
118
+ nighttime_map_id = nighttime_clipped.getMapId(nighttime_vis)
119
+ folium.TileLayer(
120
+ tiles=nighttime_map_id['tile_fetcher'].url_format,
121
+ attr='Google Earth Engine',
122
+ name='Nighttime Lights',
123
+ overlay=True,
124
+ control=True
125
+ ).add_to(folium_map)
126
+
127
+ elif selected_dataset == "precipitation":
128
+ dataset_precipitation = ee.ImageCollection('UCSB-CHG/CHIRPS/DAILY') \
129
+ .filter(ee.Filter.date(start_date_str, end_date_str))
130
+
131
+ precipitation = dataset_precipitation.mosaic().clip(ee_object)
132
+ precip_vis = {
133
+ 'min': 0,
134
+ 'max': 300,
135
+ 'palette': ['blue', 'cyan', 'lime', 'yellow', 'red']
136
+ }
137
+ precip_map_id = precipitation.getMapId(precip_vis)
138
+ folium.TileLayer(
139
+ tiles=precip_map_id['tile_fetcher'].url_format,
140
+ attr='Google Earth Engine',
141
+ name='Precipitation',
142
+ overlay=True,
143
+ control=True
144
+ ).add_to(folium_map)
145
+
146
+ elif selected_dataset == "GlobalSurfaceWater":
147
+ st.warning("GlobalSurfaceWater dataset is not configured.")
148
+
149
+ elif selected_dataset == "WorldPop":
150
+ dataset = ee.ImageCollection('WorldPop/GP/100m/pop') \
151
+ .filterBounds(ee_object) \
152
+ .filter(ee.Filter.date(start_date_str, end_date_str))
153
+
154
+ population = dataset.mean().clip(ee_object)
155
+ pop_vis = {
156
+ 'min': 0,
157
+ 'max': 1000,
158
+ 'palette': ['blue', 'green', 'yellow', 'red']
159
+ }
160
+ pop_map_id = population.getMapId(pop_vis)
161
+ folium.TileLayer(
162
+ tiles=pop_map_id['tile_fetcher'].url_format,
163
+ attr='Google Earth Engine',
164
+ name='World Population',
165
+ overlay=True,
166
+ control=True
167
+ ).add_to(folium_map)
168
+
169
+ elif selected_dataset == "COPERNICUS":
170
+ dataset = ee.ImageCollection('COPERNICUS/S2') \
171
+ .filterBounds(ee_object) \
172
+ .filter(ee.Filter.date(start_date_str, end_date_str))
173
+
174
+ sentinel = dataset.median().clip(ee_object)
175
+ vis_params = {
176
+ 'bands': ['B4', 'B3', 'B2'],
177
+ 'min': 0,
178
+ 'max': 3000,
179
+ 'gamma': 1.4
180
+ }
181
+ copernicus_map_id = sentinel.getMapId(vis_params)
182
+ folium.TileLayer(
183
+ tiles=copernicus_map_id['tile_fetcher'].url_format,
184
+ attr='Google Earth Engine',
185
+ name='Copernicus Sentinel-2',
186
+ overlay=True,
187
+ control=True
188
+ ).add_to(folium_map)
189
+
190
+ folium_map.add_child(folium.LayerControl())
191
+ except Exception as e:
192
+ st.error(f"Error processing dataset: {e}")
193
+
194
+ folium_map_html = folium_map._repr_html_()
195
+ return folium_map_html
196
+
197
+ def handle_submit(selected_dataset, selected_date_range_From, selected_date_range_To, selected_shape):
198
+ shapefile_name = f'{selected_shape}.shp'
199
+ shapefile_path = os.path.join(SHAPEFILE_DIR, shapefile_name)
200
+
201
+ if os.path.exists(shapefile_path):
202
+ try:
203
+ roi_gdf = gpd.read_file(shapefile_path)
204
+ roi_geojson = roi_gdf.to_crs("EPSG:4326").to_json()
205
+ except Exception as e:
206
+ st.error(f"Error reading shapefile: {e}")
207
+ return
208
+
209
+ try:
210
+ ee_object = geemap.geojson_to_ee(json.loads(roi_geojson))
211
+ except Exception as e:
212
+ st.error(f"Error converting GeoJSON to Earth Engine object: {e}")
213
+ return
214
+
215
+ st.markdown("### Satellite Data Map")
216
+ folium_map_html = create_folium_map(
217
+ selected_dataset,
218
+ ee_object,
219
+ selected_date_range_From.strftime('%Y-%m-%d'),
220
+ selected_date_range_To.strftime('%Y-%m-%d')
221
+ )
222
+ st.session_state.folium_map_html = folium_map_html
223
+ else:
224
+ st.error("Selected shapefile does not exist.")
225
+
226
+ def create_sidebar_controls():
227
+ with st.sidebar:
228
+ selected_dataset = st.selectbox(
229
+ "Select Dataset",
230
+ ["Modis", "dataset_nighttime", 'precipitation', 'GlobalSurfaceWater', 'WorldPop', 'COPERNICUS'],
231
+ key='sidebar_dataset_selectbox'
232
+ )
233
+
234
+ selected_date_range_From = st.date_input(
235
+ "From",
236
+ value=pd.to_datetime("2015-07-01"),
237
+ key='sidebar_date_from'
238
+ )
239
+ selected_date_range_To = st.date_input(
240
+ "To",
241
+ value=pd.to_datetime("2023-09-30"),
242
+ key='sidebar_date_to'
243
+ )
244
+
245
+ shape_options = [
246
+ 'District_Boundary', 'hydro_basins', 'karachi',
247
+ 'National_Constituency_with_Projected_2010_Population',
248
+ 'Provincial_Boundary', 'Provincial_Constituency',
249
+ 'Tehsil_Boundary', 'Union_Council'
250
+ ]
251
+
252
+ selected_shape = st.selectbox(
253
+ "Select Shape",
254
+ shape_options,
255
+ key='sidebar_shape_selectbox'
256
+ )
257
+
258
+ if st.button("Submit", key='sidebar_submit_button'):
259
+ st.session_state.selected_dataset = selected_dataset
260
+ st.session_state.selected_date_range_From = selected_date_range_From
261
+ st.session_state.selected_date_range_To = selected_date_range_To
262
+ st.session_state.selected_shape = selected_shape
263
+ st.session_state.submitted = True
264
+ else:
265
+ st.session_state.submitted = False
266
+
267
+ if 'submitted' in st.session_state and st.session_state.submitted:
268
+ handle_submit(
269
+ st.session_state.selected_dataset,
270
+ st.session_state.selected_date_range_From,
271
+ st.session_state.selected_date_range_To,
272
+ st.session_state.selected_shape
273
+ )
274
+
275
+
276
+ def interactive_map_page():
277
+ st.title("Interactive Map")
278
+ submit_control()
279
+
280
+ #<------------------------------------------------------- Interactive map code------------------------------------------------------------------------------------------------------------------->
281
+
282
+
283
+
284
+ # Create two columns: one for the map and one for the controls
285
+ map_col, control_col = st.columns([3, 1]) # Adjust column width ratios as needed
286
+
287
+ # Map column
288
+ with map_col:
289
+ if 'submitted' in st.session_state and st.session_state.submitted:
290
+ st.markdown("### Satellite Data Map")
291
+ st.components.v1.html(st.session_state.folium_map_html, height=600)
292
+
293
+ # Control column
294
+ with control_col:
295
+ st.header("Map Controls")
296
+ selected_dataset = st.selectbox(
297
+ "Select Dataset",
298
+ ["Modis", "dataset_nighttime", 'precipitation', 'GlobalSurfaceWater', 'WorldPop', 'COPERNICUS']
299
+ )
300
+
301
+ selected_date_range_From = st.date_input("From", value=pd.to_datetime("2015-07-01"))
302
+ selected_date_range_To = st.date_input("To", value=pd.to_datetime("2023-09-30"))
303
+
304
+ shape_options = [
305
+ 'District_Boundary', 'hydro_basins', 'karachi',
306
+ 'National_Constituency_with_Projected_2010_Population',
307
+ 'Provincial_Boundary', 'Provincial_Constituency',
308
+ 'Tehsil_Boundary', 'Union_Council'
309
+ ]
310
+
311
+ selected_shape = st.selectbox("Select Shape", shape_options)
312
+
313
+ if st.button("Submit"):
314
+ handle_submit(
315
+ selected_dataset,
316
+ selected_date_range_From,
317
+ selected_date_range_To,
318
+ selected_shape
319
+ )
320
+
321
+
322
+ def create_folium_map(selected_dataset, ee_object, start_date_str, end_date_str):
323
+ folium_map = folium.Map(location=[25.5973518, 65.54495724], zoom_start=7)
324
+
325
+ try:
326
+ if selected_dataset == "Modis":
327
+ dataset = ee.ImageCollection('MODIS/006/MOD13Q1') \
328
+ .filter(ee.Filter.date(start_date_str, end_date_str)) \
329
+ .filterBounds(ee_object)
330
+
331
+ def clip_image(img):
332
+ return img.clip(ee_object).select('NDVI')
333
+
334
+ clipped_collection = dataset.map(clip_image)
335
+ modis_ndvi = clipped_collection.mean()
336
+ vis_params_ndvi = {
337
+ 'min': 0,
338
+ 'max': 9000,
339
+ 'palette': ['FE8374', 'C0E5DE', '3A837C', '034B48']
340
+ }
341
+ modis_ndvi_map_id = modis_ndvi.getMapId(vis_params_ndvi)
342
+ folium.TileLayer(
343
+ tiles=modis_ndvi_map_id['tile_fetcher'].url_format,
344
+ attr='Google Earth Engine',
345
+ name='NDVI',
346
+ overlay=True,
347
+ control=True
348
+ ).add_to(folium_map)
349
+
350
+ elif selected_dataset == "dataset_nighttime":
351
+ dataset_nighttime = ee.ImageCollection('NOAA/VIIRS/DNB/MONTHLY_V1/VCMCFG') \
352
+ .filter(ee.Filter.date(start_date_str, end_date_str))
353
+
354
+ nighttime = dataset_nighttime.select('avg_rad').mosaic()
355
+ nighttime_clipped = nighttime.clip(ee_object)
356
+ nighttime_vis = {
357
+ 'min': 0.0,
358
+ 'max': 60.0,
359
+ 'palette': ['1a3678', '2955bc', '5699ff', '8dbae9', 'acd1ff', 'caebff', 'e5f9ff', 'fdffb4', 'ffe6a2', 'ffc969', 'ffa12d', 'ff7c1f', 'ca531a', 'ff0000', 'ab0000']
360
+ }
361
+ nighttime_map_id = nighttime_clipped.getMapId(nighttime_vis)
362
+ folium.TileLayer(
363
+ tiles=nighttime_map_id['tile_fetcher'].url_format,
364
+ attr='Google Earth Engine',
365
+ name='Nighttime Lights',
366
+ overlay=True,
367
+ control=True
368
+ ).add_to(folium_map)
369
+
370
+ elif selected_dataset == "precipitation":
371
+ dataset_precipitation = ee.ImageCollection('UCSB-CHG/CHIRPS/DAILY') \
372
+ .filter(ee.Filter.date(start_date_str, end_date_str))
373
+
374
+ precipitation = dataset_precipitation.mosaic().clip(ee_object)
375
+ precip_vis = {
376
+ 'min': 0,
377
+ 'max': 300,
378
+ 'palette': ['blue', 'cyan', 'lime', 'yellow', 'red']
379
+ }
380
+ precip_map_id = precipitation.getMapId(precip_vis)
381
+ folium.TileLayer(
382
+ tiles=precip_map_id['tile_fetcher'].url_format,
383
+ attr='Google Earth Engine',
384
+ name='Precipitation',
385
+ overlay=True,
386
+ control=True
387
+ ).add_to(folium_map)
388
+
389
+ elif selected_dataset == "GlobalSurfaceWater":
390
+ st.warning("GlobalSurfaceWater dataset is not configured.")
391
+
392
+ elif selected_dataset == "WorldPop":
393
+ dataset = ee.ImageCollection('WorldPop/GP/100m/pop') \
394
+ .filterBounds(ee_object) \
395
+ .filter(ee.Filter.date(start_date_str, end_date_str))
396
+
397
+ population = dataset.mean().clip(ee_object)
398
+ pop_vis = {
399
+ 'min': 0,
400
+ 'max': 1000,
401
+ 'palette': ['blue', 'green', 'yellow', 'red']
402
+ }
403
+ pop_map_id = population.getMapId(pop_vis)
404
+ folium.TileLayer(
405
+ tiles=pop_map_id['tile_fetcher'].url_format,
406
+ attr='Google Earth Engine',
407
+ name='World Population',
408
+ overlay=True,
409
+ control=True
410
+ ).add_to(folium_map)
411
+
412
+ elif selected_dataset == "COPERNICUS":
413
+ dataset = ee.ImageCollection('COPERNICUS/S2') \
414
+ .filterBounds(ee_object) \
415
+ .filter(ee.Filter.date(start_date_str, end_date_str))
416
+
417
+ sentinel = dataset.median().clip(ee_object)
418
+ vis_params = {
419
+ 'bands': ['B4', 'B3', 'B2'],
420
+ 'min': 0,
421
+ 'max': 3000,
422
+ 'gamma': 1.4
423
+ }
424
+ copernicus_map_id = sentinel.getMapId(vis_params)
425
+ folium.TileLayer(
426
+ tiles=copernicus_map_id['tile_fetcher'].url_format,
427
+ attr='Google Earth Engine',
428
+ name='Copernicus Sentinel-2',
429
+ overlay=True,
430
+ control=True
431
+ ).add_to(folium_map)
432
+
433
+ folium_map.add_child(folium.LayerControl())
434
+ except Exception as e:
435
+ st.error(f"Error processing dataset: {e}")
436
+
437
+ folium_map_html = folium_map._repr_html_()
438
+ return folium_map_html
439
+
440
+ def handle_submit(selected_dataset, selected_date_range_From, selected_date_range_To, selected_shape):
441
+ shapefile_name = f'{selected_shape}.shp'
442
+ shapefile_path = os.path.join(SHAPEFILE_DIR, shapefile_name)
443
+
444
+ if os.path.exists(shapefile_path):
445
+ try:
446
+ roi_gdf = gpd.read_file(shapefile_path)
447
+ roi_geojson = roi_gdf.to_crs("EPSG:4326").to_json()
448
+ except Exception as e:
449
+ st.error(f"Error reading shapefile: {e}")
450
+ return
451
+
452
+ try:
453
+ ee_object = geemap.geojson_to_ee(json.loads(roi_geojson))
454
+ except Exception as e:
455
+ st.error(f"Error converting GeoJSON to Earth Engine object: {e}")
456
+ return
457
+
458
+ st.markdown("### Satellite Data Map")
459
+ folium_map_html = create_folium_map(
460
+ selected_dataset,
461
+ ee_object,
462
+ selected_date_range_From.strftime('%Y-%m-%d'),
463
+ selected_date_range_To.strftime('%Y-%m-%d')
464
+ )
465
+ html(folium_map_html, height=600)
466
+ else:
467
+ st.error("Selected shapefile does not exist.")
468
+
469
+ def submit_control():
470
+ selected_dataset = st.sidebar.selectbox(
471
+ "Select Dataset",
472
+ ["Modis", "dataset_nighttime", 'precipitation', 'GlobalSurfaceWater', 'WorldPop', 'COPERNICUS']
473
+ )
474
+
475
+ selected_date_range_From = st.sidebar.date_input("From", value=pd.to_datetime("2015-07-01"))
476
+ selected_date_range_To = st.sidebar.date_input("To", value=pd.to_datetime("2023-09-30"))
477
+
478
+ shape_options = [
479
+ 'District_Boundary', 'hydro_basins', 'karachi',
480
+ 'National_Constituency_with_Projected_2010_Population',
481
+ 'Provincial_Boundary', 'Provincial_Constituency',
482
+ 'Tehsil_Boundary', 'Union_Council'
483
+ ]
484
+
485
+ selected_shape = st.sidebar.selectbox("Select Shape", shape_options)
486
+
487
+ if st.sidebar.button("Submit"):
488
+ st.session_state.selected_dataset = selected_dataset
489
+ st.session_state.selected_date_range_From = selected_date_range_From
490
+ st.session_state.selected_date_range_To = selected_date_range_To
491
+ st.session_state.selected_shape = selected_shape
492
+ st.session_state.submitted = True
493
+ else:
494
+ st.session_state.submitted = False
495
+
496
+ if 'submitted' in st.session_state and st.session_state.submitted:
497
+ handle_submit(
498
+ st.session_state.selected_dataset,
499
+ st.session_state.selected_date_range_From,
500
+ st.session_state.selected_date_range_To,
501
+ st.session_state.selected_shape
502
+ )
503
+
504
+ def main():
505
+ st.set_page_config(layout="wide")
506
+ st.title("Satellite Data Visualization")
507
+
508
+ initialize_gee()
509
+
510
+
511
+ if __name__ == "__main__":
512
+ main()
513
+
514
+ #<---------------------------------------------------------------------timelapse pagefunction which is calling it in home (Navigation Purpose)----------------------------------------------------------------------------------------------------->
515
+
516
+ def Timelapse_page():
517
+ try:
518
+ app()
519
+ except Exception as e:
520
+ pass
521
+
522
+ #<------------------------------------------------------------------- timelapse code--------------------------------------------------------------------------------------------------------->
523
+ #create timelapse
524
+
525
+ @st.cache_data
526
+ def ee_authenticate(token_name="EARTHENGINE_TOKEN"):
527
+ geemap.ee_initialize(token_name=token_name)
528
+
529
+
530
+ goes_rois = {
531
+ "Creek Fire, CA (2020-09-05)": {
532
+ "region": Polygon(
533
+ [
534
+ [-121.003418, 36.848857],
535
+ [-121.003418, 39.049052],
536
+ [-117.905273, 39.049052],
537
+ [-117.905273, 36.848857],
538
+ [-121.003418, 36.848857],
539
+ ]
540
+ ),
541
+ "start_time": "2020-09-05T15:00:00",
542
+ "end_time": "2020-09-06T02:00:00",
543
+ },
544
+ "Bomb Cyclone (2021-10-24)": {
545
+ "region": Polygon(
546
+ [
547
+ [-159.5954, 60.4088],
548
+ [-159.5954, 24.5178],
549
+ [-114.2438, 24.5178],
550
+ [-114.2438, 60.4088],
551
+ ]
552
+ ),
553
+ "start_time": "2021-10-24T14:00:00",
554
+ "end_time": "2021-10-25T01:00:00",
555
+ },
556
+ "Hunga Tonga Volcanic Eruption (2022-01-15)": {
557
+ "region": Polygon(
558
+ [
559
+ [-192.480469, -32.546813],
560
+ [-192.480469, -8.754795],
561
+ [-157.587891, -8.754795],
562
+ [-157.587891, -32.546813],
563
+ [-192.480469, -32.546813],
564
+ ]
565
+ ),
566
+ "start_time": "2022-01-15T03:00:00",
567
+ "end_time": "2022-01-15T07:00:00",
568
+ },
569
+ "Hunga Tonga Volcanic Eruption Closer Look (2022-01-15)": {
570
+ "region": Polygon(
571
+ [
572
+ [-178.901367, -22.958393],
573
+ [-178.901367, -17.85329],
574
+ [-171.452637, -17.85329],
575
+ [-171.452637, -22.958393],
576
+ [-178.901367, -22.958393],
577
+ ]
578
+ ),
579
+ "start_time": "2022-01-15T03:00:00",
580
+ "end_time": "2022-01-15T07:00:00",
581
+ },
582
+ }
583
+
584
+
585
+ landsat_rois = {
586
+ "Aral Sea": Polygon(
587
+ [
588
+ [57.667236, 43.834527],
589
+ [57.667236, 45.996962],
590
+ [61.12793, 45.996962],
591
+ [61.12793, 43.834527],
592
+ [57.667236, 43.834527],
593
+ ]
594
+ ),
595
+ "Dubai": Polygon(
596
+ [
597
+ [54.541626, 24.763044],
598
+ [54.541626, 25.427152],
599
+ [55.632019, 25.427152],
600
+ [55.632019, 24.763044],
601
+ [54.541626, 24.763044],
602
+ ]
603
+ ),
604
+ "Hong Kong International Airport": Polygon(
605
+ [
606
+ [113.825226, 22.198849],
607
+ [113.825226, 22.349758],
608
+ [114.085121, 22.349758],
609
+ [114.085121, 22.198849],
610
+ [113.825226, 22.198849],
611
+ ]
612
+ ),
613
+ "Las Vegas, NV": Polygon(
614
+ [
615
+ [-115.554199, 35.804449],
616
+ [-115.554199, 36.558188],
617
+ [-113.903503, 36.558188],
618
+ [-113.903503, 35.804449],
619
+ [-115.554199, 35.804449],
620
+ ]
621
+ ),
622
+ "Pucallpa, Peru": Polygon(
623
+ [
624
+ [-74.672699, -8.600032],
625
+ [-74.672699, -8.254983],
626
+ [-74.279938, -8.254983],
627
+ [-74.279938, -8.600032],
628
+ ]
629
+ ),
630
+ "Sierra Gorda, Chile": Polygon(
631
+ [
632
+ [-69.315491, -22.837104],
633
+ [-69.315491, -22.751488],
634
+ [-69.190006, -22.751488],
635
+ [-69.190006, -22.837104],
636
+ [-69.315491, -22.837104],
637
+ ]
638
+ ),
639
+ }
640
+
641
+ modis_rois = {
642
+ "World": Polygon(
643
+ [
644
+ [-171.210938, -57.136239],
645
+ [-171.210938, 79.997168],
646
+ [177.539063, 79.997168],
647
+ [177.539063, -57.136239],
648
+ [-171.210938, -57.136239],
649
+ ]
650
+ ),
651
+ "Africa": Polygon(
652
+ [
653
+ [-18.6983, 38.1446],
654
+ [-18.6983, -36.1630],
655
+ [52.2293, -36.1630],
656
+ [52.2293, 38.1446],
657
+ ]
658
+ ),
659
+ "USA": Polygon(
660
+ [
661
+ [-127.177734, 23.725012],
662
+ [-127.177734, 50.792047],
663
+ [-66.269531, 50.792047],
664
+ [-66.269531, 23.725012],
665
+ [-127.177734, 23.725012],
666
+ ]
667
+ ),
668
+ }
669
+
670
+ ocean_rois = {
671
+ "Gulf of Mexico": Polygon(
672
+ [
673
+ [-101.206055, 15.496032],
674
+ [-101.206055, 32.361403],
675
+ [-75.673828, 32.361403],
676
+ [-75.673828, 15.496032],
677
+ [-101.206055, 15.496032],
678
+ ]
679
+ ),
680
+ "North Atlantic Ocean": Polygon(
681
+ [
682
+ [-85.341797, 24.046464],
683
+ [-85.341797, 45.02695],
684
+ [-55.810547, 45.02695],
685
+ [-55.810547, 24.046464],
686
+ [-85.341797, 24.046464],
687
+ ]
688
+ ),
689
+ "World": Polygon(
690
+ [
691
+ [-171.210938, -57.136239],
692
+ [-171.210938, 79.997168],
693
+ [177.539063, 79.997168],
694
+ [177.539063, -57.136239],
695
+ [-171.210938, -57.136239],
696
+ ]
697
+ ),
698
+ }
699
+
700
+
701
+ @st.cache_data
702
+ def uploaded_file_to_gdf(data):
703
+ import tempfile
704
+ import os
705
+ import uuid
706
+
707
+ _, file_extension = os.path.splitext(data.name)
708
+ file_id = str(uuid.uuid4())
709
+ file_path = os.path.join(tempfile.gettempdir(), f"{file_id}{file_extension}")
710
+
711
+ with open(file_path, "wb") as file:
712
+ file.write(data.getbuffer())
713
+
714
+ if file_path.lower().endswith(".kml"):
715
+ fiona.drvsupport.supported_drivers["KML"] = "rw"
716
+ gdf = gpd.read_file(file_path, driver="KML")
717
+ else:
718
+ gdf = gpd.read_file(file_path)
719
+
720
+ return gdf
721
+
722
+
723
+ def app():
724
+
725
+ today = date.today()
726
+
727
+ st.title("Create Satellite Timelapse")
728
+
729
+ row1_col1, row1_col2 = st.columns([2, 1])
730
+
731
+ if st.session_state.get("zoom_level") is None:
732
+ st.session_state["zoom_level"] = 4
733
+
734
+ st.session_state["ee_asset_id"] = None
735
+ st.session_state["bands"] = None
736
+ st.session_state["palette"] = None
737
+ st.session_state["vis_params"] = None
738
+
739
+ with row1_col1:
740
+ ee_authenticate(token_name="EARTHENGINE_TOKEN")
741
+ m = geemap.Map(
742
+ basemap="HYBRID",
743
+ plugin_Draw=True,
744
+ Draw_export=True,
745
+ locate_control=True,
746
+ plugin_LatLngPopup=False,
747
+ )
748
+ m.add_basemap("ROADMAP")
749
+
750
+ with row1_col2:
751
+
752
+ keyword = st.text_input("Search for a location:", "")
753
+ if keyword:
754
+ locations = geemap.geocode(keyword)
755
+ if locations is not None and len(locations) > 0:
756
+ str_locations = [str(g)[1:-1] for g in locations]
757
+ location = st.selectbox("Select a location:", str_locations)
758
+ loc_index = str_locations.index(location)
759
+ selected_loc = locations[loc_index]
760
+ lat, lng = selected_loc.lat, selected_loc.lng
761
+ folium.Marker(location=[lat, lng], popup=location).add_to(m)
762
+ m.set_center(lng, lat, 12)
763
+ st.session_state["zoom_level"] = 12
764
+
765
+ collection = st.selectbox(
766
+ "Select a satellite image collection: ",
767
+ [
768
+ "Any Earth Engine ImageCollection",
769
+ "Landsat TM-ETM-OLI Surface Reflectance",
770
+ "Sentinel-2 MSI Surface Reflectance",
771
+ "Geostationary Operational Environmental Satellites (GOES)",
772
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
773
+ "MODIS Gap filled Land Surface Temperature Daily",
774
+ "MODIS Ocean Color SMI",
775
+ "USDA National Agriculture Imagery Program (NAIP)","Modis",
776
+ "dataset_nighttime", 'precipitation', 'GlobalSurfaceWater', 'WorldPop', 'COPERNICUS'
777
+ ],
778
+ index=1,
779
+ )
780
+
781
+ if collection in [
782
+ "Landsat TM-ETM-OLI Surface Reflectance",
783
+ "Sentinel-2 MSI Surface Reflectance",
784
+ ]:
785
+ roi_options = ["Uploaded GeoJSON"] + list(landsat_rois.keys())
786
+
787
+ elif collection == "Geostationary Operational Environmental Satellites (GOES)":
788
+ roi_options = ["Uploaded GeoJSON"] + list(goes_rois.keys())
789
+
790
+ elif collection in [
791
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
792
+ "MODIS Gap filled Land Surface Temperature Daily",
793
+ ]:
794
+ roi_options = ["Uploaded GeoJSON"] + list(modis_rois.keys())
795
+ elif collection == "MODIS Ocean Color SMI":
796
+ roi_options = ["Uploaded GeoJSON"] + list(ocean_rois.keys())
797
+ else:
798
+ roi_options = ["Uploaded GeoJSON"]
799
+
800
+ if collection == "Any Earth Engine ImageCollection":
801
+ keyword = st.text_input("Enter a keyword to search (e.g., MODIS):", "")
802
+ if keyword:
803
+
804
+ assets = geemap.search_ee_data(keyword)
805
+ ee_assets = []
806
+ for asset in assets:
807
+ if asset["ee_id_snippet"].startswith("ee.ImageCollection"):
808
+ ee_assets.append(asset)
809
+
810
+ asset_titles = [x["title"] for x in ee_assets]
811
+ dataset = st.selectbox("Select a dataset:", asset_titles)
812
+ if len(ee_assets) > 0:
813
+ st.session_state["ee_assets"] = ee_assets
814
+ st.session_state["asset_titles"] = asset_titles
815
+ index = asset_titles.index(dataset)
816
+ ee_id = ee_assets[index]["id"]
817
+ else:
818
+ ee_id = ""
819
+
820
+ if dataset is not None:
821
+ with st.expander("Show dataset details", False):
822
+ index = asset_titles.index(dataset)
823
+ html = geemap.ee_data_html(st.session_state["ee_assets"][index])
824
+ st.markdown(html, True)
825
+ # elif collection == "MODIS Gap filled Land Surface Temperature Daily":
826
+ # ee_id = ""
827
+ else:
828
+ ee_id = ""
829
+
830
+ asset_id = st.text_input("Enter an ee.ImageCollection asset ID:", ee_id)
831
+
832
+ if asset_id:
833
+ with st.expander("Customize band combination and color palette", True):
834
+ try:
835
+ col = ee.ImageCollection.load(asset_id)
836
+ st.session_state["ee_asset_id"] = asset_id
837
+ except:
838
+ st.error("Invalid Earth Engine asset ID.")
839
+ st.session_state["ee_asset_id"] = None
840
+ return
841
+
842
+ img_bands = col.first().bandNames().getInfo()
843
+ if len(img_bands) >= 3:
844
+ default_bands = img_bands[:3][::-1]
845
+ else:
846
+ default_bands = img_bands[:]
847
+ bands = st.multiselect(
848
+ "Select one or three bands (RGB):", img_bands, default_bands
849
+ )
850
+ st.session_state["bands"] = bands
851
+
852
+ if len(bands) == 1:
853
+ palette_options = st.selectbox(
854
+ "Color palette",
855
+ cm.list_colormaps(),
856
+ index=2,
857
+ )
858
+ palette_values = cm.get_palette(palette_options, 15)
859
+ palette = st.text_area(
860
+ "Enter a custom palette:",
861
+ palette_values,
862
+ )
863
+ st.write(
864
+ cm.plot_colormap(cmap=palette_options, return_fig=True)
865
+ )
866
+ st.session_state["palette"] = json.loads(
867
+ palette.replace("'", '"')
868
+ )
869
+
870
+ if bands:
871
+ vis_params = st.text_area(
872
+ "Enter visualization parameters",
873
+ "{'bands': ["
874
+ + ", ".join([f"'{band}'" for band in bands])
875
+ + "]}",
876
+ )
877
+ else:
878
+ vis_params = st.text_area(
879
+ "Enter visualization parameters",
880
+ "{}",
881
+ )
882
+ try:
883
+ st.session_state["vis_params"] = json.loads(
884
+ vis_params.replace("'", '"')
885
+ )
886
+ st.session_state["vis_params"]["palette"] = st.session_state[
887
+ "palette"
888
+ ]
889
+ except Exception as e:
890
+ st.session_state["vis_params"] = None
891
+ st.error(
892
+ f"Invalid visualization parameters. It must be a dictionary."
893
+ )
894
+
895
+
896
+ elif collection == "MODIS Gap filled Land Surface Temperature Daily":
897
+ with st.expander("Show dataset details", False):
898
+ st.markdown(
899
+ """
900
+ See the [Awesome GEE Community Datasets](https://samapriya.github.io/awesome-gee-community-datasets/projects/daily_lst/).
901
+ """
902
+ )
903
+
904
+ MODIS_options = ["Daytime (1:30 pm)", "Nighttime (1:30 am)"]
905
+ MODIS_option = st.selectbox("Select a MODIS dataset:", MODIS_options)
906
+ if MODIS_option == "Daytime (1:30 pm)":
907
+ st.session_state["ee_asset_id"] = (
908
+ "projects/sat-io/open-datasets/gap-filled-lst/gf_day_1km"
909
+ )
910
+ else:
911
+ st.session_state["ee_asset_id"] = (
912
+ "projects/sat-io/open-datasets/gap-filled-lst/gf_night_1km"
913
+ )
914
+
915
+ palette_options = st.selectbox(
916
+ "Color palette",
917
+ cm.list_colormaps(),
918
+ index=90,
919
+ )
920
+ palette_values = cm.get_palette(palette_options, 15)
921
+ palette = st.text_area(
922
+ "Enter a custom palette:",
923
+ palette_values,
924
+ )
925
+ st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
926
+ st.session_state["palette"] = json.loads(palette.replace("'", '"'))
927
+ elif collection == "MODIS Ocean Color SMI":
928
+ with st.expander("Show dataset details", False):
929
+ st.markdown(
930
+ """
931
+ See the [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets/catalog/NASA_OCEANDATA_MODIS-Aqua_L3SMI).
932
+ """
933
+ )
934
+
935
+ MODIS_options = ["Aqua", "Terra"]
936
+ MODIS_option = st.selectbox("Select a satellite:", MODIS_options)
937
+ st.session_state["ee_asset_id"] = MODIS_option
938
+ # if MODIS_option == "Daytime (1:30 pm)":
939
+ # st.session_state[
940
+ # "ee_asset_id"
941
+ # ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_day_1km"
942
+ # else:
943
+ # st.session_state[
944
+ # "ee_asset_id"
945
+ # ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_night_1km"
946
+
947
+ band_dict = {
948
+ "Chlorophyll a concentration": "chlor_a",
949
+ "Normalized fluorescence line height": "nflh",
950
+ "Particulate organic carbon": "poc",
951
+ "Sea surface temperature": "sst",
952
+ "Remote sensing reflectance at band 412nm": "Rrs_412",
953
+ "Remote sensing reflectance at band 443nm": "Rrs_443",
954
+ "Remote sensing reflectance at band 469nm": "Rrs_469",
955
+ "Remote sensing reflectance at band 488nm": "Rrs_488",
956
+ "Remote sensing reflectance at band 531nm": "Rrs_531",
957
+ "Remote sensing reflectance at band 547nm": "Rrs_547",
958
+ "Remote sensing reflectance at band 555nm": "Rrs_555",
959
+ "Remote sensing reflectance at band 645nm": "Rrs_645",
960
+ "Remote sensing reflectance at band 667nm": "Rrs_667",
961
+ "Remote sensing reflectance at band 678nm": "Rrs_678",
962
+ }
963
+
964
+ band_options = list(band_dict.keys())
965
+ band = st.selectbox(
966
+ "Select a band",
967
+ band_options,
968
+ band_options.index("Sea surface temperature"),
969
+ )
970
+ st.session_state["band"] = band_dict[band]
971
+
972
+ colors = cm.list_colormaps()
973
+ palette_options = st.selectbox(
974
+ "Color palette",
975
+ colors,
976
+ index=colors.index("coolwarm"),
977
+ )
978
+ palette_values = cm.get_palette(palette_options, 15)
979
+ palette = st.text_area(
980
+ "Enter a custom palette:",
981
+ palette_values,
982
+ )
983
+ st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
984
+ st.session_state["palette"] = json.loads(palette.replace("'", '"'))
985
+
986
+ sample_roi = st.selectbox(
987
+ "Select a sample ROI or upload a GeoJSON file:",
988
+ roi_options,
989
+ index=0,
990
+ )
991
+
992
+ add_outline = st.checkbox(
993
+ "Overlay an administrative boundary on timelapse", False
994
+ )
995
+
996
+ if add_outline:
997
+
998
+ with st.expander("Customize administrative boundary", True):
999
+
1000
+ overlay_options = {
1001
+ "User-defined": None,
1002
+ "Continents": "continents",
1003
+ "Countries": "countries",
1004
+ "US States": "us_states",
1005
+ "China": "china",
1006
+ }
1007
+
1008
+ overlay = st.selectbox(
1009
+ "Select an administrative boundary:",
1010
+ list(overlay_options.keys()),
1011
+ index=2,
1012
+ )
1013
+
1014
+ overlay_data = overlay_options[overlay]
1015
+
1016
+ if overlay_data is None:
1017
+ overlay_data = st.text_input(
1018
+ "Enter an HTTP URL to a GeoJSON file or an ee.FeatureCollection asset id:",
1019
+ "https://raw.githubusercontent.com/giswqs/geemap/master/examples/data/countries.geojson",
1020
+ )
1021
+
1022
+ overlay_color = st.color_picker(
1023
+ "Select a color for the administrative boundary:", "#000000"
1024
+ )
1025
+ overlay_width = st.slider(
1026
+ "Select a line width for the administrative boundary:", 1, 20, 1
1027
+ )
1028
+ overlay_opacity = st.slider(
1029
+ "Select an opacity for the administrative boundary:",
1030
+ 0.0,
1031
+ 1.0,
1032
+ 1.0,
1033
+ 0.05,
1034
+ )
1035
+ else:
1036
+ overlay_data = None
1037
+ overlay_color = "black"
1038
+ overlay_width = 1
1039
+ overlay_opacity = 1
1040
+
1041
+ with row1_col1:
1042
+
1043
+ with st.expander(
1044
+ "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 👉"
1045
+ ):
1046
+ video_empty = st.empty()
1047
+
1048
+ data = st.file_uploader(
1049
+ "Upload a GeoJSON file to use as an ROI. Customize timelapse parameters and then click the Submit button 😇👇",
1050
+ type=["geojson", "kml", "zip"],
1051
+ )
1052
+
1053
+ crs = "epsg:4326"
1054
+ if sample_roi == "Uploaded GeoJSON":
1055
+ if data is None:
1056
+ # st.info(
1057
+ # "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"
1058
+ # )
1059
+ if collection in [
1060
+ "Geostationary Operational Environmental Satellites (GOES)",
1061
+ "USDA National Agriculture Imagery Program (NAIP)",
1062
+ ] and (not keyword):
1063
+ m.set_center(-100, 40, 3)
1064
+ # else:
1065
+ # m.set_center(4.20, 18.63, zoom=2)
1066
+ else:
1067
+ if collection in [
1068
+ "Landsat TM-ETM-OLI Surface Reflectance",
1069
+ "Sentinel-2 MSI Surface Reflectance",
1070
+ ]:
1071
+ gdf = gpd.GeoDataFrame(
1072
+ index=[0], crs=crs, geometry=[landsat_rois[sample_roi]]
1073
+ )
1074
+ elif (
1075
+ collection
1076
+ == "Geostationary Operational Environmental Satellites (GOES)"
1077
+ ):
1078
+ gdf = gpd.GeoDataFrame(
1079
+ index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
1080
+ )
1081
+ elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
1082
+ gdf = gpd.GeoDataFrame(
1083
+ index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
1084
+ )
1085
+
1086
+ if sample_roi != "Uploaded GeoJSON":
1087
+
1088
+ if collection in [
1089
+ "Landsat TM-ETM-OLI Surface Reflectance",
1090
+ "Sentinel-2 MSI Surface Reflectance",
1091
+ ]:
1092
+ gdf = gpd.GeoDataFrame(
1093
+ index=[0], crs=crs, geometry=[landsat_rois[sample_roi]]
1094
+ )
1095
+ elif (
1096
+ collection
1097
+ == "Geostationary Operational Environmental Satellites (GOES)"
1098
+ ):
1099
+ gdf = gpd.GeoDataFrame(
1100
+ index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
1101
+ )
1102
+ elif collection in [
1103
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
1104
+ "MODIS Gap filled Land Surface Temperature Daily",
1105
+ ]:
1106
+ gdf = gpd.GeoDataFrame(
1107
+ index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
1108
+ )
1109
+ elif collection == "MODIS Ocean Color SMI":
1110
+ gdf = gpd.GeoDataFrame(
1111
+ index=[0], crs=crs, geometry=[ocean_rois[sample_roi]]
1112
+ )
1113
+ try:
1114
+ st.session_state["roi"] = geemap.gdf_to_ee(gdf, geodesic=False)
1115
+ except Exception as e:
1116
+ st.error(e)
1117
+ st.error("Please draw another ROI and try again.")
1118
+ return
1119
+ m.add_gdf(gdf, "ROI")
1120
+
1121
+ elif data:
1122
+ gdf = uploaded_file_to_gdf(data)
1123
+ try:
1124
+ st.session_state["roi"] = geemap.gdf_to_ee(gdf, geodesic=False)
1125
+ m.add_gdf(gdf, "ROI")
1126
+ except Exception as e:
1127
+ st.error(e)
1128
+ st.error("Please draw another ROI and try again.")
1129
+ return
1130
+
1131
+ m.to_streamlit(height=600)
1132
+
1133
+ with row1_col2:
1134
+
1135
+ if collection in [
1136
+ "Landsat TM-ETM-OLI Surface Reflectance",
1137
+ "Sentinel-2 MSI Surface Reflectance",
1138
+ ]:
1139
+
1140
+ if collection == "Landsat TM-ETM-OLI Surface Reflectance":
1141
+ sensor_start_year = 1984
1142
+ timelapse_title = "Landsat Timelapse"
1143
+ timelapse_speed = 5
1144
+ elif collection == "Sentinel-2 MSI Surface Reflectance":
1145
+ sensor_start_year = 2015
1146
+ timelapse_title = "Sentinel-2 Timelapse"
1147
+ timelapse_speed = 5
1148
+ video_empty.video("https://youtu.be/VVRK_-dEjR4")
1149
+
1150
+ with st.form("submit_landsat_form"):
1151
+
1152
+ roi = None
1153
+ if st.session_state.get("roi") is not None:
1154
+ roi = st.session_state.get("roi")
1155
+ out_gif = geemap.temp_file_path(".gif")
1156
+
1157
+ title = st.text_input(
1158
+ "Enter a title to show on the timelapse: ", timelapse_title
1159
+ )
1160
+ RGB = st.selectbox(
1161
+ "Select an RGB band combination:",
1162
+ [
1163
+ "Red/Green/Blue",
1164
+ "NIR/Red/Green",
1165
+ "SWIR2/SWIR1/NIR",
1166
+ "NIR/SWIR1/Red",
1167
+ "SWIR2/NIR/Red",
1168
+ "SWIR2/SWIR1/Red",
1169
+ "SWIR1/NIR/Blue",
1170
+ "NIR/SWIR1/Blue",
1171
+ "SWIR2/NIR/Green",
1172
+ "SWIR1/NIR/Red",
1173
+ "SWIR2/NIR/SWIR1",
1174
+ "SWIR1/NIR/SWIR2",
1175
+ ],
1176
+ index=9,
1177
+ )
1178
+
1179
+ frequency = st.selectbox(
1180
+ "Select a temporal frequency:",
1181
+ ["year", "quarter", "month"],
1182
+ index=0,
1183
+ )
1184
+
1185
+ with st.expander("Customize timelapse"):
1186
+
1187
+ speed = st.slider("Frames per second:", 1, 30, timelapse_speed)
1188
+ dimensions = st.slider(
1189
+ "Maximum dimensions (Width*Height) in pixels", 768, 2000, 768
1190
+ )
1191
+ progress_bar_color = st.color_picker(
1192
+ "Progress bar color:", "#0000ff"
1193
+ )
1194
+ years = st.slider(
1195
+ "Start and end year:",
1196
+ sensor_start_year,
1197
+ today.year,
1198
+ (sensor_start_year, today.year),
1199
+ )
1200
+ months = st.slider("Start and end month:", 1, 12, (1, 12))
1201
+ font_size = st.slider("Font size:", 10, 50, 30)
1202
+ font_color = st.color_picker("Font color:", "#ffffff")
1203
+ apply_fmask = st.checkbox(
1204
+ "Apply fmask (remove clouds, shadows, snow)", True
1205
+ )
1206
+ font_type = st.selectbox(
1207
+ "Select the font type for the title:",
1208
+ ["arial.ttf", "alibaba.otf"],
1209
+ index=0,
1210
+ )
1211
+ fading = st.slider(
1212
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1213
+ )
1214
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1215
+
1216
+ empty_text = st.empty()
1217
+ empty_image = st.empty()
1218
+ empty_fire_image = st.empty()
1219
+ empty_video = st.container()
1220
+ submitted = st.form_submit_button("Submit")
1221
+ if submitted:
1222
+
1223
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1224
+ empty_text.warning(
1225
+ "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."
1226
+ )
1227
+ else:
1228
+
1229
+ empty_text.text("Computing... Please wait...")
1230
+
1231
+ start_year = years[0]
1232
+ end_year = years[1]
1233
+ start_date = str(months[0]).zfill(2) + "-01"
1234
+ end_date = str(months[1]).zfill(2) + "-30"
1235
+ bands = RGB.split("/")
1236
+
1237
+ try:
1238
+ if collection == "Landsat TM-ETM-OLI Surface Reflectance":
1239
+ out_gif = geemap.landsat_timelapse(
1240
+ roi=roi,
1241
+ out_gif=out_gif,
1242
+ start_year=start_year,
1243
+ end_year=end_year,
1244
+ start_date=start_date,
1245
+ end_date=end_date,
1246
+ bands=bands,
1247
+ apply_fmask=apply_fmask,
1248
+ frames_per_second=speed,
1249
+ # dimensions=dimensions,
1250
+ dimensions=768,
1251
+ overlay_data=overlay_data,
1252
+ overlay_color=overlay_color,
1253
+ overlay_width=overlay_width,
1254
+ overlay_opacity=overlay_opacity,
1255
+ frequency=frequency,
1256
+ date_format=None,
1257
+ title=title,
1258
+ title_xy=("2%", "90%"),
1259
+ add_text=True,
1260
+ text_xy=("2%", "2%"),
1261
+ text_sequence=None,
1262
+ font_type=font_type,
1263
+ font_size=font_size,
1264
+ font_color=font_color,
1265
+ add_progress_bar=True,
1266
+ progress_bar_color=progress_bar_color,
1267
+ progress_bar_height=5,
1268
+ loop=0,
1269
+ mp4=mp4,
1270
+ fading=fading,
1271
+ )
1272
+ elif collection == "Sentinel-2 MSI Surface Reflectance":
1273
+ out_gif = geemap.sentinel2_timelapse(
1274
+ roi=roi,
1275
+ out_gif=out_gif,
1276
+ start_year=start_year,
1277
+ end_year=end_year,
1278
+ start_date=start_date,
1279
+ end_date=end_date,
1280
+ bands=bands,
1281
+ apply_fmask=apply_fmask,
1282
+ frames_per_second=speed,
1283
+ dimensions=768,
1284
+ # dimensions=dimensions,
1285
+ overlay_data=overlay_data,
1286
+ overlay_color=overlay_color,
1287
+ overlay_width=overlay_width,
1288
+ overlay_opacity=overlay_opacity,
1289
+ frequency=frequency,
1290
+ date_format=None,
1291
+ title=title,
1292
+ title_xy=("2%", "90%"),
1293
+ add_text=True,
1294
+ text_xy=("2%", "2%"),
1295
+ text_sequence=None,
1296
+ font_type=font_type,
1297
+ font_size=font_size,
1298
+ font_color=font_color,
1299
+ add_progress_bar=True,
1300
+ progress_bar_color=progress_bar_color,
1301
+ progress_bar_height=5,
1302
+ loop=0,
1303
+ mp4=mp4,
1304
+ fading=fading,
1305
+ )
1306
+ except:
1307
+ empty_text.error(
1308
+ "An error occurred while computing the timelapse. Your probably requested too much data. Try reducing the ROI or timespan."
1309
+ )
1310
+ st.stop()
1311
+
1312
+ if out_gif is not None and os.path.exists(out_gif):
1313
+
1314
+ empty_text.text(
1315
+ "Right click the GIF to save it to your computer👇"
1316
+ )
1317
+ empty_image.image(out_gif)
1318
+
1319
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1320
+ if mp4 and os.path.exists(out_mp4):
1321
+ with empty_video:
1322
+ st.text(
1323
+ "Right click the MP4 to save it to your computer👇"
1324
+ )
1325
+ st.video(out_gif.replace(".gif", ".mp4"))
1326
+
1327
+ else:
1328
+ empty_text.error(
1329
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1330
+ )
1331
+
1332
+ elif collection == "Geostationary Operational Environmental Satellites (GOES)":
1333
+
1334
+ video_empty.video("https://youtu.be/16fA2QORG4A")
1335
+
1336
+ with st.form("submit_goes_form"):
1337
+
1338
+ roi = None
1339
+ if st.session_state.get("roi") is not None:
1340
+ roi = st.session_state.get("roi")
1341
+ out_gif = geemap.temp_file_path(".gif")
1342
+
1343
+ satellite = st.selectbox("Select a satellite:", ["GOES-17", "GOES-16"])
1344
+ earliest_date = datetime.date(2017, 7, 10)
1345
+ latest_date = datetime.date.today()
1346
+
1347
+ if sample_roi == "Uploaded GeoJSON":
1348
+ roi_start_date = today - datetime.timedelta(days=2)
1349
+ roi_end_date = today - datetime.timedelta(days=1)
1350
+ roi_start_time = datetime.time(14, 00)
1351
+ roi_end_time = datetime.time(1, 00)
1352
+ else:
1353
+ roi_start = goes_rois[sample_roi]["start_time"]
1354
+ roi_end = goes_rois[sample_roi]["end_time"]
1355
+ roi_start_date = datetime.datetime.strptime(
1356
+ roi_start[:10], "%Y-%m-%d"
1357
+ )
1358
+ roi_end_date = datetime.datetime.strptime(roi_end[:10], "%Y-%m-%d")
1359
+ roi_start_time = datetime.time(
1360
+ int(roi_start[11:13]), int(roi_start[14:16])
1361
+ )
1362
+ roi_end_time = datetime.time(
1363
+ int(roi_end[11:13]), int(roi_end[14:16])
1364
+ )
1365
+
1366
+ start_date = st.date_input("Select the start date:", roi_start_date)
1367
+ end_date = st.date_input("Select the end date:", roi_end_date)
1368
+
1369
+ with st.expander("Customize timelapse"):
1370
+
1371
+ add_fire = st.checkbox("Add Fire/Hotspot Characterization", False)
1372
+
1373
+ scan_type = st.selectbox(
1374
+ "Select a scan type:", ["Full Disk", "CONUS", "Mesoscale"]
1375
+ )
1376
+
1377
+ start_time = st.time_input(
1378
+ "Select the start time of the start date:", roi_start_time
1379
+ )
1380
+
1381
+ end_time = st.time_input(
1382
+ "Select the end time of the end date:", roi_end_time
1383
+ )
1384
+
1385
+ start = (
1386
+ start_date.strftime("%Y-%m-%d")
1387
+ + "T"
1388
+ + start_time.strftime("%H:%M:%S")
1389
+ )
1390
+ end = (
1391
+ end_date.strftime("%Y-%m-%d")
1392
+ + "T"
1393
+ + end_time.strftime("%H:%M:%S")
1394
+ )
1395
+
1396
+ speed = st.slider("Frames per second:", 1, 30, 5)
1397
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1398
+ progress_bar_color = st.color_picker(
1399
+ "Progress bar color:", "#0000ff"
1400
+ )
1401
+ font_size = st.slider("Font size:", 10, 50, 20)
1402
+ font_color = st.color_picker("Font color:", "#ffffff")
1403
+ fading = st.slider(
1404
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1405
+ )
1406
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1407
+
1408
+ empty_text = st.empty()
1409
+ empty_image = st.empty()
1410
+ empty_video = st.container()
1411
+ empty_fire_text = st.empty()
1412
+ empty_fire_image = st.empty()
1413
+
1414
+ submitted = st.form_submit_button("Submit")
1415
+ if submitted:
1416
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1417
+ empty_text.warning(
1418
+ "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."
1419
+ )
1420
+ else:
1421
+ empty_text.text("Computing... Please wait...")
1422
+
1423
+ geemap.goes_timelapse(
1424
+ roi,
1425
+ out_gif,
1426
+ start_date=start,
1427
+ end_date=end,
1428
+ data=satellite,
1429
+ scan=scan_type.replace(" ", "_").lower(),
1430
+ dimensions=768,
1431
+ framesPerSecond=speed,
1432
+ date_format="YYYY-MM-dd HH:mm",
1433
+ xy=("3%", "3%"),
1434
+ text_sequence=None,
1435
+ font_type="arial.ttf",
1436
+ font_size=font_size,
1437
+ font_color=font_color,
1438
+ add_progress_bar=add_progress_bar,
1439
+ progress_bar_color=progress_bar_color,
1440
+ progress_bar_height=5,
1441
+ loop=0,
1442
+ overlay_data=overlay_data,
1443
+ overlay_color=overlay_color,
1444
+ overlay_width=overlay_width,
1445
+ overlay_opacity=overlay_opacity,
1446
+ mp4=mp4,
1447
+ fading=fading,
1448
+ )
1449
+
1450
+ if out_gif is not None and os.path.exists(out_gif):
1451
+ empty_text.text(
1452
+ "Right click the GIF to save it to your computer👇"
1453
+ )
1454
+ empty_image.image(out_gif)
1455
+
1456
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1457
+ if mp4 and os.path.exists(out_mp4):
1458
+ with empty_video:
1459
+ st.text(
1460
+ "Right click the MP4 to save it to your computer👇"
1461
+ )
1462
+ st.video(out_gif.replace(".gif", ".mp4"))
1463
+
1464
+ if add_fire:
1465
+ out_fire_gif = geemap.temp_file_path(".gif")
1466
+ empty_fire_text.text(
1467
+ "Delineating Fire Hotspot... Please wait..."
1468
+ )
1469
+ geemap.goes_fire_timelapse(
1470
+ out_fire_gif,
1471
+ start_date=start,
1472
+ end_date=end,
1473
+ data=satellite,
1474
+ scan=scan_type.replace(" ", "_").lower(),
1475
+ region=roi,
1476
+ dimensions=768,
1477
+ framesPerSecond=speed,
1478
+ date_format="YYYY-MM-dd HH:mm",
1479
+ xy=("3%", "3%"),
1480
+ text_sequence=None,
1481
+ font_type="arial.ttf",
1482
+ font_size=font_size,
1483
+ font_color=font_color,
1484
+ add_progress_bar=add_progress_bar,
1485
+ progress_bar_color=progress_bar_color,
1486
+ progress_bar_height=5,
1487
+ loop=0,
1488
+ )
1489
+ if os.path.exists(out_fire_gif):
1490
+ empty_fire_image.image(out_fire_gif)
1491
+ else:
1492
+ empty_text.text(
1493
+ "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."
1494
+ )
1495
+
1496
+ elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
1497
+
1498
+ video_empty.video("https://youtu.be/16fA2QORG4A")
1499
+
1500
+ satellite = st.selectbox("Select a satellite:", ["Terra", "Aqua"])
1501
+ band = st.selectbox("Select a band:", ["NDVI", "EVI"])
1502
+
1503
+ with st.form("submit_modis_form"):
1504
+
1505
+ roi = None
1506
+ if st.session_state.get("roi") is not None:
1507
+ roi = st.session_state.get("roi")
1508
+ out_gif = geemap.temp_file_path(".gif")
1509
+
1510
+ with st.expander("Customize timelapse"):
1511
+
1512
+ start = st.date_input(
1513
+ "Select a start date:", datetime.date(2000, 2, 8)
1514
+ )
1515
+ end = st.date_input("Select an end date:", datetime.date.today())
1516
+
1517
+ start_date = start.strftime("%Y-%m-%d")
1518
+ end_date = end.strftime("%Y-%m-%d")
1519
+
1520
+ speed = st.slider("Frames per second:", 1, 30, 5)
1521
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1522
+ progress_bar_color = st.color_picker(
1523
+ "Progress bar color:", "#0000ff"
1524
+ )
1525
+ font_size = st.slider("Font size:", 10, 50, 20)
1526
+ font_color = st.color_picker("Font color:", "#ffffff")
1527
+
1528
+ font_type = st.selectbox(
1529
+ "Select the font type for the title:",
1530
+ ["arial.ttf", "alibaba.otf"],
1531
+ index=0,
1532
+ )
1533
+ fading = st.slider(
1534
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1535
+ )
1536
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1537
+
1538
+ empty_text = st.empty()
1539
+ empty_image = st.empty()
1540
+ empty_video = st.container()
1541
+
1542
+ submitted = st.form_submit_button("Submit")
1543
+ if submitted:
1544
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1545
+ empty_text.warning(
1546
+ "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."
1547
+ )
1548
+ else:
1549
+
1550
+ empty_text.text("Computing... Please wait...")
1551
+
1552
+ geemap.modis_ndvi_timelapse(
1553
+ roi,
1554
+ out_gif,
1555
+ satellite,
1556
+ band,
1557
+ start_date,
1558
+ end_date,
1559
+ 768,
1560
+ speed,
1561
+ overlay_data=overlay_data,
1562
+ overlay_color=overlay_color,
1563
+ overlay_width=overlay_width,
1564
+ overlay_opacity=overlay_opacity,
1565
+ mp4=mp4,
1566
+ fading=fading,
1567
+ )
1568
+
1569
+ geemap.reduce_gif_size(out_gif)
1570
+
1571
+ empty_text.text(
1572
+ "Right click the GIF to save it to your computer👇"
1573
+ )
1574
+ empty_image.image(out_gif)
1575
+
1576
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1577
+ if mp4 and os.path.exists(out_mp4):
1578
+ with empty_video:
1579
+ st.text(
1580
+ "Right click the MP4 to save it to your computer👇"
1581
+ )
1582
+ st.video(out_gif.replace(".gif", ".mp4"))
1583
+
1584
+ elif collection == "Any Earth Engine ImageCollection":
1585
+
1586
+ with st.form("submit_ts_form"):
1587
+ with st.expander("Customize timelapse"):
1588
+
1589
+ title = st.text_input(
1590
+ "Enter a title to show on the timelapse: ", "Timelapse"
1591
+ )
1592
+ start_date = st.date_input(
1593
+ "Select the start date:", datetime.date(2020, 1, 1)
1594
+ )
1595
+ end_date = st.date_input(
1596
+ "Select the end date:", datetime.date.today()
1597
+ )
1598
+ frequency = st.selectbox(
1599
+ "Select a temporal frequency:",
1600
+ ["year", "quarter", "month", "day", "hour", "minute", "second"],
1601
+ index=0,
1602
+ )
1603
+ reducer = st.selectbox(
1604
+ "Select a reducer for aggregating data:",
1605
+ ["median", "mean", "min", "max", "sum", "variance", "stdDev"],
1606
+ index=0,
1607
+ )
1608
+ data_format = st.selectbox(
1609
+ "Select a date format to show on the timelapse:",
1610
+ [
1611
+ "YYYY-MM-dd",
1612
+ "YYYY",
1613
+ "YYMM-MM",
1614
+ "YYYY-MM-dd HH:mm",
1615
+ "YYYY-MM-dd HH:mm:ss",
1616
+ "HH:mm",
1617
+ "HH:mm:ss",
1618
+ "w",
1619
+ "M",
1620
+ "d",
1621
+ "D",
1622
+ ],
1623
+ index=0,
1624
+ )
1625
+
1626
+ speed = st.slider("Frames per second:", 1, 30, 5)
1627
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1628
+ progress_bar_color = st.color_picker(
1629
+ "Progress bar color:", "#0000ff"
1630
+ )
1631
+ font_size = st.slider("Font size:", 10, 50, 30)
1632
+ font_color = st.color_picker("Font color:", "#ffffff")
1633
+ font_type = st.selectbox(
1634
+ "Select the font type for the title:",
1635
+ ["arial.ttf", "alibaba.otf"],
1636
+ index=0,
1637
+ )
1638
+ fading = st.slider(
1639
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1640
+ )
1641
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1642
+
1643
+ empty_text = st.empty()
1644
+ empty_image = st.empty()
1645
+ empty_video = st.container()
1646
+ empty_fire_image = st.empty()
1647
+
1648
+ roi = None
1649
+ if st.session_state.get("roi") is not None:
1650
+ roi = st.session_state.get("roi")
1651
+ out_gif = geemap.temp_file_path(".gif")
1652
+
1653
+ submitted = st.form_submit_button("Submit")
1654
+ if submitted:
1655
+
1656
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1657
+ empty_text.warning(
1658
+ "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."
1659
+ )
1660
+ else:
1661
+
1662
+ empty_text.text("Computing... Please wait...")
1663
+ try:
1664
+ geemap.create_timelapse(
1665
+ st.session_state.get("ee_asset_id"),
1666
+ start_date=start_date.strftime("%Y-%m-%d"),
1667
+ end_date=end_date.strftime("%Y-%m-%d"),
1668
+ region=roi,
1669
+ frequency=frequency,
1670
+ reducer=reducer,
1671
+ date_format=data_format,
1672
+ out_gif=out_gif,
1673
+ bands=st.session_state.get("bands"),
1674
+ palette=st.session_state.get("palette"),
1675
+ vis_params=st.session_state.get("vis_params"),
1676
+ dimensions=768,
1677
+ frames_per_second=speed,
1678
+ crs="EPSG:3857",
1679
+ overlay_data=overlay_data,
1680
+ overlay_color=overlay_color,
1681
+ overlay_width=overlay_width,
1682
+ overlay_opacity=overlay_opacity,
1683
+ title=title,
1684
+ title_xy=("2%", "90%"),
1685
+ add_text=True,
1686
+ text_xy=("2%", "2%"),
1687
+ text_sequence=None,
1688
+ font_type=font_type,
1689
+ font_size=font_size,
1690
+ font_color=font_color,
1691
+ add_progress_bar=add_progress_bar,
1692
+ progress_bar_color=progress_bar_color,
1693
+ progress_bar_height=5,
1694
+ loop=0,
1695
+ mp4=mp4,
1696
+ fading=fading,
1697
+ )
1698
+ except:
1699
+ empty_text.error(
1700
+ "An error occurred while computing the timelapse. You probably requested too much data. Try reducing the ROI or timespan."
1701
+ )
1702
+
1703
+ empty_text.text(
1704
+ "Right click the GIF to save it to your computer👇"
1705
+ )
1706
+ empty_image.image(out_gif)
1707
+
1708
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1709
+ if mp4 and os.path.exists(out_mp4):
1710
+ with empty_video:
1711
+ st.text(
1712
+ "Right click the MP4 to save it to your computer👇"
1713
+ )
1714
+ st.video(out_gif.replace(".gif", ".mp4"))
1715
+
1716
+ elif collection in [
1717
+ "MODIS Gap filled Land Surface Temperature Daily",
1718
+ "MODIS Ocean Color SMI",
1719
+ ]:
1720
+
1721
+ with st.form("submit_ts_form"):
1722
+ with st.expander("Customize timelapse"):
1723
+
1724
+ title = st.text_input(
1725
+ "Enter a title to show on the timelapse: ",
1726
+ "Surface Temperature",
1727
+ )
1728
+ start_date = st.date_input(
1729
+ "Select the start date:", datetime.date(2018, 1, 1)
1730
+ )
1731
+ end_date = st.date_input(
1732
+ "Select the end date:", datetime.date(2020, 12, 31)
1733
+ )
1734
+ frequency = st.selectbox(
1735
+ "Select a temporal frequency:",
1736
+ ["year", "quarter", "month", "week", "day"],
1737
+ index=2,
1738
+ )
1739
+ reducer = st.selectbox(
1740
+ "Select a reducer for aggregating data:",
1741
+ ["median", "mean", "min", "max", "sum", "variance", "stdDev"],
1742
+ index=0,
1743
+ )
1744
+
1745
+ vis_params = st.text_area(
1746
+ "Enter visualization parameters",
1747
+ "",
1748
+ help="Enter a string in the format of a dictionary, such as '{'min': 23, 'max': 32}'",
1749
+ )
1750
+
1751
+ speed = st.slider("Frames per second:", 1, 30, 5)
1752
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1753
+ progress_bar_color = st.color_picker(
1754
+ "Progress bar color:", "#0000ff"
1755
+ )
1756
+ font_size = st.slider("Font size:", 10, 50, 30)
1757
+ font_color = st.color_picker("Font color:", "#ffffff")
1758
+ font_type = st.selectbox(
1759
+ "Select the font type for the title:",
1760
+ ["arial.ttf", "alibaba.otf"],
1761
+ index=0,
1762
+ )
1763
+ add_colorbar = st.checkbox("Add a colorbar", True)
1764
+ colorbar_label = st.text_input(
1765
+ "Enter the colorbar label:", "Surface Temperature (°C)"
1766
+ )
1767
+ fading = st.slider(
1768
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1769
+ )
1770
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1771
+
1772
+ empty_text = st.empty()
1773
+ empty_image = st.empty()
1774
+ empty_video = st.container()
1775
+
1776
+ roi = None
1777
+ if st.session_state.get("roi") is not None:
1778
+ roi = st.session_state.get("roi")
1779
+ out_gif = geemap.temp_file_path(".gif")
1780
+
1781
+ submitted = st.form_submit_button("Submit")
1782
+ if submitted:
1783
+
1784
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1785
+ empty_text.warning(
1786
+ "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."
1787
+ )
1788
+ else:
1789
+
1790
+ empty_text.text("Computing... Please wait...")
1791
+ try:
1792
+ if (
1793
+ collection
1794
+ == "MODIS Gap filled Land Surface Temperature Daily"
1795
+ ):
1796
+ out_gif = geemap.create_timelapse(
1797
+ st.session_state.get("ee_asset_id"),
1798
+ start_date=start_date.strftime("%Y-%m-%d"),
1799
+ end_date=end_date.strftime("%Y-%m-%d"),
1800
+ region=roi,
1801
+ bands=None,
1802
+ frequency=frequency,
1803
+ reducer=reducer,
1804
+ date_format=None,
1805
+ out_gif=out_gif,
1806
+ palette=st.session_state.get("palette"),
1807
+ vis_params=None,
1808
+ dimensions=768,
1809
+ frames_per_second=speed,
1810
+ crs="EPSG:3857",
1811
+ overlay_data=overlay_data,
1812
+ overlay_color=overlay_color,
1813
+ overlay_width=overlay_width,
1814
+ overlay_opacity=overlay_opacity,
1815
+ title=title,
1816
+ title_xy=("2%", "90%"),
1817
+ add_text=True,
1818
+ text_xy=("2%", "2%"),
1819
+ text_sequence=None,
1820
+ font_type=font_type,
1821
+ font_size=font_size,
1822
+ font_color=font_color,
1823
+ add_progress_bar=add_progress_bar,
1824
+ progress_bar_color=progress_bar_color,
1825
+ progress_bar_height=5,
1826
+ add_colorbar=add_colorbar,
1827
+ colorbar_label=colorbar_label,
1828
+ loop=0,
1829
+ mp4=mp4,
1830
+ fading=fading,
1831
+ )
1832
+ elif collection == "MODIS Ocean Color SMI":
1833
+ if vis_params.startswith("{") and vis_params.endswith(
1834
+ "}"
1835
+ ):
1836
+ vis_params = json.loads(
1837
+ vis_params.replace("'", '"')
1838
+ )
1839
+ else:
1840
+ vis_params = None
1841
+ out_gif = geemap.modis_ocean_color_timelapse(
1842
+ st.session_state.get("ee_asset_id"),
1843
+ start_date=start_date.strftime("%Y-%m-%d"),
1844
+ end_date=end_date.strftime("%Y-%m-%d"),
1845
+ region=roi,
1846
+ bands=st.session_state["band"],
1847
+ frequency=frequency,
1848
+ reducer=reducer,
1849
+ date_format=None,
1850
+ out_gif=out_gif,
1851
+ palette=st.session_state.get("palette"),
1852
+ vis_params=vis_params,
1853
+ dimensions=768,
1854
+ frames_per_second=speed,
1855
+ crs="EPSG:3857",
1856
+ overlay_data=overlay_data,
1857
+ overlay_color=overlay_color,
1858
+ overlay_width=overlay_width,
1859
+ overlay_opacity=overlay_opacity,
1860
+ title=title,
1861
+ title_xy=("2%", "90%"),
1862
+ add_text=True,
1863
+ text_xy=("2%", "2%"),
1864
+ text_sequence=None,
1865
+ font_type=font_type,
1866
+ font_size=font_size,
1867
+ font_color=font_color,
1868
+ add_progress_bar=add_progress_bar,
1869
+ progress_bar_color=progress_bar_color,
1870
+ progress_bar_height=5,
1871
+ add_colorbar=add_colorbar,
1872
+ colorbar_label=colorbar_label,
1873
+ loop=0,
1874
+ mp4=mp4,
1875
+ fading=fading,
1876
+ )
1877
+ except:
1878
+ empty_text.error(
1879
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1880
+ )
1881
+
1882
+ if out_gif is not None and os.path.exists(out_gif):
1883
+
1884
+ geemap.reduce_gif_size(out_gif)
1885
+
1886
+ empty_text.text(
1887
+ "Right click the GIF to save it to your computer👇"
1888
+ )
1889
+ empty_image.image(out_gif)
1890
+
1891
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1892
+ if mp4 and os.path.exists(out_mp4):
1893
+ with empty_video:
1894
+ st.text(
1895
+ "Right click the MP4 to save it to your computer👇"
1896
+ )
1897
+ st.video(out_gif.replace(".gif", ".mp4"))
1898
+
1899
+ else:
1900
+ st.error(
1901
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1902
+ )
1903
+
1904
+ elif collection == "USDA National Agriculture Imagery Program (NAIP)":
1905
+
1906
+ with st.form("submit_naip_form"):
1907
+ with st.expander("Customize timelapse"):
1908
+
1909
+ title = st.text_input(
1910
+ "Enter a title to show on the timelapse: ", "NAIP Timelapse"
1911
+ )
1912
+
1913
+ years = st.slider(
1914
+ "Start and end year:",
1915
+ 2003,
1916
+ today.year,
1917
+ (2003, today.year),
1918
+ )
1919
+
1920
+ bands = st.selectbox(
1921
+ "Select a band combination:", ["N/R/G", "R/G/B"], index=0
1922
+ )
1923
+
1924
+ speed = st.slider("Frames per second:", 1, 30, 3)
1925
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1926
+ progress_bar_color = st.color_picker(
1927
+ "Progress bar color:", "#0000ff"
1928
+ )
1929
+ font_size = st.slider("Font size:", 10, 50, 30)
1930
+ font_color = st.color_picker("Font color:", "#ffffff")
1931
+ font_type = st.selectbox(
1932
+ "Select the font type for the title:",
1933
+ ["arial.ttf", "alibaba.otf"],
1934
+ index=0,
1935
+ )
1936
+ fading = st.slider(
1937
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1938
+ )
1939
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1940
+
1941
+ empty_text = st.empty()
1942
+ empty_image = st.empty()
1943
+ empty_video = st.container()
1944
+ empty_fire_image = st.empty()
1945
+
1946
+ roi = None
1947
+ if st.session_state.get("roi") is not None:
1948
+ roi = st.session_state.get("roi")
1949
+ out_gif = geemap.temp_file_path(".gif")
1950
+
1951
+ submitted = st.form_submit_button("Submit")
1952
+ if submitted:
1953
+
1954
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1955
+ empty_text.warning(
1956
+ "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."
1957
+ )
1958
+ else:
1959
+
1960
+ empty_text.text("Computing... Please wait...")
1961
+ try:
1962
+ geemap.naip_timelapse(
1963
+ roi,
1964
+ years[0],
1965
+ years[1],
1966
+ out_gif,
1967
+ bands=bands.split("/"),
1968
+ palette=st.session_state.get("palette"),
1969
+ vis_params=None,
1970
+ dimensions=768,
1971
+ frames_per_second=speed,
1972
+ crs="EPSG:3857",
1973
+ overlay_data=overlay_data,
1974
+ overlay_color=overlay_color,
1975
+ overlay_width=overlay_width,
1976
+ overlay_opacity=overlay_opacity,
1977
+ title=title,
1978
+ title_xy=("2%", "90%"),
1979
+ add_text=True,
1980
+ text_xy=("2%", "2%"),
1981
+ text_sequence=None,
1982
+ font_type=font_type,
1983
+ font_size=font_size,
1984
+ font_color=font_color,
1985
+ add_progress_bar=add_progress_bar,
1986
+ progress_bar_color=progress_bar_color,
1987
+ progress_bar_height=5,
1988
+ loop=0,
1989
+ mp4=mp4,
1990
+ fading=fading,
1991
+ )
1992
+ except:
1993
+ empty_text.error(
1994
+ "Something went wrong. You either requested too much data or the ROI is outside the U.S."
1995
+ )
1996
+
1997
+ if out_gif is not None and os.path.exists(out_gif):
1998
+
1999
+ empty_text.text(
2000
+ "Right click the GIF to save it to your computer👇"
2001
+ )
2002
+ empty_image.image(out_gif)
2003
+
2004
+ out_mp4 = out_gif.replace(".gif", ".mp4")
2005
+ if mp4 and os.path.exists(out_mp4):
2006
+ with empty_video:
2007
+ st.text(
2008
+ "Right click the MP4 to save it to your computer👇"
2009
+ )
2010
+ st.video(out_gif.replace(".gif", ".mp4"))
2011
+
2012
+ else:
2013
+ st.error(
2014
+ "Something went wrong. You either requested too much data or the ROI is outside the U.S."
2015
+ )
2016
+
2017
+ #<----------------------------------------------------------------base map code for calling in home page(Navigation purpose)---------------------------------------------------------------->
2018
+
2019
+ def basemap_page():
2020
+ st.title("Search Basemaps")
2021
+ base_map()
2022
+
2023
+
2024
+ #<----------------------------------------------------------------basemap code------------------------------------------------------------------------------------------------------>
2025
+
2026
+ def base_map():
2027
+
2028
+ with st.expander("See demo"):
2029
+ st.image("https://i.imgur.com/0SkUhZh.gif")
2030
+
2031
+ row1_col1, row1_col2 = st.columns([3, 1])
2032
+ width = 800
2033
+ height = 600
2034
+ tiles = None
2035
+
2036
+ with row1_col2:
2037
+
2038
+ checkbox = st.checkbox("Search Quick Map Services (QMS)")
2039
+ keyword = st.text_input("Enter a keyword to search and press Enter:")
2040
+ empty = st.empty()
2041
+
2042
+ if keyword:
2043
+ options = leafmap.search_xyz_services(keyword=keyword)
2044
+ if checkbox:
2045
+ qms = leafmap.search_qms(keyword=keyword)
2046
+ if qms is not None:
2047
+ options = options + qms
2048
+
2049
+ tiles = empty.multiselect("Select XYZ tiles to add to the map:", options)
2050
+
2051
+ with row1_col1:
2052
+ m = leafmap.Map()
2053
+
2054
+ if tiles is not None:
2055
+ for tile in tiles:
2056
+ m.add_xyz_service(tile)
2057
+
2058
+ m.to_streamlit(height=height)
2059
+
2060
+
2061
+ #<-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
2062
+
2063
+
2064
+ # Create a dictionary of pages
2065
+ pages = {
2066
+ "Home": page_home,
2067
+ "About": page_about,
2068
+ "Interactive Map": interactive_map_page,
2069
+ "Timelapse": Timelapse_page, # Placeholder for Timelapse page function
2070
+ "Basemap": basemap_page,
2071
+ }
2072
+
2073
+ # Add a sidebar for navigation
2074
+ st.sidebar.title("Navigation")
2075
+ selection = st.sidebar.radio("Go to", list(pages.keys()))
2076
+
2077
+ # Call the function of the selected page
2078
+ page = pages[selection]
2079
+ page()
y/Interactive_Map.py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import folium
3
+ import geopandas as gpd
4
+ import json
5
+ import geemap.foliumap as geemap
6
+ import ee
7
+ import pandas as pd
8
+ import os
9
+ from google.auth.transport.requests import Request
10
+ import google.auth.exceptions
11
+ from streamlit.components.v1 import html
12
+
13
+ # Path to your shapefiles and service account key
14
+ SHAPEFILE_DIR = 'C:/Users/piv/Desktop/y/media/shp'
15
+
16
+ def initialize_gee():
17
+ service = os.getenv('SA')
18
+ file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'gee', 'ee-muzzamil1-37ebc3dece52.json')
19
+ credentials = ee.ServiceAccountCredentials(service, file)
20
+ try:
21
+ ee.Initialize(credentials)
22
+ st.success("Google Earth Engine initialized successfully.")
23
+ except google.auth.exceptions.RefreshError:
24
+ try:
25
+ request = Request()
26
+ credentials.refresh(request)
27
+ ee.Initialize(credentials)
28
+ st.success("Google Earth Engine token refreshed and initialized successfully.")
29
+ except Exception as e:
30
+ st.error(f"Error refreshing Google Earth Engine token: {e}")
31
+ except Exception as e:
32
+ st.error(f"Error initializing Google Earth Engine: {e}")
33
+
34
+ def create_folium_map(selected_dataset, ee_object, start_date_str, end_date_str):
35
+ folium_map = folium.Map(location=[25.5973518, 65.54495724], zoom_start=7)
36
+
37
+ try:
38
+ if selected_dataset == "Modis":
39
+ dataset = ee.ImageCollection('MODIS/006/MOD13Q1') \
40
+ .filter(ee.Filter.date(start_date_str, end_date_str)) \
41
+ .filterBounds(ee_object)
42
+
43
+ def clip_image(img):
44
+ return img.clip(ee_object).select('NDVI')
45
+
46
+ clipped_collection = dataset.map(clip_image)
47
+ modis_ndvi = clipped_collection.mean()
48
+ vis_params_ndvi = {
49
+ 'min': 0,
50
+ 'max': 9000,
51
+ 'palette': ['FE8374', 'C0E5DE', '3A837C', '034B48']
52
+ }
53
+ modis_ndvi_map_id = modis_ndvi.getMapId(vis_params_ndvi)
54
+ folium.TileLayer(
55
+ tiles=modis_ndvi_map_id['tile_fetcher'].url_format,
56
+ attr='Google Earth Engine',
57
+ name='NDVI',
58
+ overlay=True,
59
+ control=True
60
+ ).add_to(folium_map)
61
+
62
+ elif selected_dataset == "dataset_nighttime":
63
+ dataset_nighttime = ee.ImageCollection('NOAA/VIIRS/DNB/MONTHLY_V1/VCMCFG') \
64
+ .filter(ee.Filter.date(start_date_str, end_date_str))
65
+
66
+ nighttime = dataset_nighttime.select('avg_rad').mosaic()
67
+ nighttime_clipped = nighttime.clip(ee_object)
68
+ nighttime_vis = {
69
+ 'min': 0.0,
70
+ 'max': 60.0,
71
+ 'palette': ['1a3678', '2955bc', '5699ff', '8dbae9', 'acd1ff', 'caebff', 'e5f9ff', 'fdffb4', 'ffe6a2', 'ffc969', 'ffa12d', 'ff7c1f', 'ca531a', 'ff0000', 'ab0000']
72
+ }
73
+ nighttime_map_id = nighttime_clipped.getMapId(nighttime_vis)
74
+ folium.TileLayer(
75
+ tiles=nighttime_map_id['tile_fetcher'].url_format,
76
+ attr='Google Earth Engine',
77
+ name='Nighttime Lights',
78
+ overlay=True,
79
+ control=True
80
+ ).add_to(folium_map)
81
+
82
+ elif selected_dataset == "precipitation":
83
+ dataset_precipitation = ee.ImageCollection('UCSB-CHG/CHIRPS/DAILY') \
84
+ .filter(ee.Filter.date(start_date_str, end_date_str))
85
+
86
+ precipitation = dataset_precipitation.mosaic().clip(ee_object)
87
+ precip_vis = {
88
+ 'min': 0,
89
+ 'max': 300,
90
+ 'palette': ['blue', 'cyan', 'lime', 'yellow', 'red']
91
+ }
92
+ precip_map_id = precipitation.getMapId(precip_vis)
93
+ folium.TileLayer(
94
+ tiles=precip_map_id['tile_fetcher'].url_format,
95
+ attr='Google Earth Engine',
96
+ name='Precipitation',
97
+ overlay=True,
98
+ control=True
99
+ ).add_to(folium_map)
100
+
101
+ elif selected_dataset == "GlobalSurfaceWater":
102
+ st.warning("GlobalSurfaceWater dataset is not configured.")
103
+
104
+ elif selected_dataset == "WorldPop":
105
+ dataset = ee.ImageCollection('WorldPop/GP/100m/pop') \
106
+ .filterBounds(ee_object) \
107
+ .filter(ee.Filter.date(start_date_str, end_date_str))
108
+
109
+ population = dataset.mean().clip(ee_object)
110
+ pop_vis = {
111
+ 'min': 0,
112
+ 'max': 1000,
113
+ 'palette': ['blue', 'green', 'yellow', 'red']
114
+ }
115
+ pop_map_id = population.getMapId(pop_vis)
116
+ folium.TileLayer(
117
+ tiles=pop_map_id['tile_fetcher'].url_format,
118
+ attr='Google Earth Engine',
119
+ name='World Population',
120
+ overlay=True,
121
+ control=True
122
+ ).add_to(folium_map)
123
+
124
+ elif selected_dataset == "COPERNICUS":
125
+ dataset = ee.ImageCollection('COPERNICUS/S2') \
126
+ .filterBounds(ee_object) \
127
+ .filter(ee.Filter.date(start_date_str, end_date_str))
128
+
129
+ sentinel = dataset.median().clip(ee_object)
130
+ vis_params = {
131
+ 'bands': ['B4', 'B3', 'B2'],
132
+ 'min': 0,
133
+ 'max': 3000,
134
+ 'gamma': 1.4
135
+ }
136
+ copernicus_map_id = sentinel.getMapId(vis_params)
137
+ folium.TileLayer(
138
+ tiles=copernicus_map_id['tile_fetcher'].url_format,
139
+ attr='Google Earth Engine',
140
+ name='Copernicus Sentinel-2',
141
+ overlay=True,
142
+ control=True
143
+ ).add_to(folium_map)
144
+
145
+ folium_map.add_child(folium.LayerControl())
146
+ except Exception as e:
147
+ st.error(f"Error processing dataset: {e}")
148
+
149
+ folium_map_html = folium_map._repr_html_()
150
+ return folium_map_html
151
+
152
+ def handle_submit(selected_dataset, selected_date_range_From, selected_date_range_To, selected_shape):
153
+ shapefile_name = f'{selected_shape}.shp'
154
+ shapefile_path = os.path.join(SHAPEFILE_DIR, shapefile_name)
155
+
156
+ if os.path.exists(shapefile_path):
157
+ try:
158
+ roi_gdf = gpd.read_file(shapefile_path)
159
+ roi_geojson = roi_gdf.to_crs("EPSG:4326").to_json()
160
+ except Exception as e:
161
+ st.error(f"Error reading shapefile: {e}")
162
+ return
163
+
164
+ try:
165
+ ee_object = geemap.geojson_to_ee(json.loads(roi_geojson))
166
+ except Exception as e:
167
+ st.error(f"Error converting GeoJSON to Earth Engine object: {e}")
168
+ return
169
+
170
+ st.markdown("### Satellite Data Map")
171
+ folium_map_html = create_folium_map(
172
+ selected_dataset,
173
+ ee_object,
174
+ selected_date_range_From.strftime('%Y-%m-%d'),
175
+ selected_date_range_To.strftime('%Y-%m-%d')
176
+ )
177
+ html(folium_map_html, height=600)
178
+ else:
179
+ st.error("Selected shapefile does not exist.")
180
+
181
+ def submit_control():
182
+ selected_dataset = st.sidebar.selectbox(
183
+ "Select Dataset",
184
+ ["Modis", "dataset_nighttime", 'precipitation', 'GlobalSurfaceWater', 'WorldPop', 'COPERNICUS']
185
+ )
186
+
187
+ selected_date_range_From = st.sidebar.date_input("From", value=pd.to_datetime("2015-07-01"))
188
+ selected_date_range_To = st.sidebar.date_input("To", value=pd.to_datetime("2023-09-30"))
189
+
190
+ shape_options = [
191
+ 'District_Boundary', 'hydro_basins', 'karachi',
192
+ 'National_Constituency_with_Projected_2010_Population',
193
+ 'Provincial_Boundary', 'Provincial_Constituency',
194
+ 'Tehsil_Boundary', 'Union_Council'
195
+ ]
196
+
197
+ selected_shape = st.sidebar.selectbox("Select Shape", shape_options)
198
+
199
+ if st.sidebar.button("Submit"):
200
+ st.session_state.selected_dataset = selected_dataset
201
+ st.session_state.selected_date_range_From = selected_date_range_From
202
+ st.session_state.selected_date_range_To = selected_date_range_To
203
+ st.session_state.selected_shape = selected_shape
204
+ st.session_state.submitted = True
205
+ else:
206
+ st.session_state.submitted = False
207
+
208
+ if 'submitted' in st.session_state and st.session_state.submitted:
209
+ handle_submit(
210
+ st.session_state.selected_dataset,
211
+ st.session_state.selected_date_range_From,
212
+ st.session_state.selected_date_range_To,
213
+ st.session_state.selected_shape
214
+ )
215
+
216
+ def main():
217
+ st.set_page_config(layout="wide")
218
+ st.title("Satellite Data Visualization, Interactive Map")
219
+
220
+ initialize_gee()
221
+ submit_control()
222
+
223
+ if __name__ == "__main__":
224
+ main()
y/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2020 bikesh bade
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
y/Timelapse.py ADDED
@@ -0,0 +1,1534 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ee
2
+ import json
3
+ import os
4
+ import warnings
5
+ import datetime
6
+ import fiona
7
+ import geopandas as gpd
8
+ import folium
9
+ import streamlit as st
10
+ import geemap.colormaps as cm
11
+ import geemap.foliumap as geemap
12
+ from datetime import date
13
+ from shapely.geometry import Polygon
14
+
15
+ st.set_page_config(layout="wide")
16
+ warnings.filterwarnings("ignore")
17
+
18
+
19
+ @st.cache_data
20
+ def ee_authenticate(token_name="EARTHENGINE_TOKEN"):
21
+ geemap.ee_initialize(token_name=token_name)
22
+
23
+
24
+ st.sidebar.info(
25
+ """
26
+ - Web App URL: <https://streamlit.gishub.org>
27
+ - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
28
+ """
29
+ )
30
+
31
+ st.sidebar.title("Contact")
32
+ st.sidebar.info(
33
+ """
34
+ 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)
35
+ """
36
+ )
37
+
38
+ goes_rois = {
39
+ "Creek Fire, CA (2020-09-05)": {
40
+ "region": Polygon(
41
+ [
42
+ [-121.003418, 36.848857],
43
+ [-121.003418, 39.049052],
44
+ [-117.905273, 39.049052],
45
+ [-117.905273, 36.848857],
46
+ [-121.003418, 36.848857],
47
+ ]
48
+ ),
49
+ "start_time": "2020-09-05T15:00:00",
50
+ "end_time": "2020-09-06T02:00:00",
51
+ },
52
+ "Bomb Cyclone (2021-10-24)": {
53
+ "region": Polygon(
54
+ [
55
+ [-159.5954, 60.4088],
56
+ [-159.5954, 24.5178],
57
+ [-114.2438, 24.5178],
58
+ [-114.2438, 60.4088],
59
+ ]
60
+ ),
61
+ "start_time": "2021-10-24T14:00:00",
62
+ "end_time": "2021-10-25T01:00:00",
63
+ },
64
+ "Hunga Tonga Volcanic Eruption (2022-01-15)": {
65
+ "region": Polygon(
66
+ [
67
+ [-192.480469, -32.546813],
68
+ [-192.480469, -8.754795],
69
+ [-157.587891, -8.754795],
70
+ [-157.587891, -32.546813],
71
+ [-192.480469, -32.546813],
72
+ ]
73
+ ),
74
+ "start_time": "2022-01-15T03:00:00",
75
+ "end_time": "2022-01-15T07:00:00",
76
+ },
77
+ "Hunga Tonga Volcanic Eruption Closer Look (2022-01-15)": {
78
+ "region": Polygon(
79
+ [
80
+ [-178.901367, -22.958393],
81
+ [-178.901367, -17.85329],
82
+ [-171.452637, -17.85329],
83
+ [-171.452637, -22.958393],
84
+ [-178.901367, -22.958393],
85
+ ]
86
+ ),
87
+ "start_time": "2022-01-15T03:00:00",
88
+ "end_time": "2022-01-15T07:00:00",
89
+ },
90
+ }
91
+
92
+
93
+ landsat_rois = {
94
+ "Aral Sea": Polygon(
95
+ [
96
+ [57.667236, 43.834527],
97
+ [57.667236, 45.996962],
98
+ [61.12793, 45.996962],
99
+ [61.12793, 43.834527],
100
+ [57.667236, 43.834527],
101
+ ]
102
+ ),
103
+ "Dubai": Polygon(
104
+ [
105
+ [54.541626, 24.763044],
106
+ [54.541626, 25.427152],
107
+ [55.632019, 25.427152],
108
+ [55.632019, 24.763044],
109
+ [54.541626, 24.763044],
110
+ ]
111
+ ),
112
+ "Hong Kong International Airport": Polygon(
113
+ [
114
+ [113.825226, 22.198849],
115
+ [113.825226, 22.349758],
116
+ [114.085121, 22.349758],
117
+ [114.085121, 22.198849],
118
+ [113.825226, 22.198849],
119
+ ]
120
+ ),
121
+ "Las Vegas, NV": Polygon(
122
+ [
123
+ [-115.554199, 35.804449],
124
+ [-115.554199, 36.558188],
125
+ [-113.903503, 36.558188],
126
+ [-113.903503, 35.804449],
127
+ [-115.554199, 35.804449],
128
+ ]
129
+ ),
130
+ "Pucallpa, Peru": Polygon(
131
+ [
132
+ [-74.672699, -8.600032],
133
+ [-74.672699, -8.254983],
134
+ [-74.279938, -8.254983],
135
+ [-74.279938, -8.600032],
136
+ ]
137
+ ),
138
+ "Sierra Gorda, Chile": Polygon(
139
+ [
140
+ [-69.315491, -22.837104],
141
+ [-69.315491, -22.751488],
142
+ [-69.190006, -22.751488],
143
+ [-69.190006, -22.837104],
144
+ [-69.315491, -22.837104],
145
+ ]
146
+ ),
147
+ }
148
+
149
+ modis_rois = {
150
+ "World": Polygon(
151
+ [
152
+ [-171.210938, -57.136239],
153
+ [-171.210938, 79.997168],
154
+ [177.539063, 79.997168],
155
+ [177.539063, -57.136239],
156
+ [-171.210938, -57.136239],
157
+ ]
158
+ ),
159
+ "Africa": Polygon(
160
+ [
161
+ [-18.6983, 38.1446],
162
+ [-18.6983, -36.1630],
163
+ [52.2293, -36.1630],
164
+ [52.2293, 38.1446],
165
+ ]
166
+ ),
167
+ "USA": Polygon(
168
+ [
169
+ [-127.177734, 23.725012],
170
+ [-127.177734, 50.792047],
171
+ [-66.269531, 50.792047],
172
+ [-66.269531, 23.725012],
173
+ [-127.177734, 23.725012],
174
+ ]
175
+ ),
176
+ }
177
+
178
+ ocean_rois = {
179
+ "Gulf of Mexico": Polygon(
180
+ [
181
+ [-101.206055, 15.496032],
182
+ [-101.206055, 32.361403],
183
+ [-75.673828, 32.361403],
184
+ [-75.673828, 15.496032],
185
+ [-101.206055, 15.496032],
186
+ ]
187
+ ),
188
+ "North Atlantic Ocean": Polygon(
189
+ [
190
+ [-85.341797, 24.046464],
191
+ [-85.341797, 45.02695],
192
+ [-55.810547, 45.02695],
193
+ [-55.810547, 24.046464],
194
+ [-85.341797, 24.046464],
195
+ ]
196
+ ),
197
+ "World": Polygon(
198
+ [
199
+ [-171.210938, -57.136239],
200
+ [-171.210938, 79.997168],
201
+ [177.539063, 79.997168],
202
+ [177.539063, -57.136239],
203
+ [-171.210938, -57.136239],
204
+ ]
205
+ ),
206
+ }
207
+
208
+
209
+ @st.cache_data
210
+ def uploaded_file_to_gdf(data):
211
+ import tempfile
212
+ import os
213
+ import uuid
214
+
215
+ _, file_extension = os.path.splitext(data.name)
216
+ file_id = str(uuid.uuid4())
217
+ file_path = os.path.join(tempfile.gettempdir(), f"{file_id}{file_extension}")
218
+
219
+ with open(file_path, "wb") as file:
220
+ file.write(data.getbuffer())
221
+
222
+ if file_path.lower().endswith(".kml"):
223
+ fiona.drvsupport.supported_drivers["KML"] = "rw"
224
+ gdf = gpd.read_file(file_path, driver="KML")
225
+ else:
226
+ gdf = gpd.read_file(file_path)
227
+
228
+ return gdf
229
+
230
+
231
+ def app():
232
+
233
+ today = date.today()
234
+
235
+ st.title("Create Satellite Timelapse")
236
+
237
+ st.markdown(
238
+ """
239
+ 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.
240
+ 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).
241
+ """
242
+ )
243
+
244
+ row1_col1, row1_col2 = st.columns([2, 1])
245
+
246
+ if st.session_state.get("zoom_level") is None:
247
+ st.session_state["zoom_level"] = 4
248
+
249
+ st.session_state["ee_asset_id"] = None
250
+ st.session_state["bands"] = None
251
+ st.session_state["palette"] = None
252
+ st.session_state["vis_params"] = None
253
+
254
+ with row1_col1:
255
+ ee_authenticate(token_name="EARTHENGINE_TOKEN")
256
+ m = geemap.Map(
257
+ basemap="HYBRID",
258
+ plugin_Draw=True,
259
+ Draw_export=True,
260
+ locate_control=True,
261
+ plugin_LatLngPopup=False,
262
+ )
263
+ m.add_basemap("ROADMAP")
264
+
265
+ with row1_col2:
266
+
267
+ keyword = st.text_input("Search for a location:", "")
268
+ if keyword:
269
+ locations = geemap.geocode(keyword)
270
+ if locations is not None and len(locations) > 0:
271
+ str_locations = [str(g)[1:-1] for g in locations]
272
+ location = st.selectbox("Select a location:", str_locations)
273
+ loc_index = str_locations.index(location)
274
+ selected_loc = locations[loc_index]
275
+ lat, lng = selected_loc.lat, selected_loc.lng
276
+ folium.Marker(location=[lat, lng], popup=location).add_to(m)
277
+ m.set_center(lng, lat, 12)
278
+ st.session_state["zoom_level"] = 12
279
+
280
+ collection = st.selectbox(
281
+ "Select a satellite image collection: ",
282
+ [
283
+ "Any Earth Engine ImageCollection",
284
+ "Landsat TM-ETM-OLI Surface Reflectance",
285
+ "Sentinel-2 MSI Surface Reflectance",
286
+ "Geostationary Operational Environmental Satellites (GOES)",
287
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
288
+ "MODIS Gap filled Land Surface Temperature Daily",
289
+ "MODIS Ocean Color SMI",
290
+ "USDA National Agriculture Imagery Program (NAIP)",
291
+ ],
292
+ index=1,
293
+ )
294
+
295
+ if collection in [
296
+ "Landsat TM-ETM-OLI Surface Reflectance",
297
+ "Sentinel-2 MSI Surface Reflectance",
298
+ ]:
299
+ roi_options = ["Uploaded GeoJSON"] + list(landsat_rois.keys())
300
+
301
+ elif collection == "Geostationary Operational Environmental Satellites (GOES)":
302
+ roi_options = ["Uploaded GeoJSON"] + list(goes_rois.keys())
303
+
304
+ elif collection in [
305
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
306
+ "MODIS Gap filled Land Surface Temperature Daily",
307
+ ]:
308
+ roi_options = ["Uploaded GeoJSON"] + list(modis_rois.keys())
309
+ elif collection == "MODIS Ocean Color SMI":
310
+ roi_options = ["Uploaded GeoJSON"] + list(ocean_rois.keys())
311
+ else:
312
+ roi_options = ["Uploaded GeoJSON"]
313
+
314
+ if collection == "Any Earth Engine ImageCollection":
315
+ keyword = st.text_input("Enter a keyword to search (e.g., MODIS):", "")
316
+ if keyword:
317
+
318
+ assets = geemap.search_ee_data(keyword)
319
+ ee_assets = []
320
+ for asset in assets:
321
+ if asset["ee_id_snippet"].startswith("ee.ImageCollection"):
322
+ ee_assets.append(asset)
323
+
324
+ asset_titles = [x["title"] for x in ee_assets]
325
+ dataset = st.selectbox("Select a dataset:", asset_titles)
326
+ if len(ee_assets) > 0:
327
+ st.session_state["ee_assets"] = ee_assets
328
+ st.session_state["asset_titles"] = asset_titles
329
+ index = asset_titles.index(dataset)
330
+ ee_id = ee_assets[index]["id"]
331
+ else:
332
+ ee_id = ""
333
+
334
+ if dataset is not None:
335
+ with st.expander("Show dataset details", False):
336
+ index = asset_titles.index(dataset)
337
+ html = geemap.ee_data_html(st.session_state["ee_assets"][index])
338
+ st.markdown(html, True)
339
+ # elif collection == "MODIS Gap filled Land Surface Temperature Daily":
340
+ # ee_id = ""
341
+ else:
342
+ ee_id = ""
343
+
344
+ asset_id = st.text_input("Enter an ee.ImageCollection asset ID:", ee_id)
345
+
346
+ if asset_id:
347
+ with st.expander("Customize band combination and color palette", True):
348
+ try:
349
+ col = ee.ImageCollection.load(asset_id)
350
+ st.session_state["ee_asset_id"] = asset_id
351
+ except:
352
+ st.error("Invalid Earth Engine asset ID.")
353
+ st.session_state["ee_asset_id"] = None
354
+ return
355
+
356
+ img_bands = col.first().bandNames().getInfo()
357
+ if len(img_bands) >= 3:
358
+ default_bands = img_bands[:3][::-1]
359
+ else:
360
+ default_bands = img_bands[:]
361
+ bands = st.multiselect(
362
+ "Select one or three bands (RGB):", img_bands, default_bands
363
+ )
364
+ st.session_state["bands"] = bands
365
+
366
+ if len(bands) == 1:
367
+ palette_options = st.selectbox(
368
+ "Color palette",
369
+ cm.list_colormaps(),
370
+ index=2,
371
+ )
372
+ palette_values = cm.get_palette(palette_options, 15)
373
+ palette = st.text_area(
374
+ "Enter a custom palette:",
375
+ palette_values,
376
+ )
377
+ st.write(
378
+ cm.plot_colormap(cmap=palette_options, return_fig=True)
379
+ )
380
+ st.session_state["palette"] = json.loads(
381
+ palette.replace("'", '"')
382
+ )
383
+
384
+ if bands:
385
+ vis_params = st.text_area(
386
+ "Enter visualization parameters",
387
+ "{'bands': ["
388
+ + ", ".join([f"'{band}'" for band in bands])
389
+ + "]}",
390
+ )
391
+ else:
392
+ vis_params = st.text_area(
393
+ "Enter visualization parameters",
394
+ "{}",
395
+ )
396
+ try:
397
+ st.session_state["vis_params"] = json.loads(
398
+ vis_params.replace("'", '"')
399
+ )
400
+ st.session_state["vis_params"]["palette"] = st.session_state[
401
+ "palette"
402
+ ]
403
+ except Exception as e:
404
+ st.session_state["vis_params"] = None
405
+ st.error(
406
+ f"Invalid visualization parameters. It must be a dictionary."
407
+ )
408
+
409
+ elif collection == "MODIS Gap filled Land Surface Temperature Daily":
410
+ with st.expander("Show dataset details", False):
411
+ st.markdown(
412
+ """
413
+ See the [Awesome GEE Community Datasets](https://samapriya.github.io/awesome-gee-community-datasets/projects/daily_lst/).
414
+ """
415
+ )
416
+
417
+ MODIS_options = ["Daytime (1:30 pm)", "Nighttime (1:30 am)"]
418
+ MODIS_option = st.selectbox("Select a MODIS dataset:", MODIS_options)
419
+ if MODIS_option == "Daytime (1:30 pm)":
420
+ st.session_state["ee_asset_id"] = (
421
+ "projects/sat-io/open-datasets/gap-filled-lst/gf_day_1km"
422
+ )
423
+ else:
424
+ st.session_state["ee_asset_id"] = (
425
+ "projects/sat-io/open-datasets/gap-filled-lst/gf_night_1km"
426
+ )
427
+
428
+ palette_options = st.selectbox(
429
+ "Color palette",
430
+ cm.list_colormaps(),
431
+ index=90,
432
+ )
433
+ palette_values = cm.get_palette(palette_options, 15)
434
+ palette = st.text_area(
435
+ "Enter a custom palette:",
436
+ palette_values,
437
+ )
438
+ st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
439
+ st.session_state["palette"] = json.loads(palette.replace("'", '"'))
440
+ elif collection == "MODIS Ocean Color SMI":
441
+ with st.expander("Show dataset details", False):
442
+ st.markdown(
443
+ """
444
+ See the [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets/catalog/NASA_OCEANDATA_MODIS-Aqua_L3SMI).
445
+ """
446
+ )
447
+
448
+ MODIS_options = ["Aqua", "Terra"]
449
+ MODIS_option = st.selectbox("Select a satellite:", MODIS_options)
450
+ st.session_state["ee_asset_id"] = MODIS_option
451
+ # if MODIS_option == "Daytime (1:30 pm)":
452
+ # st.session_state[
453
+ # "ee_asset_id"
454
+ # ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_day_1km"
455
+ # else:
456
+ # st.session_state[
457
+ # "ee_asset_id"
458
+ # ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_night_1km"
459
+
460
+ band_dict = {
461
+ "Chlorophyll a concentration": "chlor_a",
462
+ "Normalized fluorescence line height": "nflh",
463
+ "Particulate organic carbon": "poc",
464
+ "Sea surface temperature": "sst",
465
+ "Remote sensing reflectance at band 412nm": "Rrs_412",
466
+ "Remote sensing reflectance at band 443nm": "Rrs_443",
467
+ "Remote sensing reflectance at band 469nm": "Rrs_469",
468
+ "Remote sensing reflectance at band 488nm": "Rrs_488",
469
+ "Remote sensing reflectance at band 531nm": "Rrs_531",
470
+ "Remote sensing reflectance at band 547nm": "Rrs_547",
471
+ "Remote sensing reflectance at band 555nm": "Rrs_555",
472
+ "Remote sensing reflectance at band 645nm": "Rrs_645",
473
+ "Remote sensing reflectance at band 667nm": "Rrs_667",
474
+ "Remote sensing reflectance at band 678nm": "Rrs_678",
475
+ }
476
+
477
+ band_options = list(band_dict.keys())
478
+ band = st.selectbox(
479
+ "Select a band",
480
+ band_options,
481
+ band_options.index("Sea surface temperature"),
482
+ )
483
+ st.session_state["band"] = band_dict[band]
484
+
485
+ colors = cm.list_colormaps()
486
+ palette_options = st.selectbox(
487
+ "Color palette",
488
+ colors,
489
+ index=colors.index("coolwarm"),
490
+ )
491
+ palette_values = cm.get_palette(palette_options, 15)
492
+ palette = st.text_area(
493
+ "Enter a custom palette:",
494
+ palette_values,
495
+ )
496
+ st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
497
+ st.session_state["palette"] = json.loads(palette.replace("'", '"'))
498
+
499
+ sample_roi = st.selectbox(
500
+ "Select a sample ROI or upload a GeoJSON file:",
501
+ roi_options,
502
+ index=0,
503
+ )
504
+
505
+ add_outline = st.checkbox(
506
+ "Overlay an administrative boundary on timelapse", False
507
+ )
508
+
509
+ if add_outline:
510
+
511
+ with st.expander("Customize administrative boundary", True):
512
+
513
+ overlay_options = {
514
+ "User-defined": None,
515
+ "Continents": "continents",
516
+ "Countries": "countries",
517
+ "US States": "us_states",
518
+ "China": "china",
519
+ }
520
+
521
+ overlay = st.selectbox(
522
+ "Select an administrative boundary:",
523
+ list(overlay_options.keys()),
524
+ index=2,
525
+ )
526
+
527
+ overlay_data = overlay_options[overlay]
528
+
529
+ if overlay_data is None:
530
+ overlay_data = st.text_input(
531
+ "Enter an HTTP URL to a GeoJSON file or an ee.FeatureCollection asset id:",
532
+ "https://raw.githubusercontent.com/giswqs/geemap/master/examples/data/countries.geojson",
533
+ )
534
+
535
+ overlay_color = st.color_picker(
536
+ "Select a color for the administrative boundary:", "#000000"
537
+ )
538
+ overlay_width = st.slider(
539
+ "Select a line width for the administrative boundary:", 1, 20, 1
540
+ )
541
+ overlay_opacity = st.slider(
542
+ "Select an opacity for the administrative boundary:",
543
+ 0.0,
544
+ 1.0,
545
+ 1.0,
546
+ 0.05,
547
+ )
548
+ else:
549
+ overlay_data = None
550
+ overlay_color = "black"
551
+ overlay_width = 1
552
+ overlay_opacity = 1
553
+
554
+ with row1_col1:
555
+
556
+ with st.expander(
557
+ "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 👉"
558
+ ):
559
+ video_empty = st.empty()
560
+
561
+ data = st.file_uploader(
562
+ "Upload a GeoJSON file to use as an ROI. Customize timelapse parameters and then click the Submit button 😇👇",
563
+ type=["geojson", "kml", "zip"],
564
+ )
565
+
566
+ crs = "epsg:4326"
567
+ if sample_roi == "Uploaded GeoJSON":
568
+ if data is None:
569
+ # st.info(
570
+ # "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"
571
+ # )
572
+ if collection in [
573
+ "Geostationary Operational Environmental Satellites (GOES)",
574
+ "USDA National Agriculture Imagery Program (NAIP)",
575
+ ] and (not keyword):
576
+ m.set_center(-100, 40, 3)
577
+ # else:
578
+ # m.set_center(4.20, 18.63, zoom=2)
579
+ else:
580
+ if collection in [
581
+ "Landsat TM-ETM-OLI Surface Reflectance",
582
+ "Sentinel-2 MSI Surface Reflectance",
583
+ ]:
584
+ gdf = gpd.GeoDataFrame(
585
+ index=[0], crs=crs, geometry=[landsat_rois[sample_roi]]
586
+ )
587
+ elif (
588
+ collection
589
+ == "Geostationary Operational Environmental Satellites (GOES)"
590
+ ):
591
+ gdf = gpd.GeoDataFrame(
592
+ index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
593
+ )
594
+ elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
595
+ gdf = gpd.GeoDataFrame(
596
+ index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
597
+ )
598
+
599
+ if sample_roi != "Uploaded GeoJSON":
600
+
601
+ if collection in [
602
+ "Landsat TM-ETM-OLI Surface Reflectance",
603
+ "Sentinel-2 MSI Surface Reflectance",
604
+ ]:
605
+ gdf = gpd.GeoDataFrame(
606
+ index=[0], crs=crs, geometry=[landsat_rois[sample_roi]]
607
+ )
608
+ elif (
609
+ collection
610
+ == "Geostationary Operational Environmental Satellites (GOES)"
611
+ ):
612
+ gdf = gpd.GeoDataFrame(
613
+ index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
614
+ )
615
+ elif collection in [
616
+ "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
617
+ "MODIS Gap filled Land Surface Temperature Daily",
618
+ ]:
619
+ gdf = gpd.GeoDataFrame(
620
+ index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
621
+ )
622
+ elif collection == "MODIS Ocean Color SMI":
623
+ gdf = gpd.GeoDataFrame(
624
+ index=[0], crs=crs, geometry=[ocean_rois[sample_roi]]
625
+ )
626
+ try:
627
+ st.session_state["roi"] = geemap.gdf_to_ee(gdf, geodesic=False)
628
+ except Exception as e:
629
+ st.error(e)
630
+ st.error("Please draw another ROI and try again.")
631
+ return
632
+ m.add_gdf(gdf, "ROI")
633
+
634
+ elif data:
635
+ gdf = uploaded_file_to_gdf(data)
636
+ try:
637
+ st.session_state["roi"] = geemap.gdf_to_ee(gdf, geodesic=False)
638
+ m.add_gdf(gdf, "ROI")
639
+ except Exception as e:
640
+ st.error(e)
641
+ st.error("Please draw another ROI and try again.")
642
+ return
643
+
644
+ m.to_streamlit(height=600)
645
+
646
+ with row1_col2:
647
+
648
+ if collection in [
649
+ "Landsat TM-ETM-OLI Surface Reflectance",
650
+ "Sentinel-2 MSI Surface Reflectance",
651
+ ]:
652
+
653
+ if collection == "Landsat TM-ETM-OLI Surface Reflectance":
654
+ sensor_start_year = 1984
655
+ timelapse_title = "Landsat Timelapse"
656
+ timelapse_speed = 5
657
+ elif collection == "Sentinel-2 MSI Surface Reflectance":
658
+ sensor_start_year = 2015
659
+ timelapse_title = "Sentinel-2 Timelapse"
660
+ timelapse_speed = 5
661
+ video_empty.video("https://youtu.be/VVRK_-dEjR4")
662
+
663
+ with st.form("submit_landsat_form"):
664
+
665
+ roi = None
666
+ if st.session_state.get("roi") is not None:
667
+ roi = st.session_state.get("roi")
668
+ out_gif = geemap.temp_file_path(".gif")
669
+
670
+ title = st.text_input(
671
+ "Enter a title to show on the timelapse: ", timelapse_title
672
+ )
673
+ RGB = st.selectbox(
674
+ "Select an RGB band combination:",
675
+ [
676
+ "Red/Green/Blue",
677
+ "NIR/Red/Green",
678
+ "SWIR2/SWIR1/NIR",
679
+ "NIR/SWIR1/Red",
680
+ "SWIR2/NIR/Red",
681
+ "SWIR2/SWIR1/Red",
682
+ "SWIR1/NIR/Blue",
683
+ "NIR/SWIR1/Blue",
684
+ "SWIR2/NIR/Green",
685
+ "SWIR1/NIR/Red",
686
+ "SWIR2/NIR/SWIR1",
687
+ "SWIR1/NIR/SWIR2",
688
+ ],
689
+ index=9,
690
+ )
691
+
692
+ frequency = st.selectbox(
693
+ "Select a temporal frequency:",
694
+ ["year", "quarter", "month"],
695
+ index=0,
696
+ )
697
+
698
+ with st.expander("Customize timelapse"):
699
+
700
+ speed = st.slider("Frames per second:", 1, 30, timelapse_speed)
701
+ dimensions = st.slider(
702
+ "Maximum dimensions (Width*Height) in pixels", 768, 2000, 768
703
+ )
704
+ progress_bar_color = st.color_picker(
705
+ "Progress bar color:", "#0000ff"
706
+ )
707
+ years = st.slider(
708
+ "Start and end year:",
709
+ sensor_start_year,
710
+ today.year,
711
+ (sensor_start_year, today.year),
712
+ )
713
+ months = st.slider("Start and end month:", 1, 12, (1, 12))
714
+ font_size = st.slider("Font size:", 10, 50, 30)
715
+ font_color = st.color_picker("Font color:", "#ffffff")
716
+ apply_fmask = st.checkbox(
717
+ "Apply fmask (remove clouds, shadows, snow)", True
718
+ )
719
+ font_type = st.selectbox(
720
+ "Select the font type for the title:",
721
+ ["arial.ttf", "alibaba.otf"],
722
+ index=0,
723
+ )
724
+ fading = st.slider(
725
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
726
+ )
727
+ mp4 = st.checkbox("Save timelapse as MP4", True)
728
+
729
+ empty_text = st.empty()
730
+ empty_image = st.empty()
731
+ empty_fire_image = st.empty()
732
+ empty_video = st.container()
733
+ submitted = st.form_submit_button("Submit")
734
+ if submitted:
735
+
736
+ if sample_roi == "Uploaded GeoJSON" and data is None:
737
+ empty_text.warning(
738
+ "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."
739
+ )
740
+ else:
741
+
742
+ empty_text.text("Computing... Please wait...")
743
+
744
+ start_year = years[0]
745
+ end_year = years[1]
746
+ start_date = str(months[0]).zfill(2) + "-01"
747
+ end_date = str(months[1]).zfill(2) + "-30"
748
+ bands = RGB.split("/")
749
+
750
+ try:
751
+ if collection == "Landsat TM-ETM-OLI Surface Reflectance":
752
+ out_gif = geemap.landsat_timelapse(
753
+ roi=roi,
754
+ out_gif=out_gif,
755
+ start_year=start_year,
756
+ end_year=end_year,
757
+ start_date=start_date,
758
+ end_date=end_date,
759
+ bands=bands,
760
+ apply_fmask=apply_fmask,
761
+ frames_per_second=speed,
762
+ # dimensions=dimensions,
763
+ dimensions=768,
764
+ overlay_data=overlay_data,
765
+ overlay_color=overlay_color,
766
+ overlay_width=overlay_width,
767
+ overlay_opacity=overlay_opacity,
768
+ frequency=frequency,
769
+ date_format=None,
770
+ title=title,
771
+ title_xy=("2%", "90%"),
772
+ add_text=True,
773
+ text_xy=("2%", "2%"),
774
+ text_sequence=None,
775
+ font_type=font_type,
776
+ font_size=font_size,
777
+ font_color=font_color,
778
+ add_progress_bar=True,
779
+ progress_bar_color=progress_bar_color,
780
+ progress_bar_height=5,
781
+ loop=0,
782
+ mp4=mp4,
783
+ fading=fading,
784
+ )
785
+ elif collection == "Sentinel-2 MSI Surface Reflectance":
786
+ out_gif = geemap.sentinel2_timelapse(
787
+ roi=roi,
788
+ out_gif=out_gif,
789
+ start_year=start_year,
790
+ end_year=end_year,
791
+ start_date=start_date,
792
+ end_date=end_date,
793
+ bands=bands,
794
+ apply_fmask=apply_fmask,
795
+ frames_per_second=speed,
796
+ dimensions=768,
797
+ # dimensions=dimensions,
798
+ overlay_data=overlay_data,
799
+ overlay_color=overlay_color,
800
+ overlay_width=overlay_width,
801
+ overlay_opacity=overlay_opacity,
802
+ frequency=frequency,
803
+ date_format=None,
804
+ title=title,
805
+ title_xy=("2%", "90%"),
806
+ add_text=True,
807
+ text_xy=("2%", "2%"),
808
+ text_sequence=None,
809
+ font_type=font_type,
810
+ font_size=font_size,
811
+ font_color=font_color,
812
+ add_progress_bar=True,
813
+ progress_bar_color=progress_bar_color,
814
+ progress_bar_height=5,
815
+ loop=0,
816
+ mp4=mp4,
817
+ fading=fading,
818
+ )
819
+ except:
820
+ empty_text.error(
821
+ "An error occurred while computing the timelapse. Your probably requested too much data. Try reducing the ROI or timespan."
822
+ )
823
+ st.stop()
824
+
825
+ if out_gif is not None and os.path.exists(out_gif):
826
+
827
+ empty_text.text(
828
+ "Right click the GIF to save it to your computer👇"
829
+ )
830
+ empty_image.image(out_gif)
831
+
832
+ out_mp4 = out_gif.replace(".gif", ".mp4")
833
+ if mp4 and os.path.exists(out_mp4):
834
+ with empty_video:
835
+ st.text(
836
+ "Right click the MP4 to save it to your computer👇"
837
+ )
838
+ st.video(out_gif.replace(".gif", ".mp4"))
839
+
840
+ else:
841
+ empty_text.error(
842
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
843
+ )
844
+
845
+ elif collection == "Geostationary Operational Environmental Satellites (GOES)":
846
+
847
+ video_empty.video("https://youtu.be/16fA2QORG4A")
848
+
849
+ with st.form("submit_goes_form"):
850
+
851
+ roi = None
852
+ if st.session_state.get("roi") is not None:
853
+ roi = st.session_state.get("roi")
854
+ out_gif = geemap.temp_file_path(".gif")
855
+
856
+ satellite = st.selectbox("Select a satellite:", ["GOES-17", "GOES-16"])
857
+ earliest_date = datetime.date(2017, 7, 10)
858
+ latest_date = datetime.date.today()
859
+
860
+ if sample_roi == "Uploaded GeoJSON":
861
+ roi_start_date = today - datetime.timedelta(days=2)
862
+ roi_end_date = today - datetime.timedelta(days=1)
863
+ roi_start_time = datetime.time(14, 00)
864
+ roi_end_time = datetime.time(1, 00)
865
+ else:
866
+ roi_start = goes_rois[sample_roi]["start_time"]
867
+ roi_end = goes_rois[sample_roi]["end_time"]
868
+ roi_start_date = datetime.datetime.strptime(
869
+ roi_start[:10], "%Y-%m-%d"
870
+ )
871
+ roi_end_date = datetime.datetime.strptime(roi_end[:10], "%Y-%m-%d")
872
+ roi_start_time = datetime.time(
873
+ int(roi_start[11:13]), int(roi_start[14:16])
874
+ )
875
+ roi_end_time = datetime.time(
876
+ int(roi_end[11:13]), int(roi_end[14:16])
877
+ )
878
+
879
+ start_date = st.date_input("Select the start date:", roi_start_date)
880
+ end_date = st.date_input("Select the end date:", roi_end_date)
881
+
882
+ with st.expander("Customize timelapse"):
883
+
884
+ add_fire = st.checkbox("Add Fire/Hotspot Characterization", False)
885
+
886
+ scan_type = st.selectbox(
887
+ "Select a scan type:", ["Full Disk", "CONUS", "Mesoscale"]
888
+ )
889
+
890
+ start_time = st.time_input(
891
+ "Select the start time of the start date:", roi_start_time
892
+ )
893
+
894
+ end_time = st.time_input(
895
+ "Select the end time of the end date:", roi_end_time
896
+ )
897
+
898
+ start = (
899
+ start_date.strftime("%Y-%m-%d")
900
+ + "T"
901
+ + start_time.strftime("%H:%M:%S")
902
+ )
903
+ end = (
904
+ end_date.strftime("%Y-%m-%d")
905
+ + "T"
906
+ + end_time.strftime("%H:%M:%S")
907
+ )
908
+
909
+ speed = st.slider("Frames per second:", 1, 30, 5)
910
+ add_progress_bar = st.checkbox("Add a progress bar", True)
911
+ progress_bar_color = st.color_picker(
912
+ "Progress bar color:", "#0000ff"
913
+ )
914
+ font_size = st.slider("Font size:", 10, 50, 20)
915
+ font_color = st.color_picker("Font color:", "#ffffff")
916
+ fading = st.slider(
917
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
918
+ )
919
+ mp4 = st.checkbox("Save timelapse as MP4", True)
920
+
921
+ empty_text = st.empty()
922
+ empty_image = st.empty()
923
+ empty_video = st.container()
924
+ empty_fire_text = st.empty()
925
+ empty_fire_image = st.empty()
926
+
927
+ submitted = st.form_submit_button("Submit")
928
+ if submitted:
929
+ if sample_roi == "Uploaded GeoJSON" and data is None:
930
+ empty_text.warning(
931
+ "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."
932
+ )
933
+ else:
934
+ empty_text.text("Computing... Please wait...")
935
+
936
+ geemap.goes_timelapse(
937
+ roi,
938
+ out_gif,
939
+ start_date=start,
940
+ end_date=end,
941
+ data=satellite,
942
+ scan=scan_type.replace(" ", "_").lower(),
943
+ dimensions=768,
944
+ framesPerSecond=speed,
945
+ date_format="YYYY-MM-dd HH:mm",
946
+ xy=("3%", "3%"),
947
+ text_sequence=None,
948
+ font_type="arial.ttf",
949
+ font_size=font_size,
950
+ font_color=font_color,
951
+ add_progress_bar=add_progress_bar,
952
+ progress_bar_color=progress_bar_color,
953
+ progress_bar_height=5,
954
+ loop=0,
955
+ overlay_data=overlay_data,
956
+ overlay_color=overlay_color,
957
+ overlay_width=overlay_width,
958
+ overlay_opacity=overlay_opacity,
959
+ mp4=mp4,
960
+ fading=fading,
961
+ )
962
+
963
+ if out_gif is not None and os.path.exists(out_gif):
964
+ empty_text.text(
965
+ "Right click the GIF to save it to your computer👇"
966
+ )
967
+ empty_image.image(out_gif)
968
+
969
+ out_mp4 = out_gif.replace(".gif", ".mp4")
970
+ if mp4 and os.path.exists(out_mp4):
971
+ with empty_video:
972
+ st.text(
973
+ "Right click the MP4 to save it to your computer👇"
974
+ )
975
+ st.video(out_gif.replace(".gif", ".mp4"))
976
+
977
+ if add_fire:
978
+ out_fire_gif = geemap.temp_file_path(".gif")
979
+ empty_fire_text.text(
980
+ "Delineating Fire Hotspot... Please wait..."
981
+ )
982
+ geemap.goes_fire_timelapse(
983
+ out_fire_gif,
984
+ start_date=start,
985
+ end_date=end,
986
+ data=satellite,
987
+ scan=scan_type.replace(" ", "_").lower(),
988
+ region=roi,
989
+ dimensions=768,
990
+ framesPerSecond=speed,
991
+ date_format="YYYY-MM-dd HH:mm",
992
+ xy=("3%", "3%"),
993
+ text_sequence=None,
994
+ font_type="arial.ttf",
995
+ font_size=font_size,
996
+ font_color=font_color,
997
+ add_progress_bar=add_progress_bar,
998
+ progress_bar_color=progress_bar_color,
999
+ progress_bar_height=5,
1000
+ loop=0,
1001
+ )
1002
+ if os.path.exists(out_fire_gif):
1003
+ empty_fire_image.image(out_fire_gif)
1004
+ else:
1005
+ empty_text.text(
1006
+ "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."
1007
+ )
1008
+
1009
+ elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
1010
+
1011
+ video_empty.video("https://youtu.be/16fA2QORG4A")
1012
+
1013
+ satellite = st.selectbox("Select a satellite:", ["Terra", "Aqua"])
1014
+ band = st.selectbox("Select a band:", ["NDVI", "EVI"])
1015
+
1016
+ with st.form("submit_modis_form"):
1017
+
1018
+ roi = None
1019
+ if st.session_state.get("roi") is not None:
1020
+ roi = st.session_state.get("roi")
1021
+ out_gif = geemap.temp_file_path(".gif")
1022
+
1023
+ with st.expander("Customize timelapse"):
1024
+
1025
+ start = st.date_input(
1026
+ "Select a start date:", datetime.date(2000, 2, 8)
1027
+ )
1028
+ end = st.date_input("Select an end date:", datetime.date.today())
1029
+
1030
+ start_date = start.strftime("%Y-%m-%d")
1031
+ end_date = end.strftime("%Y-%m-%d")
1032
+
1033
+ speed = st.slider("Frames per second:", 1, 30, 5)
1034
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1035
+ progress_bar_color = st.color_picker(
1036
+ "Progress bar color:", "#0000ff"
1037
+ )
1038
+ font_size = st.slider("Font size:", 10, 50, 20)
1039
+ font_color = st.color_picker("Font color:", "#ffffff")
1040
+
1041
+ font_type = st.selectbox(
1042
+ "Select the font type for the title:",
1043
+ ["arial.ttf", "alibaba.otf"],
1044
+ index=0,
1045
+ )
1046
+ fading = st.slider(
1047
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1048
+ )
1049
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1050
+
1051
+ empty_text = st.empty()
1052
+ empty_image = st.empty()
1053
+ empty_video = st.container()
1054
+
1055
+ submitted = st.form_submit_button("Submit")
1056
+ if submitted:
1057
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1058
+ empty_text.warning(
1059
+ "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."
1060
+ )
1061
+ else:
1062
+
1063
+ empty_text.text("Computing... Please wait...")
1064
+
1065
+ geemap.modis_ndvi_timelapse(
1066
+ roi,
1067
+ out_gif,
1068
+ satellite,
1069
+ band,
1070
+ start_date,
1071
+ end_date,
1072
+ 768,
1073
+ speed,
1074
+ overlay_data=overlay_data,
1075
+ overlay_color=overlay_color,
1076
+ overlay_width=overlay_width,
1077
+ overlay_opacity=overlay_opacity,
1078
+ mp4=mp4,
1079
+ fading=fading,
1080
+ )
1081
+
1082
+ geemap.reduce_gif_size(out_gif)
1083
+
1084
+ empty_text.text(
1085
+ "Right click the GIF to save it to your computer👇"
1086
+ )
1087
+ empty_image.image(out_gif)
1088
+
1089
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1090
+ if mp4 and os.path.exists(out_mp4):
1091
+ with empty_video:
1092
+ st.text(
1093
+ "Right click the MP4 to save it to your computer👇"
1094
+ )
1095
+ st.video(out_gif.replace(".gif", ".mp4"))
1096
+
1097
+ elif collection == "Any Earth Engine ImageCollection":
1098
+
1099
+ with st.form("submit_ts_form"):
1100
+ with st.expander("Customize timelapse"):
1101
+
1102
+ title = st.text_input(
1103
+ "Enter a title to show on the timelapse: ", "Timelapse"
1104
+ )
1105
+ start_date = st.date_input(
1106
+ "Select the start date:", datetime.date(2020, 1, 1)
1107
+ )
1108
+ end_date = st.date_input(
1109
+ "Select the end date:", datetime.date.today()
1110
+ )
1111
+ frequency = st.selectbox(
1112
+ "Select a temporal frequency:",
1113
+ ["year", "quarter", "month", "day", "hour", "minute", "second"],
1114
+ index=0,
1115
+ )
1116
+ reducer = st.selectbox(
1117
+ "Select a reducer for aggregating data:",
1118
+ ["median", "mean", "min", "max", "sum", "variance", "stdDev"],
1119
+ index=0,
1120
+ )
1121
+ data_format = st.selectbox(
1122
+ "Select a date format to show on the timelapse:",
1123
+ [
1124
+ "YYYY-MM-dd",
1125
+ "YYYY",
1126
+ "YYMM-MM",
1127
+ "YYYY-MM-dd HH:mm",
1128
+ "YYYY-MM-dd HH:mm:ss",
1129
+ "HH:mm",
1130
+ "HH:mm:ss",
1131
+ "w",
1132
+ "M",
1133
+ "d",
1134
+ "D",
1135
+ ],
1136
+ index=0,
1137
+ )
1138
+
1139
+ speed = st.slider("Frames per second:", 1, 30, 5)
1140
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1141
+ progress_bar_color = st.color_picker(
1142
+ "Progress bar color:", "#0000ff"
1143
+ )
1144
+ font_size = st.slider("Font size:", 10, 50, 30)
1145
+ font_color = st.color_picker("Font color:", "#ffffff")
1146
+ font_type = st.selectbox(
1147
+ "Select the font type for the title:",
1148
+ ["arial.ttf", "alibaba.otf"],
1149
+ index=0,
1150
+ )
1151
+ fading = st.slider(
1152
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1153
+ )
1154
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1155
+
1156
+ empty_text = st.empty()
1157
+ empty_image = st.empty()
1158
+ empty_video = st.container()
1159
+ empty_fire_image = st.empty()
1160
+
1161
+ roi = None
1162
+ if st.session_state.get("roi") is not None:
1163
+ roi = st.session_state.get("roi")
1164
+ out_gif = geemap.temp_file_path(".gif")
1165
+
1166
+ submitted = st.form_submit_button("Submit")
1167
+ if submitted:
1168
+
1169
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1170
+ empty_text.warning(
1171
+ "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."
1172
+ )
1173
+ else:
1174
+
1175
+ empty_text.text("Computing... Please wait...")
1176
+ try:
1177
+ geemap.create_timelapse(
1178
+ st.session_state.get("ee_asset_id"),
1179
+ start_date=start_date.strftime("%Y-%m-%d"),
1180
+ end_date=end_date.strftime("%Y-%m-%d"),
1181
+ region=roi,
1182
+ frequency=frequency,
1183
+ reducer=reducer,
1184
+ date_format=data_format,
1185
+ out_gif=out_gif,
1186
+ bands=st.session_state.get("bands"),
1187
+ palette=st.session_state.get("palette"),
1188
+ vis_params=st.session_state.get("vis_params"),
1189
+ dimensions=768,
1190
+ frames_per_second=speed,
1191
+ crs="EPSG:3857",
1192
+ overlay_data=overlay_data,
1193
+ overlay_color=overlay_color,
1194
+ overlay_width=overlay_width,
1195
+ overlay_opacity=overlay_opacity,
1196
+ title=title,
1197
+ title_xy=("2%", "90%"),
1198
+ add_text=True,
1199
+ text_xy=("2%", "2%"),
1200
+ text_sequence=None,
1201
+ font_type=font_type,
1202
+ font_size=font_size,
1203
+ font_color=font_color,
1204
+ add_progress_bar=add_progress_bar,
1205
+ progress_bar_color=progress_bar_color,
1206
+ progress_bar_height=5,
1207
+ loop=0,
1208
+ mp4=mp4,
1209
+ fading=fading,
1210
+ )
1211
+ except:
1212
+ empty_text.error(
1213
+ "An error occurred while computing the timelapse. You probably requested too much data. Try reducing the ROI or timespan."
1214
+ )
1215
+
1216
+ empty_text.text(
1217
+ "Right click the GIF to save it to your computer👇"
1218
+ )
1219
+ empty_image.image(out_gif)
1220
+
1221
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1222
+ if mp4 and os.path.exists(out_mp4):
1223
+ with empty_video:
1224
+ st.text(
1225
+ "Right click the MP4 to save it to your computer👇"
1226
+ )
1227
+ st.video(out_gif.replace(".gif", ".mp4"))
1228
+
1229
+ elif collection in [
1230
+ "MODIS Gap filled Land Surface Temperature Daily",
1231
+ "MODIS Ocean Color SMI",
1232
+ ]:
1233
+
1234
+ with st.form("submit_ts_form"):
1235
+ with st.expander("Customize timelapse"):
1236
+
1237
+ title = st.text_input(
1238
+ "Enter a title to show on the timelapse: ",
1239
+ "Surface Temperature",
1240
+ )
1241
+ start_date = st.date_input(
1242
+ "Select the start date:", datetime.date(2018, 1, 1)
1243
+ )
1244
+ end_date = st.date_input(
1245
+ "Select the end date:", datetime.date(2020, 12, 31)
1246
+ )
1247
+ frequency = st.selectbox(
1248
+ "Select a temporal frequency:",
1249
+ ["year", "quarter", "month", "week", "day"],
1250
+ index=2,
1251
+ )
1252
+ reducer = st.selectbox(
1253
+ "Select a reducer for aggregating data:",
1254
+ ["median", "mean", "min", "max", "sum", "variance", "stdDev"],
1255
+ index=0,
1256
+ )
1257
+
1258
+ vis_params = st.text_area(
1259
+ "Enter visualization parameters",
1260
+ "",
1261
+ help="Enter a string in the format of a dictionary, such as '{'min': 23, 'max': 32}'",
1262
+ )
1263
+
1264
+ speed = st.slider("Frames per second:", 1, 30, 5)
1265
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1266
+ progress_bar_color = st.color_picker(
1267
+ "Progress bar color:", "#0000ff"
1268
+ )
1269
+ font_size = st.slider("Font size:", 10, 50, 30)
1270
+ font_color = st.color_picker("Font color:", "#ffffff")
1271
+ font_type = st.selectbox(
1272
+ "Select the font type for the title:",
1273
+ ["arial.ttf", "alibaba.otf"],
1274
+ index=0,
1275
+ )
1276
+ add_colorbar = st.checkbox("Add a colorbar", True)
1277
+ colorbar_label = st.text_input(
1278
+ "Enter the colorbar label:", "Surface Temperature (°C)"
1279
+ )
1280
+ fading = st.slider(
1281
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1282
+ )
1283
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1284
+
1285
+ empty_text = st.empty()
1286
+ empty_image = st.empty()
1287
+ empty_video = st.container()
1288
+
1289
+ roi = None
1290
+ if st.session_state.get("roi") is not None:
1291
+ roi = st.session_state.get("roi")
1292
+ out_gif = geemap.temp_file_path(".gif")
1293
+
1294
+ submitted = st.form_submit_button("Submit")
1295
+ if submitted:
1296
+
1297
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1298
+ empty_text.warning(
1299
+ "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."
1300
+ )
1301
+ else:
1302
+
1303
+ empty_text.text("Computing... Please wait...")
1304
+ try:
1305
+ if (
1306
+ collection
1307
+ == "MODIS Gap filled Land Surface Temperature Daily"
1308
+ ):
1309
+ out_gif = geemap.create_timelapse(
1310
+ st.session_state.get("ee_asset_id"),
1311
+ start_date=start_date.strftime("%Y-%m-%d"),
1312
+ end_date=end_date.strftime("%Y-%m-%d"),
1313
+ region=roi,
1314
+ bands=None,
1315
+ frequency=frequency,
1316
+ reducer=reducer,
1317
+ date_format=None,
1318
+ out_gif=out_gif,
1319
+ palette=st.session_state.get("palette"),
1320
+ vis_params=None,
1321
+ dimensions=768,
1322
+ frames_per_second=speed,
1323
+ crs="EPSG:3857",
1324
+ overlay_data=overlay_data,
1325
+ overlay_color=overlay_color,
1326
+ overlay_width=overlay_width,
1327
+ overlay_opacity=overlay_opacity,
1328
+ title=title,
1329
+ title_xy=("2%", "90%"),
1330
+ add_text=True,
1331
+ text_xy=("2%", "2%"),
1332
+ text_sequence=None,
1333
+ font_type=font_type,
1334
+ font_size=font_size,
1335
+ font_color=font_color,
1336
+ add_progress_bar=add_progress_bar,
1337
+ progress_bar_color=progress_bar_color,
1338
+ progress_bar_height=5,
1339
+ add_colorbar=add_colorbar,
1340
+ colorbar_label=colorbar_label,
1341
+ loop=0,
1342
+ mp4=mp4,
1343
+ fading=fading,
1344
+ )
1345
+ elif collection == "MODIS Ocean Color SMI":
1346
+ if vis_params.startswith("{") and vis_params.endswith(
1347
+ "}"
1348
+ ):
1349
+ vis_params = json.loads(
1350
+ vis_params.replace("'", '"')
1351
+ )
1352
+ else:
1353
+ vis_params = None
1354
+ out_gif = geemap.modis_ocean_color_timelapse(
1355
+ st.session_state.get("ee_asset_id"),
1356
+ start_date=start_date.strftime("%Y-%m-%d"),
1357
+ end_date=end_date.strftime("%Y-%m-%d"),
1358
+ region=roi,
1359
+ bands=st.session_state["band"],
1360
+ frequency=frequency,
1361
+ reducer=reducer,
1362
+ date_format=None,
1363
+ out_gif=out_gif,
1364
+ palette=st.session_state.get("palette"),
1365
+ vis_params=vis_params,
1366
+ dimensions=768,
1367
+ frames_per_second=speed,
1368
+ crs="EPSG:3857",
1369
+ overlay_data=overlay_data,
1370
+ overlay_color=overlay_color,
1371
+ overlay_width=overlay_width,
1372
+ overlay_opacity=overlay_opacity,
1373
+ title=title,
1374
+ title_xy=("2%", "90%"),
1375
+ add_text=True,
1376
+ text_xy=("2%", "2%"),
1377
+ text_sequence=None,
1378
+ font_type=font_type,
1379
+ font_size=font_size,
1380
+ font_color=font_color,
1381
+ add_progress_bar=add_progress_bar,
1382
+ progress_bar_color=progress_bar_color,
1383
+ progress_bar_height=5,
1384
+ add_colorbar=add_colorbar,
1385
+ colorbar_label=colorbar_label,
1386
+ loop=0,
1387
+ mp4=mp4,
1388
+ fading=fading,
1389
+ )
1390
+ except:
1391
+ empty_text.error(
1392
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1393
+ )
1394
+
1395
+ if out_gif is not None and os.path.exists(out_gif):
1396
+
1397
+ geemap.reduce_gif_size(out_gif)
1398
+
1399
+ empty_text.text(
1400
+ "Right click the GIF to save it to your computer👇"
1401
+ )
1402
+ empty_image.image(out_gif)
1403
+
1404
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1405
+ if mp4 and os.path.exists(out_mp4):
1406
+ with empty_video:
1407
+ st.text(
1408
+ "Right click the MP4 to save it to your computer👇"
1409
+ )
1410
+ st.video(out_gif.replace(".gif", ".mp4"))
1411
+
1412
+ else:
1413
+ st.error(
1414
+ "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1415
+ )
1416
+
1417
+ elif collection == "USDA National Agriculture Imagery Program (NAIP)":
1418
+
1419
+ with st.form("submit_naip_form"):
1420
+ with st.expander("Customize timelapse"):
1421
+
1422
+ title = st.text_input(
1423
+ "Enter a title to show on the timelapse: ", "NAIP Timelapse"
1424
+ )
1425
+
1426
+ years = st.slider(
1427
+ "Start and end year:",
1428
+ 2003,
1429
+ today.year,
1430
+ (2003, today.year),
1431
+ )
1432
+
1433
+ bands = st.selectbox(
1434
+ "Select a band combination:", ["N/R/G", "R/G/B"], index=0
1435
+ )
1436
+
1437
+ speed = st.slider("Frames per second:", 1, 30, 3)
1438
+ add_progress_bar = st.checkbox("Add a progress bar", True)
1439
+ progress_bar_color = st.color_picker(
1440
+ "Progress bar color:", "#0000ff"
1441
+ )
1442
+ font_size = st.slider("Font size:", 10, 50, 30)
1443
+ font_color = st.color_picker("Font color:", "#ffffff")
1444
+ font_type = st.selectbox(
1445
+ "Select the font type for the title:",
1446
+ ["arial.ttf", "alibaba.otf"],
1447
+ index=0,
1448
+ )
1449
+ fading = st.slider(
1450
+ "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1451
+ )
1452
+ mp4 = st.checkbox("Save timelapse as MP4", True)
1453
+
1454
+ empty_text = st.empty()
1455
+ empty_image = st.empty()
1456
+ empty_video = st.container()
1457
+ empty_fire_image = st.empty()
1458
+
1459
+ roi = None
1460
+ if st.session_state.get("roi") is not None:
1461
+ roi = st.session_state.get("roi")
1462
+ out_gif = geemap.temp_file_path(".gif")
1463
+
1464
+ submitted = st.form_submit_button("Submit")
1465
+ if submitted:
1466
+
1467
+ if sample_roi == "Uploaded GeoJSON" and data is None:
1468
+ empty_text.warning(
1469
+ "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."
1470
+ )
1471
+ else:
1472
+
1473
+ empty_text.text("Computing... Please wait...")
1474
+ try:
1475
+ geemap.naip_timelapse(
1476
+ roi,
1477
+ years[0],
1478
+ years[1],
1479
+ out_gif,
1480
+ bands=bands.split("/"),
1481
+ palette=st.session_state.get("palette"),
1482
+ vis_params=None,
1483
+ dimensions=768,
1484
+ frames_per_second=speed,
1485
+ crs="EPSG:3857",
1486
+ overlay_data=overlay_data,
1487
+ overlay_color=overlay_color,
1488
+ overlay_width=overlay_width,
1489
+ overlay_opacity=overlay_opacity,
1490
+ title=title,
1491
+ title_xy=("2%", "90%"),
1492
+ add_text=True,
1493
+ text_xy=("2%", "2%"),
1494
+ text_sequence=None,
1495
+ font_type=font_type,
1496
+ font_size=font_size,
1497
+ font_color=font_color,
1498
+ add_progress_bar=add_progress_bar,
1499
+ progress_bar_color=progress_bar_color,
1500
+ progress_bar_height=5,
1501
+ loop=0,
1502
+ mp4=mp4,
1503
+ fading=fading,
1504
+ )
1505
+ except:
1506
+ empty_text.error(
1507
+ "Something went wrong. You either requested too much data or the ROI is outside the U.S."
1508
+ )
1509
+
1510
+ if out_gif is not None and os.path.exists(out_gif):
1511
+
1512
+ empty_text.text(
1513
+ "Right click the GIF to save it to your computer👇"
1514
+ )
1515
+ empty_image.image(out_gif)
1516
+
1517
+ out_mp4 = out_gif.replace(".gif", ".mp4")
1518
+ if mp4 and os.path.exists(out_mp4):
1519
+ with empty_video:
1520
+ st.text(
1521
+ "Right click the MP4 to save it to your computer👇"
1522
+ )
1523
+ st.video(out_gif.replace(".gif", ".mp4"))
1524
+
1525
+ else:
1526
+ st.error(
1527
+ "Something went wrong. You either requested too much data or the ROI is outside the U.S."
1528
+ )
1529
+
1530
+
1531
+ try:
1532
+ app()
1533
+ except Exception as e:
1534
+ pass
y/__pycache__/Interactive_Map.cpython-312.pyc ADDED
Binary file (11.6 kB). View file
 
y/__pycache__/Timelapse.cpython-312.pyc ADDED
Binary file (50.7 kB). View file
 
y/custom.js ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener("DOMContentLoaded", function () {
2
+ // Add a fade-in effect to elements with class "fade-in"
3
+ const elements = document.querySelectorAll(".fade-in");
4
+ elements.forEach(function (element) {
5
+ element.classList.add("fade");
6
+ element.style.opacity = 0;
7
+ element.addEventListener("transitionend", function () {
8
+ element.style.opacity = 1;
9
+ });
10
+ });
11
+
12
+ // Handle form submission when the "Submit" button is clicked
13
+ const submitButton = document.getElementById("submitButton");
14
+ submitButton.addEventListener("click", function (event) {
15
+ // Prevent the default form submission
16
+ event.preventDefault();
17
+
18
+ // Trigger the form submission
19
+ const form = document.getElementById("dataForm");
20
+ form.submit();
21
+ });
22
+ });
y/db.sqlite3 ADDED
Binary file (131 kB). View file
 
y/djangoGEE/__init__.py ADDED
File without changes
y/djangoGEE/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (180 Bytes). View file
 
y/djangoGEE/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (141 Bytes). View file
 
y/djangoGEE/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (175 Bytes). View file
 
y/djangoGEE/__pycache__/settings.cpython-311.pyc ADDED
Binary file (3.11 kB). View file
 
y/djangoGEE/__pycache__/settings.cpython-312.pyc ADDED
Binary file (3.03 kB). View file
 
y/djangoGEE/__pycache__/settings.cpython-39.pyc ADDED
Binary file (2.49 kB). View file
 
y/djangoGEE/__pycache__/urls.cpython-311.pyc ADDED
Binary file (2.97 kB). View file
 
y/djangoGEE/__pycache__/urls.cpython-312.pyc ADDED
Binary file (2.8 kB). View file
 
y/djangoGEE/__pycache__/urls.cpython-39.pyc ADDED
Binary file (1.9 kB). View file
 
y/djangoGEE/__pycache__/wsgi.cpython-311.pyc ADDED
Binary file (706 Bytes). View file
 
y/djangoGEE/__pycache__/wsgi.cpython-312.pyc ADDED
Binary file (633 Bytes). View file
 
y/djangoGEE/__pycache__/wsgi.cpython-39.pyc ADDED
Binary file (582 Bytes). View file
 
y/djangoGEE/geoApp/__init__.py ADDED
File without changes
y/djangoGEE/geoApp/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (130 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (140 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/admin.cpython-310.pyc ADDED
Binary file (171 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/admin.cpython-39.pyc ADDED
Binary file (181 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/apps.cpython-310.pyc ADDED
Binary file (409 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/apps.cpython-39.pyc ADDED
Binary file (417 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/models.cpython-310.pyc ADDED
Binary file (168 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/models.cpython-39.pyc ADDED
Binary file (178 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/urls.cpython-310.pyc ADDED
Binary file (307 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/urls.cpython-39.pyc ADDED
Binary file (317 Bytes). View file
 
y/djangoGEE/geoApp/__pycache__/views.cpython-310.pyc ADDED
Binary file (2.21 kB). View file
 
y/djangoGEE/geoApp/__pycache__/views.cpython-39.pyc ADDED
Binary file (1.63 kB). View file
 
y/djangoGEE/geoApp/admin.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from django.contrib import admin
2
+
3
+ # Register your models here.
y/djangoGEE/geoApp/apps.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class GeoappConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "geoApp"
y/djangoGEE/geoApp/geoApp/__init__.py ADDED
File without changes
y/djangoGEE/geoApp/geoApp/admin.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from django.contrib import admin
2
+
3
+ # Register your models here.
y/djangoGEE/geoApp/geoApp/apps.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class GeoappConfig(AppConfig):
5
+ default_auto_field = "django.db.models.BigAutoField"
6
+ name = "geoApp"
y/djangoGEE/geoApp/geoApp/migrations/__init__.py ADDED
File without changes
y/djangoGEE/geoApp/geoApp/models.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from django.db import models
2
+
3
+ # Create your models here.
y/djangoGEE/geoApp/geoApp/tests.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from django.test import TestCase
2
+
3
+ # Create your tests here.
y/djangoGEE/geoApp/geoApp/views.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from django.shortcuts import render
2
+
3
+ # Create your views here.
y/djangoGEE/geoApp/manage.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """Django's command-line utility for administrative tasks."""
3
+ import os
4
+ import sys
5
+
6
+
7
+ def main():
8
+ """Run administrative tasks."""
9
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "geo.settings")
10
+ try:
11
+ from django.core.management import execute_from_command_line
12
+ except ImportError as exc:
13
+ raise ImportError(
14
+ "Couldn't import Django. Are you sure it's installed and "
15
+ "available on your PYTHONPATH environment variable? Did you "
16
+ "forget to activate a virtual environment?"
17
+ ) from exc
18
+ execute_from_command_line(sys.argv)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ main()
y/djangoGEE/geoApp/migrations/__init__.py ADDED
File without changes
y/djangoGEE/geoApp/migrations/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (141 Bytes). View file
 
y/djangoGEE/geoApp/migrations/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (151 Bytes). View file