Yunus Serhat Bıçakçı commited on
Commit
ad5fbfa
·
1 Parent(s): b9f1929
pages/10_🌍_Earth_Engine_Datasets.py DELETED
@@ -1,157 +0,0 @@
1
- import ee
2
- import streamlit as st
3
- import geemap.foliumap as geemap
4
-
5
- st.set_page_config(layout="wide")
6
-
7
- st.sidebar.info(
8
- """
9
- - Web App URL: <https://streamlit.gishub.org>
10
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
11
- """
12
- )
13
-
14
- st.sidebar.title("Contact")
15
- st.sidebar.info(
16
- """
17
- 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)
18
- """
19
- )
20
-
21
-
22
- def nlcd():
23
-
24
- # st.header("National Land Cover Database (NLCD)")
25
-
26
- row1_col1, row1_col2 = st.columns([3, 1])
27
- width = 950
28
- height = 600
29
-
30
- Map = geemap.Map(center=[40, -100], zoom=4)
31
-
32
- # Select the seven NLCD epoches after 2000.
33
- years = ["2001", "2004", "2006", "2008", "2011", "2013", "2016", "2019"]
34
-
35
- # Get an NLCD image by year.
36
- def getNLCD(year):
37
- # Import the NLCD collection.
38
- dataset = ee.ImageCollection("USGS/NLCD_RELEASES/2019_REL/NLCD")
39
-
40
- # Filter the collection by year.
41
- nlcd = dataset.filter(ee.Filter.eq("system:index", year)).first()
42
-
43
- # Select the land cover band.
44
- landcover = nlcd.select("landcover")
45
- return landcover
46
-
47
- with row1_col2:
48
- selected_year = st.multiselect("Select a year", years)
49
- add_legend = st.checkbox("Show legend")
50
-
51
- if selected_year:
52
- for year in selected_year:
53
- Map.addLayer(getNLCD(year), {}, "NLCD " + year)
54
-
55
- if add_legend:
56
- Map.add_legend(
57
- legend_title="NLCD Land Cover Classification", builtin_legend="NLCD"
58
- )
59
- with row1_col1:
60
- Map.to_streamlit(width=width, height=height)
61
-
62
- else:
63
- with row1_col1:
64
- Map.to_streamlit(width=width, height=height)
65
-
66
-
67
- def search_data():
68
-
69
- # st.header("Search Earth Engine Data Catalog")
70
-
71
- Map = geemap.Map()
72
-
73
- if "ee_assets" not in st.session_state:
74
- st.session_state["ee_assets"] = None
75
- if "asset_titles" not in st.session_state:
76
- st.session_state["asset_titles"] = None
77
-
78
- col1, col2 = st.columns([2, 1])
79
-
80
- dataset = None
81
- with col2:
82
- keyword = st.text_input(
83
- "Enter a keyword to search (e.g., elevation)", "")
84
- if keyword:
85
- ee_assets = geemap.search_ee_data(keyword)
86
- asset_titles = [x["title"] for x in ee_assets]
87
- asset_types = [x["type"] for x in ee_assets]
88
-
89
- translate = {
90
- "image_collection": "ee.ImageCollection('",
91
- "image": "ee.Image('",
92
- "table": "ee.FeatureCollection('",
93
- "table_collection": "ee.FeatureCollection('",
94
- }
95
-
96
- dataset = st.selectbox("Select a dataset", asset_titles)
97
- if len(ee_assets) > 0:
98
- st.session_state["ee_assets"] = ee_assets
99
- st.session_state["asset_titles"] = asset_titles
100
-
101
- if dataset is not None:
102
- with st.expander("Show dataset details", True):
103
- index = asset_titles.index(dataset)
104
-
105
- html = geemap.ee_data_html(
106
- st.session_state["ee_assets"][index])
107
- html = html.replace("\n", "")
108
- st.markdown(html, True)
109
-
110
- ee_id = ee_assets[index]["id"]
111
- uid = ee_assets[index]["uid"]
112
- st.markdown(f"""**Earth Engine Snippet:** `{ee_id}`""")
113
- ee_asset = f"{translate[asset_types[index]]}{ee_id}')"
114
- vis_params = st.text_input(
115
- "Enter visualization parameters as a dictionary", {}
116
- )
117
- layer_name = st.text_input("Enter a layer name", uid)
118
- button = st.button("Add dataset to map")
119
- if button:
120
- vis = {}
121
- try:
122
- if vis_params.strip() == "":
123
- # st.error("Please enter visualization parameters")
124
- vis_params = "{}"
125
- vis = eval(vis_params)
126
- if not isinstance(vis, dict):
127
- st.error(
128
- "Visualization parameters must be a dictionary")
129
- try:
130
- Map.addLayer(eval(ee_asset), vis, layer_name)
131
- except Exception as e:
132
- st.error(f"Error adding layer: {e}")
133
- except Exception as e:
134
- st.error(f"Invalid visualization parameters: {e}")
135
-
136
- with col1:
137
- Map.to_streamlit()
138
- else:
139
- with col1:
140
- Map.to_streamlit()
141
-
142
-
143
- def app():
144
- st.title("Earth Engine Data Catalog")
145
-
146
- apps = ["Search Earth Engine Data Catalog",
147
- "National Land Cover Database (NLCD)"]
148
-
149
- selected_app = st.selectbox("Select an app", apps)
150
-
151
- if selected_app == "National Land Cover Database (NLCD)":
152
- nlcd()
153
- elif selected_app == "Search Earth Engine Data Catalog":
154
- search_data()
155
-
156
-
157
- app()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/11_🧱_Ordnance_Survey.py DELETED
@@ -1,108 +0,0 @@
1
- import folium
2
- import pandas as pd
3
- import streamlit as st
4
- import leafmap.foliumap as leafmap
5
- import folium.plugins as plugins
6
-
7
- st.set_page_config(layout="wide")
8
-
9
- st.sidebar.info(
10
- """
11
- - Web App URL: <https://streamlit.gishub.org>
12
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
13
- """
14
- )
15
-
16
- st.sidebar.title("Contact")
17
- st.sidebar.info(
18
- """
19
- 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)
20
- """
21
- )
22
-
23
- st.title("National Library of Scotland XYZ Layers")
24
- df = pd.read_csv("data/scotland_xyz.tsv", sep="\t")
25
- basemaps = leafmap.basemaps
26
- names = df["Name"].values.tolist() + list(basemaps.keys())
27
- links = df["URL"].values.tolist() + list(basemaps.values())
28
-
29
- col1, col2, col3, col4, col5, col6, col7 = st.columns([3, 3, 1, 1, 1, 1.5, 1.5])
30
- with col1:
31
- left_name = st.selectbox(
32
- "Select the left layer",
33
- names,
34
- index=names.index("Great Britain - Bartholomew Half Inch, 1897-1907"),
35
- )
36
-
37
- with col2:
38
- right_name = st.selectbox(
39
- "Select the right layer",
40
- names,
41
- index=names.index("HYBRID"),
42
- )
43
-
44
- with col3:
45
- # lat = st.slider('Latitude', -90.0, 90.0, 55.68, step=0.01)
46
- lat = st.text_input("Latitude", " 55.68")
47
-
48
- with col4:
49
- # lon = st.slider('Longitude', -180.0, 180.0, -2.98, step=0.01)
50
- lon = st.text_input("Longitude", "-2.98")
51
-
52
- with col5:
53
- # zoom = st.slider('Zoom', 1, 24, 6, step=1)
54
- zoom = st.text_input("Zoom", "6")
55
-
56
- with col6:
57
- checkbox = st.checkbox("Add OS 25 inch")
58
-
59
- # with col7:
60
- with st.expander("Acknowledgements"):
61
- markdown = """
62
- The map tile access is by kind arrangement of the National Library of Scotland on the understanding that re-use is for personal purposes. They host most of the map layers except these:
63
- - The Roy Maps are owned by the British Library.
64
- - The Great Britain – OS maps 1:25,000, 1937-61 and One Inch 7th series, 1955-61 are hosted by MapTiler.
65
-
66
- If you wish you use these layers within a website, or for a commercial or public purpose, please view the [National Library of Scotland Historic Maps Subscription API](https://maps.nls.uk/projects/subscription-api/) or contact them at [email protected].
67
- """
68
- st.markdown(markdown, unsafe_allow_html=True)
69
-
70
- m = leafmap.Map(
71
- center=[float(lat), float(lon)],
72
- zoom=int(zoom),
73
- locate_control=True,
74
- draw_control=False,
75
- measure_control=False,
76
- )
77
- measure = plugins.MeasureControl(position="bottomleft", active_color="orange")
78
- measure.add_to(m)
79
-
80
- if left_name in basemaps:
81
- left_layer = basemaps[left_name]
82
- else:
83
- left_layer = folium.TileLayer(
84
- tiles=links[names.index(left_name)],
85
- name=left_name,
86
- attr="National Library of Scotland",
87
- overlay=True,
88
- )
89
-
90
- if right_name in basemaps:
91
- right_layer = basemaps[right_name]
92
- else:
93
- right_layer = folium.TileLayer(
94
- tiles=links[names.index(right_name)],
95
- name=right_name,
96
- attr="National Library of Scotland",
97
- overlay=True,
98
- )
99
-
100
- if checkbox:
101
- for index, name in enumerate(names):
102
- if "OS 25 inch" in name:
103
- m.add_tile_layer(
104
- links[index], name, attribution="National Library of Scotland"
105
- )
106
-
107
- m.split_map(left_layer, right_layer)
108
- m.to_streamlit(height=600)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/12_🌲_Land_Cover_Mapping.py DELETED
@@ -1,111 +0,0 @@
1
- import datetime
2
- import ee
3
- import streamlit as st
4
- import geemap.foliumap as geemap
5
-
6
- st.set_page_config(layout="wide")
7
-
8
- st.sidebar.info(
9
- """
10
- - Web App URL: <https://streamlit.gishub.org>
11
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
12
- """
13
- )
14
-
15
- st.sidebar.title("Contact")
16
- st.sidebar.info(
17
- """
18
- 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)
19
- """
20
- )
21
-
22
- st.title("Comparing Global Land Cover Maps")
23
-
24
- col1, col2 = st.columns([4, 1])
25
-
26
- Map = geemap.Map()
27
- Map.add_basemap("ESA WorldCover 2020 S2 FCC")
28
- Map.add_basemap("ESA WorldCover 2020 S2 TCC")
29
- Map.add_basemap("HYBRID")
30
-
31
- esa = ee.ImageCollection("ESA/WorldCover/v100").first()
32
- esa_vis = {"bands": ["Map"]}
33
-
34
-
35
- esri = ee.ImageCollection(
36
- "projects/sat-io/open-datasets/landcover/ESRI_Global-LULC_10m"
37
- ).mosaic()
38
- esri_vis = {
39
- "min": 1,
40
- "max": 10,
41
- "palette": [
42
- "#1A5BAB",
43
- "#358221",
44
- "#A7D282",
45
- "#87D19E",
46
- "#FFDB5C",
47
- "#EECFA8",
48
- "#ED022A",
49
- "#EDE9E4",
50
- "#F2FAFF",
51
- "#C8C8C8",
52
- ],
53
- }
54
-
55
-
56
- markdown = """
57
- - [Dynamic World Land Cover](https://developers.google.com/earth-engine/datasets/catalog/GOOGLE_DYNAMICWORLD_V1?hl=en)
58
- - [ESA Global Land Cover](https://developers.google.com/earth-engine/datasets/catalog/ESA_WorldCover_v100)
59
- - [ESRI Global Land Cover](https://samapriya.github.io/awesome-gee-community-datasets/projects/esrilc2020)
60
-
61
- """
62
-
63
- with col2:
64
-
65
- longitude = st.number_input("Longitude", -180.0, 180.0, -89.3998)
66
- latitude = st.number_input("Latitude", -90.0, 90.0, 43.0886)
67
- zoom = st.number_input("Zoom", 0, 20, 11)
68
-
69
- Map.setCenter(longitude, latitude, zoom)
70
-
71
- start = st.date_input("Start Date for Dynamic World", datetime.date(2020, 1, 1))
72
- end = st.date_input("End Date for Dynamic World", datetime.date(2021, 1, 1))
73
-
74
- start_date = start.strftime("%Y-%m-%d")
75
- end_date = end.strftime("%Y-%m-%d")
76
-
77
- region = ee.Geometry.BBox(-179, -89, 179, 89)
78
- dw = geemap.dynamic_world(region, start_date, end_date, return_type="hillshade")
79
-
80
- layers = {
81
- "Dynamic World": geemap.ee_tile_layer(dw, {}, "Dynamic World Land Cover"),
82
- "ESA Land Cover": geemap.ee_tile_layer(esa, esa_vis, "ESA Land Cover"),
83
- "ESRI Land Cover": geemap.ee_tile_layer(esri, esri_vis, "ESRI Land Cover"),
84
- }
85
-
86
- options = list(layers.keys())
87
- left = st.selectbox("Select a left layer", options, index=1)
88
- right = st.selectbox("Select a right layer", options, index=0)
89
-
90
- left_layer = layers[left]
91
- right_layer = layers[right]
92
-
93
- Map.split_map(left_layer, right_layer)
94
-
95
- legend = st.selectbox("Select a legend", options, index=options.index(right))
96
- if legend == "Dynamic World":
97
- Map.add_legend(
98
- title="Dynamic World Land Cover",
99
- builtin_legend="Dynamic_World",
100
- )
101
- elif legend == "ESA Land Cover":
102
- Map.add_legend(title="ESA Land Cover", builtin_legend="ESA_WorldCover")
103
- elif legend == "ESRI Land Cover":
104
- Map.add_legend(title="ESRI Land Cover", builtin_legend="ESRI_LandCover")
105
-
106
- with st.expander("Data sources"):
107
- st.markdown(markdown)
108
-
109
-
110
- with col1:
111
- Map.to_streamlit(height=750)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/13_🏘️_Global_Building_Footprints.py DELETED
@@ -1,111 +0,0 @@
1
- import ee
2
- import geemap.foliumap as geemap
3
- import geopandas as gpd
4
- import streamlit as st
5
-
6
- st.set_page_config(layout="wide")
7
-
8
-
9
- @st.cache(persist=True)
10
- def ee_authenticate(token_name="EARTHENGINE_TOKEN"):
11
- geemap.ee_initialize(token_name=token_name)
12
-
13
-
14
- st.sidebar.info(
15
- """
16
- - Web App URL: <https://streamlit.gishub.org>
17
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
18
- """
19
- )
20
-
21
- st.sidebar.title("Contact")
22
- st.sidebar.info(
23
- """
24
- 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)
25
- """
26
- )
27
-
28
- st.title("Global Building Footprints")
29
-
30
- col1, col2 = st.columns([8, 2])
31
-
32
-
33
- @st.cache(allow_output_mutation=True)
34
- def read_data(url):
35
- return gpd.read_file(url)
36
-
37
-
38
- countries = 'https://github.com/giswqs/geemap/raw/master/examples/data/countries.geojson'
39
- states = 'https://github.com/giswqs/geemap/raw/master/examples/data/us_states.json'
40
-
41
- countries_gdf = read_data(countries)
42
- states_gdf = read_data(states)
43
-
44
- country_names = countries_gdf['NAME'].values.tolist()
45
- country_names.remove('United States of America')
46
- country_names.append('USA')
47
- country_names.sort()
48
- country_names = [name.replace('.', '').replace(' ', '_')
49
- for name in country_names]
50
-
51
- state_names = states_gdf['name'].values.tolist()
52
-
53
- basemaps = list(geemap.basemaps)
54
-
55
- Map = geemap.Map()
56
-
57
- with col2:
58
-
59
- basemap = st.selectbox("Select a basemap", basemaps,
60
- index=basemaps.index('HYBRID'))
61
- Map.add_basemap(basemap)
62
-
63
- country = st.selectbox('Select a country', country_names,
64
- index=country_names.index('USA'))
65
-
66
- if country == 'USA':
67
- state = st.selectbox('Select a state', state_names,
68
- index=state_names.index('Florida'))
69
- layer_name = state
70
-
71
- try:
72
- fc = ee.FeatureCollection(
73
- f'projects/sat-io/open-datasets/MSBuildings/US/{state}')
74
- except:
75
- st.error('No data available for the selected state.')
76
-
77
- else:
78
- try:
79
- fc = ee.FeatureCollection(
80
- f'projects/sat-io/open-datasets/MSBuildings/{country}')
81
- except:
82
- st.error('No data available for the selected country.')
83
-
84
- layer_name = country
85
-
86
- color = st.color_picker('Select a color', '#FF5500')
87
-
88
- style = {'fillColor': '00000000', 'color': color}
89
-
90
- split = st.checkbox("Split-panel map")
91
-
92
- if split:
93
- left = geemap.ee_tile_layer(fc.style(**style), {}, 'Left')
94
- right = left
95
- Map.split_map(left, right)
96
- else:
97
- Map.addLayer(fc.style(**style), {}, layer_name)
98
-
99
- Map.centerObject(fc.first(), zoom=16)
100
-
101
- with st.expander("Data Sources"):
102
- st.info(
103
- """
104
- [Microsoft Building Footprints](https://gee-community-catalog.org/projects/msbuildings/)
105
- """
106
- )
107
-
108
-
109
- with col1:
110
-
111
- Map.to_streamlit(height=1000)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/{5_📍_Marker_Cluster.py → 1_📍_Marker_Cluster.py} RENAMED
@@ -5,15 +5,15 @@ st.set_page_config(layout="wide")
5
 
6
  st.sidebar.info(
7
  """
8
- - Web App URL: <https://streamlit.gishub.org>
9
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
10
  """
11
  )
12
 
13
  st.sidebar.title("Contact")
14
  st.sidebar.info(
15
  """
16
- 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)
17
  """
18
  )
19
 
 
5
 
6
  st.sidebar.info(
7
  """
8
+ - Web App URL: <https://huggingface.co/spaces/yunusserhat/Crime-Map>
9
+ - HuggingFace repository: <https://huggingface.co/spaces/yunusserhat/Crime-Map/tree/main>
10
  """
11
  )
12
 
13
  st.sidebar.title("Contact")
14
  st.sidebar.info(
15
  """
16
+ Yunus Serhat Bıçakçı at [yunusserhat.com](https://yunusserhat.com) | [GitHub](https://github.com/yunusserhat) | [Twitter](https://twitter.com/yunusserhat) | [LinkedIn](https://www.linkedin.com/in/yunusserhat)
17
  """
18
  )
19
 
pages/1_📷_Timelapse.py DELETED
@@ -1,1527 +0,0 @@
1
- import ee
2
- import os
3
- import warnings
4
- import datetime
5
- import fiona
6
- import geopandas as gpd
7
- import folium
8
- import streamlit as st
9
- import geemap.colormaps as cm
10
- import geemap.foliumap as geemap
11
- from datetime import date
12
- from shapely.geometry import Polygon
13
-
14
- st.set_page_config(layout="wide")
15
- warnings.filterwarnings("ignore")
16
-
17
-
18
- @st.cache(allow_output_mutation=True)
19
- def ee_authenticate(token_name="EARTHENGINE_TOKEN"):
20
- geemap.ee_initialize(token_name=token_name)
21
-
22
-
23
- st.sidebar.info(
24
- """
25
- - Web App URL: <https://streamlit.gishub.org>
26
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
27
- """
28
- )
29
-
30
- st.sidebar.title("Contact")
31
- st.sidebar.info(
32
- """
33
- Qiusheng Wu at [wetlands.io](https://wetlands.io) | [GitHub](https://github.com/giswqs) | [Twitter](https://twitter.com/giswqs) | [YouTube](https://www.youtube.com/c/QiushengWu) | [LinkedIn](https://www.linkedin.com/in/qiushengwu)
34
- """
35
- )
36
-
37
- goes_rois = {
38
- "Creek Fire, CA (2020-09-05)": {
39
- "region": Polygon(
40
- [
41
- [-121.003418, 36.848857],
42
- [-121.003418, 39.049052],
43
- [-117.905273, 39.049052],
44
- [-117.905273, 36.848857],
45
- [-121.003418, 36.848857],
46
- ]
47
- ),
48
- "start_time": "2020-09-05T15:00:00",
49
- "end_time": "2020-09-06T02:00:00",
50
- },
51
- "Bomb Cyclone (2021-10-24)": {
52
- "region": Polygon(
53
- [
54
- [-159.5954, 60.4088],
55
- [-159.5954, 24.5178],
56
- [-114.2438, 24.5178],
57
- [-114.2438, 60.4088],
58
- ]
59
- ),
60
- "start_time": "2021-10-24T14:00:00",
61
- "end_time": "2021-10-25T01:00:00",
62
- },
63
- "Hunga Tonga Volcanic Eruption (2022-01-15)": {
64
- "region": Polygon(
65
- [
66
- [-192.480469, -32.546813],
67
- [-192.480469, -8.754795],
68
- [-157.587891, -8.754795],
69
- [-157.587891, -32.546813],
70
- [-192.480469, -32.546813],
71
- ]
72
- ),
73
- "start_time": "2022-01-15T03:00:00",
74
- "end_time": "2022-01-15T07:00:00",
75
- },
76
- "Hunga Tonga Volcanic Eruption Closer Look (2022-01-15)": {
77
- "region": Polygon(
78
- [
79
- [-178.901367, -22.958393],
80
- [-178.901367, -17.85329],
81
- [-171.452637, -17.85329],
82
- [-171.452637, -22.958393],
83
- [-178.901367, -22.958393],
84
- ]
85
- ),
86
- "start_time": "2022-01-15T03:00:00",
87
- "end_time": "2022-01-15T07:00:00",
88
- },
89
- }
90
-
91
-
92
- landsat_rois = {
93
- "Aral Sea": Polygon(
94
- [
95
- [57.667236, 43.834527],
96
- [57.667236, 45.996962],
97
- [61.12793, 45.996962],
98
- [61.12793, 43.834527],
99
- [57.667236, 43.834527],
100
- ]
101
- ),
102
- "Dubai": Polygon(
103
- [
104
- [54.541626, 24.763044],
105
- [54.541626, 25.427152],
106
- [55.632019, 25.427152],
107
- [55.632019, 24.763044],
108
- [54.541626, 24.763044],
109
- ]
110
- ),
111
- "Hong Kong International Airport": Polygon(
112
- [
113
- [113.825226, 22.198849],
114
- [113.825226, 22.349758],
115
- [114.085121, 22.349758],
116
- [114.085121, 22.198849],
117
- [113.825226, 22.198849],
118
- ]
119
- ),
120
- "Las Vegas, NV": Polygon(
121
- [
122
- [-115.554199, 35.804449],
123
- [-115.554199, 36.558188],
124
- [-113.903503, 36.558188],
125
- [-113.903503, 35.804449],
126
- [-115.554199, 35.804449],
127
- ]
128
- ),
129
- "Pucallpa, Peru": Polygon(
130
- [
131
- [-74.672699, -8.600032],
132
- [-74.672699, -8.254983],
133
- [-74.279938, -8.254983],
134
- [-74.279938, -8.600032],
135
- ]
136
- ),
137
- "Sierra Gorda, Chile": Polygon(
138
- [
139
- [-69.315491, -22.837104],
140
- [-69.315491, -22.751488],
141
- [-69.190006, -22.751488],
142
- [-69.190006, -22.837104],
143
- [-69.315491, -22.837104],
144
- ]
145
- ),
146
- }
147
-
148
- modis_rois = {
149
- "World": Polygon(
150
- [
151
- [-171.210938, -57.136239],
152
- [-171.210938, 79.997168],
153
- [177.539063, 79.997168],
154
- [177.539063, -57.136239],
155
- [-171.210938, -57.136239],
156
- ]
157
- ),
158
- "Africa": Polygon(
159
- [
160
- [-18.6983, 38.1446],
161
- [-18.6983, -36.1630],
162
- [52.2293, -36.1630],
163
- [52.2293, 38.1446],
164
- ]
165
- ),
166
- "USA": Polygon(
167
- [
168
- [-127.177734, 23.725012],
169
- [-127.177734, 50.792047],
170
- [-66.269531, 50.792047],
171
- [-66.269531, 23.725012],
172
- [-127.177734, 23.725012],
173
- ]
174
- ),
175
- }
176
-
177
- ocean_rois = {
178
- "Gulf of Mexico": Polygon(
179
- [
180
- [-101.206055, 15.496032],
181
- [-101.206055, 32.361403],
182
- [-75.673828, 32.361403],
183
- [-75.673828, 15.496032],
184
- [-101.206055, 15.496032],
185
- ]
186
- ),
187
- "North Atlantic Ocean": Polygon(
188
- [
189
- [-85.341797, 24.046464],
190
- [-85.341797, 45.02695],
191
- [-55.810547, 45.02695],
192
- [-55.810547, 24.046464],
193
- [-85.341797, 24.046464],
194
- ]
195
- ),
196
- "World": Polygon(
197
- [
198
- [-171.210938, -57.136239],
199
- [-171.210938, 79.997168],
200
- [177.539063, 79.997168],
201
- [177.539063, -57.136239],
202
- [-171.210938, -57.136239],
203
- ]
204
- ),
205
- }
206
-
207
-
208
- @st.cache(allow_output_mutation=True)
209
- def uploaded_file_to_gdf(data):
210
- import tempfile
211
- import os
212
- import uuid
213
-
214
- _, file_extension = os.path.splitext(data.name)
215
- file_id = str(uuid.uuid4())
216
- file_path = os.path.join(tempfile.gettempdir(), f"{file_id}{file_extension}")
217
-
218
- with open(file_path, "wb") as file:
219
- file.write(data.getbuffer())
220
-
221
- if file_path.lower().endswith(".kml"):
222
- fiona.drvsupport.supported_drivers["KML"] = "rw"
223
- gdf = gpd.read_file(file_path, driver="KML")
224
- else:
225
- gdf = gpd.read_file(file_path)
226
-
227
- return gdf
228
-
229
-
230
- def app():
231
-
232
- today = date.today()
233
-
234
- st.title("Create Satellite Timelapse")
235
-
236
- st.markdown(
237
- """
238
- An interactive web app for creating [Landsat](https://developers.google.com/earth-engine/datasets/catalog/landsat)/[GOES](https://jstnbraaten.medium.com/goes-in-earth-engine-53fbc8783c16) timelapse for any location around the globe.
239
- The app was built using [streamlit](https://streamlit.io), [geemap](https://geemap.org), and [Google Earth Engine](https://earthengine.google.com). For more info, check out my streamlit [blog post](https://blog.streamlit.io/creating-satellite-timelapse-with-streamlit-and-earth-engine).
240
- """
241
- )
242
-
243
- row1_col1, row1_col2 = st.columns([2, 1])
244
-
245
- if st.session_state.get("zoom_level") is None:
246
- st.session_state["zoom_level"] = 4
247
-
248
- st.session_state["ee_asset_id"] = None
249
- st.session_state["bands"] = None
250
- st.session_state["palette"] = None
251
- st.session_state["vis_params"] = None
252
-
253
- with row1_col1:
254
- ee_authenticate(token_name="EARTHENGINE_TOKEN")
255
- m = geemap.Map(
256
- basemap="HYBRID",
257
- plugin_Draw=True,
258
- Draw_export=True,
259
- locate_control=True,
260
- plugin_LatLngPopup=False,
261
- )
262
- m.add_basemap("ROADMAP")
263
-
264
- with row1_col2:
265
-
266
- keyword = st.text_input("Search for a location:", "")
267
- if keyword:
268
- locations = geemap.geocode(keyword)
269
- if locations is not None and len(locations) > 0:
270
- str_locations = [str(g)[1:-1] for g in locations]
271
- location = st.selectbox("Select a location:", str_locations)
272
- loc_index = str_locations.index(location)
273
- selected_loc = locations[loc_index]
274
- lat, lng = selected_loc.lat, selected_loc.lng
275
- folium.Marker(location=[lat, lng], popup=location).add_to(m)
276
- m.set_center(lng, lat, 12)
277
- st.session_state["zoom_level"] = 12
278
-
279
- collection = st.selectbox(
280
- "Select a satellite image collection: ",
281
- [
282
- "Any Earth Engine ImageCollection",
283
- "Landsat TM-ETM-OLI Surface Reflectance",
284
- "Sentinel-2 MSI Surface Reflectance",
285
- "Geostationary Operational Environmental Satellites (GOES)",
286
- "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
287
- "MODIS Gap filled Land Surface Temperature Daily",
288
- "MODIS Ocean Color SMI",
289
- "USDA National Agriculture Imagery Program (NAIP)",
290
- ],
291
- index=1,
292
- )
293
-
294
- if collection in [
295
- "Landsat TM-ETM-OLI Surface Reflectance",
296
- "Sentinel-2 MSI Surface Reflectance",
297
- ]:
298
- roi_options = ["Uploaded GeoJSON"] + list(landsat_rois.keys())
299
-
300
- elif collection == "Geostationary Operational Environmental Satellites (GOES)":
301
- roi_options = ["Uploaded GeoJSON"] + list(goes_rois.keys())
302
-
303
- elif collection in [
304
- "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
305
- "MODIS Gap filled Land Surface Temperature Daily",
306
- ]:
307
- roi_options = ["Uploaded GeoJSON"] + list(modis_rois.keys())
308
- elif collection == "MODIS Ocean Color SMI":
309
- roi_options = ["Uploaded GeoJSON"] + list(ocean_rois.keys())
310
- else:
311
- roi_options = ["Uploaded GeoJSON"]
312
-
313
- if collection == "Any Earth Engine ImageCollection":
314
- keyword = st.text_input("Enter a keyword to search (e.g., MODIS):", "")
315
- if keyword:
316
-
317
- assets = geemap.search_ee_data(keyword)
318
- ee_assets = []
319
- for asset in assets:
320
- if asset["ee_id_snippet"].startswith("ee.ImageCollection"):
321
- ee_assets.append(asset)
322
-
323
- asset_titles = [x["title"] for x in ee_assets]
324
- dataset = st.selectbox("Select a dataset:", asset_titles)
325
- if len(ee_assets) > 0:
326
- st.session_state["ee_assets"] = ee_assets
327
- st.session_state["asset_titles"] = asset_titles
328
- index = asset_titles.index(dataset)
329
- ee_id = ee_assets[index]["id"]
330
- else:
331
- ee_id = ""
332
-
333
- if dataset is not None:
334
- with st.expander("Show dataset details", False):
335
- index = asset_titles.index(dataset)
336
- html = geemap.ee_data_html(st.session_state["ee_assets"][index])
337
- st.markdown(html, True)
338
- # elif collection == "MODIS Gap filled Land Surface Temperature Daily":
339
- # ee_id = ""
340
- else:
341
- ee_id = ""
342
-
343
- asset_id = st.text_input("Enter an ee.ImageCollection asset ID:", ee_id)
344
-
345
- if asset_id:
346
- with st.expander("Customize band combination and color palette", True):
347
- try:
348
- col = ee.ImageCollection.load(asset_id)
349
- st.session_state["ee_asset_id"] = asset_id
350
- except:
351
- st.error("Invalid Earth Engine asset ID.")
352
- st.session_state["ee_asset_id"] = None
353
- return
354
-
355
- img_bands = col.first().bandNames().getInfo()
356
- if len(img_bands) >= 3:
357
- default_bands = img_bands[:3][::-1]
358
- else:
359
- default_bands = img_bands[:]
360
- bands = st.multiselect(
361
- "Select one or three bands (RGB):", img_bands, default_bands
362
- )
363
- st.session_state["bands"] = bands
364
-
365
- if len(bands) == 1:
366
- palette_options = st.selectbox(
367
- "Color palette",
368
- cm.list_colormaps(),
369
- index=2,
370
- )
371
- palette_values = cm.get_palette(palette_options, 15)
372
- palette = st.text_area(
373
- "Enter a custom palette:",
374
- palette_values,
375
- )
376
- st.write(
377
- cm.plot_colormap(cmap=palette_options, return_fig=True)
378
- )
379
- st.session_state["palette"] = eval(palette)
380
-
381
- if bands:
382
- vis_params = st.text_area(
383
- "Enter visualization parameters",
384
- "{'bands': ["
385
- + ", ".join([f"'{band}'" for band in bands])
386
- + "]}",
387
- )
388
- else:
389
- vis_params = st.text_area(
390
- "Enter visualization parameters",
391
- "{}",
392
- )
393
- try:
394
- st.session_state["vis_params"] = eval(vis_params)
395
- st.session_state["vis_params"]["palette"] = st.session_state[
396
- "palette"
397
- ]
398
- except Exception as e:
399
- st.session_state["vis_params"] = None
400
- st.error(
401
- f"Invalid visualization parameters. It must be a dictionary."
402
- )
403
-
404
- elif collection == "MODIS Gap filled Land Surface Temperature Daily":
405
- with st.expander("Show dataset details", False):
406
- st.markdown(
407
- """
408
- See the [Awesome GEE Community Datasets](https://samapriya.github.io/awesome-gee-community-datasets/projects/daily_lst/).
409
- """
410
- )
411
-
412
- MODIS_options = ["Daytime (1:30 pm)", "Nighttime (1:30 am)"]
413
- MODIS_option = st.selectbox("Select a MODIS dataset:", MODIS_options)
414
- if MODIS_option == "Daytime (1:30 pm)":
415
- st.session_state[
416
- "ee_asset_id"
417
- ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_day_1km"
418
- else:
419
- st.session_state[
420
- "ee_asset_id"
421
- ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_night_1km"
422
-
423
- palette_options = st.selectbox(
424
- "Color palette",
425
- cm.list_colormaps(),
426
- index=90,
427
- )
428
- palette_values = cm.get_palette(palette_options, 15)
429
- palette = st.text_area(
430
- "Enter a custom palette:",
431
- palette_values,
432
- )
433
- st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
434
- st.session_state["palette"] = eval(palette)
435
- elif collection == "MODIS Ocean Color SMI":
436
- with st.expander("Show dataset details", False):
437
- st.markdown(
438
- """
439
- See the [Earth Engine Data Catalog](https://developers.google.com/earth-engine/datasets/catalog/NASA_OCEANDATA_MODIS-Aqua_L3SMI).
440
- """
441
- )
442
-
443
- MODIS_options = ["Aqua", "Terra"]
444
- MODIS_option = st.selectbox("Select a satellite:", MODIS_options)
445
- st.session_state["ee_asset_id"] = MODIS_option
446
- # if MODIS_option == "Daytime (1:30 pm)":
447
- # st.session_state[
448
- # "ee_asset_id"
449
- # ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_day_1km"
450
- # else:
451
- # st.session_state[
452
- # "ee_asset_id"
453
- # ] = "projects/sat-io/open-datasets/gap-filled-lst/gf_night_1km"
454
-
455
- band_dict = {
456
- "Chlorophyll a concentration": "chlor_a",
457
- "Normalized fluorescence line height": "nflh",
458
- "Particulate organic carbon": "poc",
459
- "Sea surface temperature": "sst",
460
- "Remote sensing reflectance at band 412nm": "Rrs_412",
461
- "Remote sensing reflectance at band 443nm": "Rrs_443",
462
- "Remote sensing reflectance at band 469nm": "Rrs_469",
463
- "Remote sensing reflectance at band 488nm": "Rrs_488",
464
- "Remote sensing reflectance at band 531nm": "Rrs_531",
465
- "Remote sensing reflectance at band 547nm": "Rrs_547",
466
- "Remote sensing reflectance at band 555nm": "Rrs_555",
467
- "Remote sensing reflectance at band 645nm": "Rrs_645",
468
- "Remote sensing reflectance at band 667nm": "Rrs_667",
469
- "Remote sensing reflectance at band 678nm": "Rrs_678",
470
- }
471
-
472
- band_options = list(band_dict.keys())
473
- band = st.selectbox(
474
- "Select a band",
475
- band_options,
476
- band_options.index("Sea surface temperature"),
477
- )
478
- st.session_state["band"] = band_dict[band]
479
-
480
- colors = cm.list_colormaps()
481
- palette_options = st.selectbox(
482
- "Color palette",
483
- colors,
484
- index=colors.index("coolwarm"),
485
- )
486
- palette_values = cm.get_palette(palette_options, 15)
487
- palette = st.text_area(
488
- "Enter a custom palette:",
489
- palette_values,
490
- )
491
- st.write(cm.plot_colormap(cmap=palette_options, return_fig=True))
492
- st.session_state["palette"] = eval(palette)
493
-
494
- sample_roi = st.selectbox(
495
- "Select a sample ROI or upload a GeoJSON file:",
496
- roi_options,
497
- index=0,
498
- )
499
-
500
- add_outline = st.checkbox(
501
- "Overlay an administrative boundary on timelapse", False
502
- )
503
-
504
- if add_outline:
505
-
506
- with st.expander("Customize administrative boundary", True):
507
-
508
- overlay_options = {
509
- "User-defined": None,
510
- "Continents": "continents",
511
- "Countries": "countries",
512
- "US States": "us_states",
513
- "China": "china",
514
- }
515
-
516
- overlay = st.selectbox(
517
- "Select an administrative boundary:",
518
- list(overlay_options.keys()),
519
- index=2,
520
- )
521
-
522
- overlay_data = overlay_options[overlay]
523
-
524
- if overlay_data is None:
525
- overlay_data = st.text_input(
526
- "Enter an HTTP URL to a GeoJSON file or an ee.FeatureCollection asset id:",
527
- "https://raw.githubusercontent.com/giswqs/geemap/master/examples/data/countries.geojson",
528
- )
529
-
530
- overlay_color = st.color_picker(
531
- "Select a color for the administrative boundary:", "#000000"
532
- )
533
- overlay_width = st.slider(
534
- "Select a line width for the administrative boundary:", 1, 20, 1
535
- )
536
- overlay_opacity = st.slider(
537
- "Select an opacity for the administrative boundary:",
538
- 0.0,
539
- 1.0,
540
- 1.0,
541
- 0.05,
542
- )
543
- else:
544
- overlay_data = None
545
- overlay_color = "black"
546
- overlay_width = 1
547
- overlay_opacity = 1
548
-
549
- with row1_col1:
550
-
551
- with st.expander(
552
- "Steps: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Expand this tab to see a demo 👉"
553
- ):
554
- video_empty = st.empty()
555
-
556
- data = st.file_uploader(
557
- "Upload a GeoJSON file to use as an ROI. Customize timelapse parameters and then click the Submit button 😇👇",
558
- type=["geojson", "kml", "zip"],
559
- )
560
-
561
- crs = "epsg:4326"
562
- if sample_roi == "Uploaded GeoJSON":
563
- if data is None:
564
- # st.info(
565
- # "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click Submit button"
566
- # )
567
- if collection in [
568
- "Geostationary Operational Environmental Satellites (GOES)",
569
- "USDA National Agriculture Imagery Program (NAIP)",
570
- ] and (not keyword):
571
- m.set_center(-100, 40, 3)
572
- # else:
573
- # m.set_center(4.20, 18.63, zoom=2)
574
- else:
575
- if collection in [
576
- "Landsat TM-ETM-OLI Surface Reflectance",
577
- "Sentinel-2 MSI Surface Reflectance",
578
- ]:
579
- gdf = gpd.GeoDataFrame(
580
- index=[0], crs=crs, geometry=[landsat_rois[sample_roi]]
581
- )
582
- elif (
583
- collection
584
- == "Geostationary Operational Environmental Satellites (GOES)"
585
- ):
586
- gdf = gpd.GeoDataFrame(
587
- index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
588
- )
589
- elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
590
- gdf = gpd.GeoDataFrame(
591
- index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
592
- )
593
-
594
- if sample_roi != "Uploaded GeoJSON":
595
-
596
- if collection in [
597
- "Landsat TM-ETM-OLI Surface Reflectance",
598
- "Sentinel-2 MSI Surface Reflectance",
599
- ]:
600
- gdf = gpd.GeoDataFrame(
601
- index=[0], crs=crs, geometry=[landsat_rois[sample_roi]]
602
- )
603
- elif (
604
- collection
605
- == "Geostationary Operational Environmental Satellites (GOES)"
606
- ):
607
- gdf = gpd.GeoDataFrame(
608
- index=[0], crs=crs, geometry=[goes_rois[sample_roi]["region"]]
609
- )
610
- elif collection in [
611
- "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km",
612
- "MODIS Gap filled Land Surface Temperature Daily",
613
- ]:
614
- gdf = gpd.GeoDataFrame(
615
- index=[0], crs=crs, geometry=[modis_rois[sample_roi]]
616
- )
617
- elif collection == "MODIS Ocean Color SMI":
618
- gdf = gpd.GeoDataFrame(
619
- index=[0], crs=crs, geometry=[ocean_rois[sample_roi]]
620
- )
621
- try:
622
- st.session_state["roi"] = geemap.gdf_to_ee(gdf, geodesic=False)
623
- except Exception as e:
624
- st.error(e)
625
- st.error("Please draw another ROI and try again.")
626
- return
627
- m.add_gdf(gdf, "ROI")
628
-
629
- elif data:
630
- gdf = uploaded_file_to_gdf(data)
631
- try:
632
- st.session_state["roi"] = geemap.gdf_to_ee(gdf, geodesic=False)
633
- m.add_gdf(gdf, "ROI")
634
- except Exception as e:
635
- st.error(e)
636
- st.error("Please draw another ROI and try again.")
637
- return
638
-
639
- m.to_streamlit(height=600)
640
-
641
- with row1_col2:
642
-
643
- if collection in [
644
- "Landsat TM-ETM-OLI Surface Reflectance",
645
- "Sentinel-2 MSI Surface Reflectance",
646
- ]:
647
-
648
- if collection == "Landsat TM-ETM-OLI Surface Reflectance":
649
- sensor_start_year = 1984
650
- timelapse_title = "Landsat Timelapse"
651
- timelapse_speed = 5
652
- elif collection == "Sentinel-2 MSI Surface Reflectance":
653
- sensor_start_year = 2015
654
- timelapse_title = "Sentinel-2 Timelapse"
655
- timelapse_speed = 5
656
- video_empty.video("https://youtu.be/VVRK_-dEjR4")
657
-
658
- with st.form("submit_landsat_form"):
659
-
660
- roi = None
661
- if st.session_state.get("roi") is not None:
662
- roi = st.session_state.get("roi")
663
- out_gif = geemap.temp_file_path(".gif")
664
-
665
- title = st.text_input(
666
- "Enter a title to show on the timelapse: ", timelapse_title
667
- )
668
- RGB = st.selectbox(
669
- "Select an RGB band combination:",
670
- [
671
- "Red/Green/Blue",
672
- "NIR/Red/Green",
673
- "SWIR2/SWIR1/NIR",
674
- "NIR/SWIR1/Red",
675
- "SWIR2/NIR/Red",
676
- "SWIR2/SWIR1/Red",
677
- "SWIR1/NIR/Blue",
678
- "NIR/SWIR1/Blue",
679
- "SWIR2/NIR/Green",
680
- "SWIR1/NIR/Red",
681
- "SWIR2/NIR/SWIR1",
682
- "SWIR1/NIR/SWIR2",
683
- ],
684
- index=9,
685
- )
686
-
687
- frequency = st.selectbox(
688
- "Select a temporal frequency:",
689
- ["year", "quarter", "month"],
690
- index=0,
691
- )
692
-
693
- with st.expander("Customize timelapse"):
694
-
695
- speed = st.slider("Frames per second:", 1, 30, timelapse_speed)
696
- dimensions = st.slider(
697
- "Maximum dimensions (Width*Height) in pixels", 768, 2000, 768
698
- )
699
- progress_bar_color = st.color_picker(
700
- "Progress bar color:", "#0000ff"
701
- )
702
- years = st.slider(
703
- "Start and end year:",
704
- sensor_start_year,
705
- today.year,
706
- (sensor_start_year, today.year),
707
- )
708
- months = st.slider("Start and end month:", 1, 12, (1, 12))
709
- font_size = st.slider("Font size:", 10, 50, 30)
710
- font_color = st.color_picker("Font color:", "#ffffff")
711
- apply_fmask = st.checkbox(
712
- "Apply fmask (remove clouds, shadows, snow)", True
713
- )
714
- font_type = st.selectbox(
715
- "Select the font type for the title:",
716
- ["arial.ttf", "alibaba.otf"],
717
- index=0,
718
- )
719
- fading = st.slider(
720
- "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
721
- )
722
- mp4 = st.checkbox("Save timelapse as MP4", True)
723
-
724
- empty_text = st.empty()
725
- empty_image = st.empty()
726
- empty_fire_image = st.empty()
727
- empty_video = st.container()
728
- submitted = st.form_submit_button("Submit")
729
- if submitted:
730
-
731
- if sample_roi == "Uploaded GeoJSON" and data is None:
732
- empty_text.warning(
733
- "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
734
- )
735
- else:
736
-
737
- empty_text.text("Computing... Please wait...")
738
-
739
- start_year = years[0]
740
- end_year = years[1]
741
- start_date = str(months[0]).zfill(2) + "-01"
742
- end_date = str(months[1]).zfill(2) + "-30"
743
- bands = RGB.split("/")
744
-
745
- try:
746
- if collection == "Landsat TM-ETM-OLI Surface Reflectance":
747
- out_gif = geemap.landsat_timelapse(
748
- roi=roi,
749
- out_gif=out_gif,
750
- start_year=start_year,
751
- end_year=end_year,
752
- start_date=start_date,
753
- end_date=end_date,
754
- bands=bands,
755
- apply_fmask=apply_fmask,
756
- frames_per_second=speed,
757
- # dimensions=dimensions,
758
- dimensions=768,
759
- overlay_data=overlay_data,
760
- overlay_color=overlay_color,
761
- overlay_width=overlay_width,
762
- overlay_opacity=overlay_opacity,
763
- frequency=frequency,
764
- date_format=None,
765
- title=title,
766
- title_xy=("2%", "90%"),
767
- add_text=True,
768
- text_xy=("2%", "2%"),
769
- text_sequence=None,
770
- font_type=font_type,
771
- font_size=font_size,
772
- font_color=font_color,
773
- add_progress_bar=True,
774
- progress_bar_color=progress_bar_color,
775
- progress_bar_height=5,
776
- loop=0,
777
- mp4=mp4,
778
- fading=fading,
779
- )
780
- elif collection == "Sentinel-2 MSI Surface Reflectance":
781
- out_gif = geemap.sentinel2_timelapse(
782
- roi=roi,
783
- out_gif=out_gif,
784
- start_year=start_year,
785
- end_year=end_year,
786
- start_date=start_date,
787
- end_date=end_date,
788
- bands=bands,
789
- apply_fmask=apply_fmask,
790
- frames_per_second=speed,
791
- dimensions=768,
792
- # dimensions=dimensions,
793
- overlay_data=overlay_data,
794
- overlay_color=overlay_color,
795
- overlay_width=overlay_width,
796
- overlay_opacity=overlay_opacity,
797
- frequency=frequency,
798
- date_format=None,
799
- title=title,
800
- title_xy=("2%", "90%"),
801
- add_text=True,
802
- text_xy=("2%", "2%"),
803
- text_sequence=None,
804
- font_type=font_type,
805
- font_size=font_size,
806
- font_color=font_color,
807
- add_progress_bar=True,
808
- progress_bar_color=progress_bar_color,
809
- progress_bar_height=5,
810
- loop=0,
811
- mp4=mp4,
812
- fading=fading,
813
- )
814
- except:
815
- empty_text.error(
816
- "An error occurred while computing the timelapse. Your probably requested too much data. Try reducing the ROI or timespan."
817
- )
818
- st.stop()
819
-
820
- if out_gif is not None and os.path.exists(out_gif):
821
-
822
- empty_text.text(
823
- "Right click the GIF to save it to your computer👇"
824
- )
825
- empty_image.image(out_gif)
826
-
827
- out_mp4 = out_gif.replace(".gif", ".mp4")
828
- if mp4 and os.path.exists(out_mp4):
829
- with empty_video:
830
- st.text(
831
- "Right click the MP4 to save it to your computer👇"
832
- )
833
- st.video(out_gif.replace(".gif", ".mp4"))
834
-
835
- else:
836
- empty_text.error(
837
- "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
838
- )
839
-
840
- elif collection == "Geostationary Operational Environmental Satellites (GOES)":
841
-
842
- video_empty.video("https://youtu.be/16fA2QORG4A")
843
-
844
- with st.form("submit_goes_form"):
845
-
846
- roi = None
847
- if st.session_state.get("roi") is not None:
848
- roi = st.session_state.get("roi")
849
- out_gif = geemap.temp_file_path(".gif")
850
-
851
- satellite = st.selectbox("Select a satellite:", ["GOES-17", "GOES-16"])
852
- earliest_date = datetime.date(2017, 7, 10)
853
- latest_date = datetime.date.today()
854
-
855
- if sample_roi == "Uploaded GeoJSON":
856
- roi_start_date = today - datetime.timedelta(days=2)
857
- roi_end_date = today - datetime.timedelta(days=1)
858
- roi_start_time = datetime.time(14, 00)
859
- roi_end_time = datetime.time(1, 00)
860
- else:
861
- roi_start = goes_rois[sample_roi]["start_time"]
862
- roi_end = goes_rois[sample_roi]["end_time"]
863
- roi_start_date = datetime.datetime.strptime(
864
- roi_start[:10], "%Y-%m-%d"
865
- )
866
- roi_end_date = datetime.datetime.strptime(roi_end[:10], "%Y-%m-%d")
867
- roi_start_time = datetime.time(
868
- int(roi_start[11:13]), int(roi_start[14:16])
869
- )
870
- roi_end_time = datetime.time(
871
- int(roi_end[11:13]), int(roi_end[14:16])
872
- )
873
-
874
- start_date = st.date_input("Select the start date:", roi_start_date)
875
- end_date = st.date_input("Select the end date:", roi_end_date)
876
-
877
- with st.expander("Customize timelapse"):
878
-
879
- add_fire = st.checkbox("Add Fire/Hotspot Characterization", False)
880
-
881
- scan_type = st.selectbox(
882
- "Select a scan type:", ["Full Disk", "CONUS", "Mesoscale"]
883
- )
884
-
885
- start_time = st.time_input(
886
- "Select the start time of the start date:", roi_start_time
887
- )
888
-
889
- end_time = st.time_input(
890
- "Select the end time of the end date:", roi_end_time
891
- )
892
-
893
- start = (
894
- start_date.strftime("%Y-%m-%d")
895
- + "T"
896
- + start_time.strftime("%H:%M:%S")
897
- )
898
- end = (
899
- end_date.strftime("%Y-%m-%d")
900
- + "T"
901
- + end_time.strftime("%H:%M:%S")
902
- )
903
-
904
- speed = st.slider("Frames per second:", 1, 30, 5)
905
- add_progress_bar = st.checkbox("Add a progress bar", True)
906
- progress_bar_color = st.color_picker(
907
- "Progress bar color:", "#0000ff"
908
- )
909
- font_size = st.slider("Font size:", 10, 50, 20)
910
- font_color = st.color_picker("Font color:", "#ffffff")
911
- fading = st.slider(
912
- "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
913
- )
914
- mp4 = st.checkbox("Save timelapse as MP4", True)
915
-
916
- empty_text = st.empty()
917
- empty_image = st.empty()
918
- empty_video = st.container()
919
- empty_fire_text = st.empty()
920
- empty_fire_image = st.empty()
921
-
922
- submitted = st.form_submit_button("Submit")
923
- if submitted:
924
- if sample_roi == "Uploaded GeoJSON" and data is None:
925
- empty_text.warning(
926
- "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
927
- )
928
- else:
929
- empty_text.text("Computing... Please wait...")
930
-
931
- geemap.goes_timelapse(
932
- roi,
933
- out_gif,
934
- start_date=start,
935
- end_date=end,
936
- data=satellite,
937
- scan=scan_type.replace(" ", "_").lower(),
938
- dimensions=768,
939
- framesPerSecond=speed,
940
- date_format="YYYY-MM-dd HH:mm",
941
- xy=("3%", "3%"),
942
- text_sequence=None,
943
- font_type="arial.ttf",
944
- font_size=font_size,
945
- font_color=font_color,
946
- add_progress_bar=add_progress_bar,
947
- progress_bar_color=progress_bar_color,
948
- progress_bar_height=5,
949
- loop=0,
950
- overlay_data=overlay_data,
951
- overlay_color=overlay_color,
952
- overlay_width=overlay_width,
953
- overlay_opacity=overlay_opacity,
954
- mp4=mp4,
955
- fading=fading,
956
- )
957
-
958
- if out_gif is not None and os.path.exists(out_gif):
959
- empty_text.text(
960
- "Right click the GIF to save it to your computer👇"
961
- )
962
- empty_image.image(out_gif)
963
-
964
- out_mp4 = out_gif.replace(".gif", ".mp4")
965
- if mp4 and os.path.exists(out_mp4):
966
- with empty_video:
967
- st.text(
968
- "Right click the MP4 to save it to your computer👇"
969
- )
970
- st.video(out_gif.replace(".gif", ".mp4"))
971
-
972
- if add_fire:
973
- out_fire_gif = geemap.temp_file_path(".gif")
974
- empty_fire_text.text(
975
- "Delineating Fire Hotspot... Please wait..."
976
- )
977
- geemap.goes_fire_timelapse(
978
- out_fire_gif,
979
- start_date=start,
980
- end_date=end,
981
- data=satellite,
982
- scan=scan_type.replace(" ", "_").lower(),
983
- region=roi,
984
- dimensions=768,
985
- framesPerSecond=speed,
986
- date_format="YYYY-MM-dd HH:mm",
987
- xy=("3%", "3%"),
988
- text_sequence=None,
989
- font_type="arial.ttf",
990
- font_size=font_size,
991
- font_color=font_color,
992
- add_progress_bar=add_progress_bar,
993
- progress_bar_color=progress_bar_color,
994
- progress_bar_height=5,
995
- loop=0,
996
- )
997
- if os.path.exists(out_fire_gif):
998
- empty_fire_image.image(out_fire_gif)
999
- else:
1000
- empty_text.text(
1001
- "Something went wrong, either the ROI is too big or there are no data available for the specified date range. Please try a smaller ROI or different date range."
1002
- )
1003
-
1004
- elif collection == "MODIS Vegetation Indices (NDVI/EVI) 16-Day Global 1km":
1005
-
1006
- video_empty.video("https://youtu.be/16fA2QORG4A")
1007
-
1008
- satellite = st.selectbox("Select a satellite:", ["Terra", "Aqua"])
1009
- band = st.selectbox("Select a band:", ["NDVI", "EVI"])
1010
-
1011
- with st.form("submit_modis_form"):
1012
-
1013
- roi = None
1014
- if st.session_state.get("roi") is not None:
1015
- roi = st.session_state.get("roi")
1016
- out_gif = geemap.temp_file_path(".gif")
1017
-
1018
- with st.expander("Customize timelapse"):
1019
-
1020
- start = st.date_input(
1021
- "Select a start date:", datetime.date(2000, 2, 8)
1022
- )
1023
- end = st.date_input("Select an end date:", datetime.date.today())
1024
-
1025
- start_date = start.strftime("%Y-%m-%d")
1026
- end_date = end.strftime("%Y-%m-%d")
1027
-
1028
- speed = st.slider("Frames per second:", 1, 30, 5)
1029
- add_progress_bar = st.checkbox("Add a progress bar", True)
1030
- progress_bar_color = st.color_picker(
1031
- "Progress bar color:", "#0000ff"
1032
- )
1033
- font_size = st.slider("Font size:", 10, 50, 20)
1034
- font_color = st.color_picker("Font color:", "#ffffff")
1035
-
1036
- font_type = st.selectbox(
1037
- "Select the font type for the title:",
1038
- ["arial.ttf", "alibaba.otf"],
1039
- index=0,
1040
- )
1041
- fading = st.slider(
1042
- "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1043
- )
1044
- mp4 = st.checkbox("Save timelapse as MP4", True)
1045
-
1046
- empty_text = st.empty()
1047
- empty_image = st.empty()
1048
- empty_video = st.container()
1049
-
1050
- submitted = st.form_submit_button("Submit")
1051
- if submitted:
1052
- if sample_roi == "Uploaded GeoJSON" and data is None:
1053
- empty_text.warning(
1054
- "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
1055
- )
1056
- else:
1057
-
1058
- empty_text.text("Computing... Please wait...")
1059
-
1060
- geemap.modis_ndvi_timelapse(
1061
- roi,
1062
- out_gif,
1063
- satellite,
1064
- band,
1065
- start_date,
1066
- end_date,
1067
- 768,
1068
- speed,
1069
- overlay_data=overlay_data,
1070
- overlay_color=overlay_color,
1071
- overlay_width=overlay_width,
1072
- overlay_opacity=overlay_opacity,
1073
- mp4=mp4,
1074
- fading=fading,
1075
- )
1076
-
1077
- geemap.reduce_gif_size(out_gif)
1078
-
1079
- empty_text.text(
1080
- "Right click the GIF to save it to your computer👇"
1081
- )
1082
- empty_image.image(out_gif)
1083
-
1084
- out_mp4 = out_gif.replace(".gif", ".mp4")
1085
- if mp4 and os.path.exists(out_mp4):
1086
- with empty_video:
1087
- st.text(
1088
- "Right click the MP4 to save it to your computer👇"
1089
- )
1090
- st.video(out_gif.replace(".gif", ".mp4"))
1091
-
1092
- elif collection == "Any Earth Engine ImageCollection":
1093
-
1094
- with st.form("submit_ts_form"):
1095
- with st.expander("Customize timelapse"):
1096
-
1097
- title = st.text_input(
1098
- "Enter a title to show on the timelapse: ", "Timelapse"
1099
- )
1100
- start_date = st.date_input(
1101
- "Select the start date:", datetime.date(2020, 1, 1)
1102
- )
1103
- end_date = st.date_input(
1104
- "Select the end date:", datetime.date.today()
1105
- )
1106
- frequency = st.selectbox(
1107
- "Select a temporal frequency:",
1108
- ["year", "quarter", "month", "day", "hour", "minute", "second"],
1109
- index=0,
1110
- )
1111
- reducer = st.selectbox(
1112
- "Select a reducer for aggregating data:",
1113
- ["median", "mean", "min", "max", "sum", "variance", "stdDev"],
1114
- index=0,
1115
- )
1116
- data_format = st.selectbox(
1117
- "Select a date format to show on the timelapse:",
1118
- [
1119
- "YYYY-MM-dd",
1120
- "YYYY",
1121
- "YYMM-MM",
1122
- "YYYY-MM-dd HH:mm",
1123
- "YYYY-MM-dd HH:mm:ss",
1124
- "HH:mm",
1125
- "HH:mm:ss",
1126
- "w",
1127
- "M",
1128
- "d",
1129
- "D",
1130
- ],
1131
- index=0,
1132
- )
1133
-
1134
- speed = st.slider("Frames per second:", 1, 30, 5)
1135
- add_progress_bar = st.checkbox("Add a progress bar", True)
1136
- progress_bar_color = st.color_picker(
1137
- "Progress bar color:", "#0000ff"
1138
- )
1139
- font_size = st.slider("Font size:", 10, 50, 30)
1140
- font_color = st.color_picker("Font color:", "#ffffff")
1141
- font_type = st.selectbox(
1142
- "Select the font type for the title:",
1143
- ["arial.ttf", "alibaba.otf"],
1144
- index=0,
1145
- )
1146
- fading = st.slider(
1147
- "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1148
- )
1149
- mp4 = st.checkbox("Save timelapse as MP4", True)
1150
-
1151
- empty_text = st.empty()
1152
- empty_image = st.empty()
1153
- empty_video = st.container()
1154
- empty_fire_image = st.empty()
1155
-
1156
- roi = None
1157
- if st.session_state.get("roi") is not None:
1158
- roi = st.session_state.get("roi")
1159
- out_gif = geemap.temp_file_path(".gif")
1160
-
1161
- submitted = st.form_submit_button("Submit")
1162
- if submitted:
1163
-
1164
- if sample_roi == "Uploaded GeoJSON" and data is None:
1165
- empty_text.warning(
1166
- "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
1167
- )
1168
- else:
1169
-
1170
- empty_text.text("Computing... Please wait...")
1171
- try:
1172
- geemap.create_timelapse(
1173
- st.session_state.get("ee_asset_id"),
1174
- start_date=start_date.strftime("%Y-%m-%d"),
1175
- end_date=end_date.strftime("%Y-%m-%d"),
1176
- region=roi,
1177
- frequency=frequency,
1178
- reducer=reducer,
1179
- date_format=data_format,
1180
- out_gif=out_gif,
1181
- bands=st.session_state.get("bands"),
1182
- palette=st.session_state.get("palette"),
1183
- vis_params=st.session_state.get("vis_params"),
1184
- dimensions=768,
1185
- frames_per_second=speed,
1186
- crs="EPSG:3857",
1187
- overlay_data=overlay_data,
1188
- overlay_color=overlay_color,
1189
- overlay_width=overlay_width,
1190
- overlay_opacity=overlay_opacity,
1191
- title=title,
1192
- title_xy=("2%", "90%"),
1193
- add_text=True,
1194
- text_xy=("2%", "2%"),
1195
- text_sequence=None,
1196
- font_type=font_type,
1197
- font_size=font_size,
1198
- font_color=font_color,
1199
- add_progress_bar=add_progress_bar,
1200
- progress_bar_color=progress_bar_color,
1201
- progress_bar_height=5,
1202
- loop=0,
1203
- mp4=mp4,
1204
- fading=fading,
1205
- )
1206
- except:
1207
- empty_text.error(
1208
- "An error occurred while computing the timelapse. You probably requested too much data. Try reducing the ROI or timespan."
1209
- )
1210
-
1211
- empty_text.text(
1212
- "Right click the GIF to save it to your computer👇"
1213
- )
1214
- empty_image.image(out_gif)
1215
-
1216
- out_mp4 = out_gif.replace(".gif", ".mp4")
1217
- if mp4 and os.path.exists(out_mp4):
1218
- with empty_video:
1219
- st.text(
1220
- "Right click the MP4 to save it to your computer👇"
1221
- )
1222
- st.video(out_gif.replace(".gif", ".mp4"))
1223
-
1224
- elif collection in [
1225
- "MODIS Gap filled Land Surface Temperature Daily",
1226
- "MODIS Ocean Color SMI",
1227
- ]:
1228
-
1229
- with st.form("submit_ts_form"):
1230
- with st.expander("Customize timelapse"):
1231
-
1232
- title = st.text_input(
1233
- "Enter a title to show on the timelapse: ",
1234
- "Surface Temperature",
1235
- )
1236
- start_date = st.date_input(
1237
- "Select the start date:", datetime.date(2018, 1, 1)
1238
- )
1239
- end_date = st.date_input(
1240
- "Select the end date:", datetime.date(2020, 12, 31)
1241
- )
1242
- frequency = st.selectbox(
1243
- "Select a temporal frequency:",
1244
- ["year", "quarter", "month", "week", "day"],
1245
- index=2,
1246
- )
1247
- reducer = st.selectbox(
1248
- "Select a reducer for aggregating data:",
1249
- ["median", "mean", "min", "max", "sum", "variance", "stdDev"],
1250
- index=0,
1251
- )
1252
-
1253
- vis_params = st.text_area(
1254
- "Enter visualization parameters",
1255
- "",
1256
- help="Enter a string in the format of a dictionary, such as '{'min': 23, 'max': 32}'",
1257
- )
1258
-
1259
- speed = st.slider("Frames per second:", 1, 30, 5)
1260
- add_progress_bar = st.checkbox("Add a progress bar", True)
1261
- progress_bar_color = st.color_picker(
1262
- "Progress bar color:", "#0000ff"
1263
- )
1264
- font_size = st.slider("Font size:", 10, 50, 30)
1265
- font_color = st.color_picker("Font color:", "#ffffff")
1266
- font_type = st.selectbox(
1267
- "Select the font type for the title:",
1268
- ["arial.ttf", "alibaba.otf"],
1269
- index=0,
1270
- )
1271
- add_colorbar = st.checkbox("Add a colorbar", True)
1272
- colorbar_label = st.text_input(
1273
- "Enter the colorbar label:", "Surface Temperature (°C)"
1274
- )
1275
- fading = st.slider(
1276
- "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1277
- )
1278
- mp4 = st.checkbox("Save timelapse as MP4", True)
1279
-
1280
- empty_text = st.empty()
1281
- empty_image = st.empty()
1282
- empty_video = st.container()
1283
-
1284
- roi = None
1285
- if st.session_state.get("roi") is not None:
1286
- roi = st.session_state.get("roi")
1287
- out_gif = geemap.temp_file_path(".gif")
1288
-
1289
- submitted = st.form_submit_button("Submit")
1290
- if submitted:
1291
-
1292
- if sample_roi == "Uploaded GeoJSON" and data is None:
1293
- empty_text.warning(
1294
- "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
1295
- )
1296
- else:
1297
-
1298
- empty_text.text("Computing... Please wait...")
1299
- try:
1300
- if (
1301
- collection
1302
- == "MODIS Gap filled Land Surface Temperature Daily"
1303
- ):
1304
- out_gif = geemap.create_timelapse(
1305
- st.session_state.get("ee_asset_id"),
1306
- start_date=start_date.strftime("%Y-%m-%d"),
1307
- end_date=end_date.strftime("%Y-%m-%d"),
1308
- region=roi,
1309
- bands=None,
1310
- frequency=frequency,
1311
- reducer=reducer,
1312
- date_format=None,
1313
- out_gif=out_gif,
1314
- palette=st.session_state.get("palette"),
1315
- vis_params=None,
1316
- dimensions=768,
1317
- frames_per_second=speed,
1318
- crs="EPSG:3857",
1319
- overlay_data=overlay_data,
1320
- overlay_color=overlay_color,
1321
- overlay_width=overlay_width,
1322
- overlay_opacity=overlay_opacity,
1323
- title=title,
1324
- title_xy=("2%", "90%"),
1325
- add_text=True,
1326
- text_xy=("2%", "2%"),
1327
- text_sequence=None,
1328
- font_type=font_type,
1329
- font_size=font_size,
1330
- font_color=font_color,
1331
- add_progress_bar=add_progress_bar,
1332
- progress_bar_color=progress_bar_color,
1333
- progress_bar_height=5,
1334
- add_colorbar=add_colorbar,
1335
- colorbar_label=colorbar_label,
1336
- loop=0,
1337
- mp4=mp4,
1338
- fading=fading,
1339
- )
1340
- elif collection == "MODIS Ocean Color SMI":
1341
- if vis_params.startswith("{") and vis_params.endswith(
1342
- "}"
1343
- ):
1344
- vis_params = eval(vis_params)
1345
- else:
1346
- vis_params = None
1347
- out_gif = geemap.modis_ocean_color_timelapse(
1348
- st.session_state.get("ee_asset_id"),
1349
- start_date=start_date.strftime("%Y-%m-%d"),
1350
- end_date=end_date.strftime("%Y-%m-%d"),
1351
- region=roi,
1352
- bands=st.session_state["band"],
1353
- frequency=frequency,
1354
- reducer=reducer,
1355
- date_format=None,
1356
- out_gif=out_gif,
1357
- palette=st.session_state.get("palette"),
1358
- vis_params=vis_params,
1359
- dimensions=768,
1360
- frames_per_second=speed,
1361
- crs="EPSG:3857",
1362
- overlay_data=overlay_data,
1363
- overlay_color=overlay_color,
1364
- overlay_width=overlay_width,
1365
- overlay_opacity=overlay_opacity,
1366
- title=title,
1367
- title_xy=("2%", "90%"),
1368
- add_text=True,
1369
- text_xy=("2%", "2%"),
1370
- text_sequence=None,
1371
- font_type=font_type,
1372
- font_size=font_size,
1373
- font_color=font_color,
1374
- add_progress_bar=add_progress_bar,
1375
- progress_bar_color=progress_bar_color,
1376
- progress_bar_height=5,
1377
- add_colorbar=add_colorbar,
1378
- colorbar_label=colorbar_label,
1379
- loop=0,
1380
- mp4=mp4,
1381
- fading=fading,
1382
- )
1383
- except:
1384
- empty_text.error(
1385
- "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1386
- )
1387
-
1388
- if out_gif is not None and os.path.exists(out_gif):
1389
-
1390
- geemap.reduce_gif_size(out_gif)
1391
-
1392
- empty_text.text(
1393
- "Right click the GIF to save it to your computer👇"
1394
- )
1395
- empty_image.image(out_gif)
1396
-
1397
- out_mp4 = out_gif.replace(".gif", ".mp4")
1398
- if mp4 and os.path.exists(out_mp4):
1399
- with empty_video:
1400
- st.text(
1401
- "Right click the MP4 to save it to your computer👇"
1402
- )
1403
- st.video(out_gif.replace(".gif", ".mp4"))
1404
-
1405
- else:
1406
- st.error(
1407
- "Something went wrong. You probably requested too much data. Try reducing the ROI or timespan."
1408
- )
1409
-
1410
- elif collection == "USDA National Agriculture Imagery Program (NAIP)":
1411
-
1412
- with st.form("submit_naip_form"):
1413
- with st.expander("Customize timelapse"):
1414
-
1415
- title = st.text_input(
1416
- "Enter a title to show on the timelapse: ", "NAIP Timelapse"
1417
- )
1418
-
1419
- years = st.slider(
1420
- "Start and end year:",
1421
- 2003,
1422
- today.year,
1423
- (2003, today.year),
1424
- )
1425
-
1426
- bands = st.selectbox(
1427
- "Select a band combination:", ["N/R/G", "R/G/B"], index=0
1428
- )
1429
-
1430
- speed = st.slider("Frames per second:", 1, 30, 3)
1431
- add_progress_bar = st.checkbox("Add a progress bar", True)
1432
- progress_bar_color = st.color_picker(
1433
- "Progress bar color:", "#0000ff"
1434
- )
1435
- font_size = st.slider("Font size:", 10, 50, 30)
1436
- font_color = st.color_picker("Font color:", "#ffffff")
1437
- font_type = st.selectbox(
1438
- "Select the font type for the title:",
1439
- ["arial.ttf", "alibaba.otf"],
1440
- index=0,
1441
- )
1442
- fading = st.slider(
1443
- "Fading duration (seconds) for each frame:", 0.0, 3.0, 0.0
1444
- )
1445
- mp4 = st.checkbox("Save timelapse as MP4", True)
1446
-
1447
- empty_text = st.empty()
1448
- empty_image = st.empty()
1449
- empty_video = st.container()
1450
- empty_fire_image = st.empty()
1451
-
1452
- roi = None
1453
- if st.session_state.get("roi") is not None:
1454
- roi = st.session_state.get("roi")
1455
- out_gif = geemap.temp_file_path(".gif")
1456
-
1457
- submitted = st.form_submit_button("Submit")
1458
- if submitted:
1459
-
1460
- if sample_roi == "Uploaded GeoJSON" and data is None:
1461
- empty_text.warning(
1462
- "Steps to create a timelapse: Draw a rectangle on the map -> Export it as a GeoJSON -> Upload it back to the app -> Click the Submit button. Alternatively, you can select a sample ROI from the dropdown list."
1463
- )
1464
- else:
1465
-
1466
- empty_text.text("Computing... Please wait...")
1467
- try:
1468
- geemap.naip_timelapse(
1469
- roi,
1470
- years[0],
1471
- years[1],
1472
- out_gif,
1473
- bands=bands.split("/"),
1474
- palette=st.session_state.get("palette"),
1475
- vis_params=None,
1476
- dimensions=768,
1477
- frames_per_second=speed,
1478
- crs="EPSG:3857",
1479
- overlay_data=overlay_data,
1480
- overlay_color=overlay_color,
1481
- overlay_width=overlay_width,
1482
- overlay_opacity=overlay_opacity,
1483
- title=title,
1484
- title_xy=("2%", "90%"),
1485
- add_text=True,
1486
- text_xy=("2%", "2%"),
1487
- text_sequence=None,
1488
- font_type=font_type,
1489
- font_size=font_size,
1490
- font_color=font_color,
1491
- add_progress_bar=add_progress_bar,
1492
- progress_bar_color=progress_bar_color,
1493
- progress_bar_height=5,
1494
- loop=0,
1495
- mp4=mp4,
1496
- fading=fading,
1497
- )
1498
- except:
1499
- empty_text.error(
1500
- "Something went wrong. You either requested too much data or the ROI is outside the U.S."
1501
- )
1502
-
1503
- if out_gif is not None and os.path.exists(out_gif):
1504
-
1505
- empty_text.text(
1506
- "Right click the GIF to save it to your computer👇"
1507
- )
1508
- empty_image.image(out_gif)
1509
-
1510
- out_mp4 = out_gif.replace(".gif", ".mp4")
1511
- if mp4 and os.path.exists(out_mp4):
1512
- with empty_video:
1513
- st.text(
1514
- "Right click the MP4 to save it to your computer👇"
1515
- )
1516
- st.video(out_gif.replace(".gif", ".mp4"))
1517
-
1518
- else:
1519
- st.error(
1520
- "Something went wrong. You either requested too much data or the ROI is outside the U.S."
1521
- )
1522
-
1523
-
1524
- try:
1525
- app()
1526
- except Exception as e:
1527
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/2_🏠_U.S._Housing.py DELETED
@@ -1,482 +0,0 @@
1
- import datetime
2
- import os
3
- import pathlib
4
- import requests
5
- import zipfile
6
- import pandas as pd
7
- import pydeck as pdk
8
- import geopandas as gpd
9
- import streamlit as st
10
- import leafmap.colormaps as cm
11
- from leafmap.common import hex_to_rgb
12
-
13
- st.set_page_config(layout="wide")
14
-
15
- st.sidebar.info(
16
- """
17
- - Web App URL: <https://streamlit.gishub.org>
18
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
19
- """
20
- )
21
-
22
- st.sidebar.title("Contact")
23
- st.sidebar.info(
24
- """
25
- 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)
26
- """
27
- )
28
-
29
- STREAMLIT_STATIC_PATH = pathlib.Path(st.__path__[0]) / "static"
30
- # We create a downloads directory within the streamlit static asset directory
31
- # and we write output files to it
32
- DOWNLOADS_PATH = STREAMLIT_STATIC_PATH / "downloads"
33
- if not DOWNLOADS_PATH.is_dir():
34
- DOWNLOADS_PATH.mkdir()
35
-
36
- # Data source: https://www.realtor.com/research/data/
37
- # link_prefix = "https://econdata.s3-us-west-2.amazonaws.com/Reports/"
38
- link_prefix = "https://raw.githubusercontent.com/giswqs/data/main/housing/"
39
-
40
- data_links = {
41
- "weekly": {
42
- "national": link_prefix + "Core/listing_weekly_core_aggregate_by_country.csv",
43
- "metro": link_prefix + "Core/listing_weekly_core_aggregate_by_metro.csv",
44
- },
45
- "monthly_current": {
46
- "national": link_prefix + "Core/RDC_Inventory_Core_Metrics_Country.csv",
47
- "state": link_prefix + "Core/RDC_Inventory_Core_Metrics_State.csv",
48
- "metro": link_prefix + "Core/RDC_Inventory_Core_Metrics_Metro.csv",
49
- "county": link_prefix + "Core/RDC_Inventory_Core_Metrics_County.csv",
50
- "zip": link_prefix + "Core/RDC_Inventory_Core_Metrics_Zip.csv",
51
- },
52
- "monthly_historical": {
53
- "national": link_prefix + "Core/RDC_Inventory_Core_Metrics_Country_History.csv",
54
- "state": link_prefix + "Core/RDC_Inventory_Core_Metrics_State_History.csv",
55
- "metro": link_prefix + "Core/RDC_Inventory_Core_Metrics_Metro_History.csv",
56
- "county": link_prefix + "Core/RDC_Inventory_Core_Metrics_County_History.csv",
57
- "zip": link_prefix + "Core/RDC_Inventory_Core_Metrics_Zip_History.csv",
58
- },
59
- "hotness": {
60
- "metro": link_prefix
61
- + "Hotness/RDC_Inventory_Hotness_Metrics_Metro_History.csv",
62
- "county": link_prefix
63
- + "Hotness/RDC_Inventory_Hotness_Metrics_County_History.csv",
64
- "zip": link_prefix + "Hotness/RDC_Inventory_Hotness_Metrics_Zip_History.csv",
65
- },
66
- }
67
-
68
-
69
- def get_data_columns(df, category, frequency="monthly"):
70
- if frequency == "monthly":
71
- if category.lower() == "county":
72
- del_cols = ["month_date_yyyymm", "county_fips", "county_name"]
73
- elif category.lower() == "state":
74
- del_cols = ["month_date_yyyymm", "state", "state_id"]
75
- elif category.lower() == "national":
76
- del_cols = ["month_date_yyyymm", "country"]
77
- elif category.lower() == "metro":
78
- del_cols = ["month_date_yyyymm", "cbsa_code", "cbsa_title", "HouseholdRank"]
79
- elif category.lower() == "zip":
80
- del_cols = ["month_date_yyyymm", "postal_code", "zip_name", "flag"]
81
- elif frequency == "weekly":
82
- if category.lower() == "national":
83
- del_cols = ["week_end_date", "geo_country"]
84
- elif category.lower() == "metro":
85
- del_cols = ["week_end_date", "cbsa_code", "cbsa_title", "hh_rank"]
86
-
87
- cols = df.columns.values.tolist()
88
-
89
- for col in cols:
90
- if col.strip() in del_cols:
91
- cols.remove(col)
92
- if category.lower() == "metro":
93
- return cols[2:]
94
- else:
95
- return cols[1:]
96
-
97
-
98
- @st.cache(allow_output_mutation=True)
99
- def get_inventory_data(url):
100
- df = pd.read_csv(url)
101
- url = url.lower()
102
- if "county" in url:
103
- df["county_fips"] = df["county_fips"].map(str)
104
- df["county_fips"] = df["county_fips"].str.zfill(5)
105
- elif "state" in url:
106
- df["STUSPS"] = df["state_id"].str.upper()
107
- elif "metro" in url:
108
- df["cbsa_code"] = df["cbsa_code"].map(str)
109
- elif "zip" in url:
110
- df["postal_code"] = df["postal_code"].map(str)
111
- df["postal_code"] = df["postal_code"].str.zfill(5)
112
-
113
- if "listing_weekly_core_aggregate_by_country" in url:
114
- columns = get_data_columns(df, "national", "weekly")
115
- for column in columns:
116
- if column != "median_days_on_market_by_day_yy":
117
- df[column] = df[column].str.rstrip("%").astype(float) / 100
118
- if "listing_weekly_core_aggregate_by_metro" in url:
119
- columns = get_data_columns(df, "metro", "weekly")
120
- for column in columns:
121
- if column != "median_days_on_market_by_day_yy":
122
- df[column] = df[column].str.rstrip("%").astype(float) / 100
123
- df["cbsa_code"] = df["cbsa_code"].str[:5]
124
- return df
125
-
126
-
127
- def filter_weekly_inventory(df, week):
128
- df = df[df["week_end_date"] == week]
129
- return df
130
-
131
-
132
- def get_start_end_year(df):
133
- start_year = int(str(df["month_date_yyyymm"].min())[:4])
134
- end_year = int(str(df["month_date_yyyymm"].max())[:4])
135
- return start_year, end_year
136
-
137
-
138
- def get_periods(df):
139
- return [str(d) for d in list(set(df["month_date_yyyymm"].tolist()))]
140
-
141
-
142
- @st.cache(allow_output_mutation=True)
143
- def get_geom_data(category):
144
-
145
- prefix = (
146
- "https://raw.githubusercontent.com/giswqs/streamlit-geospatial/master/data/"
147
- )
148
- links = {
149
- "national": prefix + "us_nation.geojson",
150
- "state": prefix + "us_states.geojson",
151
- "county": prefix + "us_counties.geojson",
152
- "metro": prefix + "us_metro_areas.geojson",
153
- "zip": "https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_zcta510_500k.zip",
154
- }
155
-
156
- if category.lower() == "zip":
157
- r = requests.get(links[category])
158
- out_zip = os.path.join(DOWNLOADS_PATH, "cb_2018_us_zcta510_500k.zip")
159
- with open(out_zip, "wb") as code:
160
- code.write(r.content)
161
- zip_ref = zipfile.ZipFile(out_zip, "r")
162
- zip_ref.extractall(DOWNLOADS_PATH)
163
- gdf = gpd.read_file(out_zip.replace("zip", "shp"))
164
- else:
165
- gdf = gpd.read_file(links[category])
166
- return gdf
167
-
168
-
169
- def join_attributes(gdf, df, category):
170
-
171
- new_gdf = None
172
- if category == "county":
173
- new_gdf = gdf.merge(df, left_on="GEOID", right_on="county_fips", how="outer")
174
- elif category == "state":
175
- new_gdf = gdf.merge(df, left_on="STUSPS", right_on="STUSPS", how="outer")
176
- elif category == "national":
177
- if "geo_country" in df.columns.values.tolist():
178
- df["country"] = None
179
- df.loc[0, "country"] = "United States"
180
- new_gdf = gdf.merge(df, left_on="NAME", right_on="country", how="outer")
181
- elif category == "metro":
182
- new_gdf = gdf.merge(df, left_on="CBSAFP", right_on="cbsa_code", how="outer")
183
- elif category == "zip":
184
- new_gdf = gdf.merge(df, left_on="GEOID10", right_on="postal_code", how="outer")
185
- return new_gdf
186
-
187
-
188
- def select_non_null(gdf, col_name):
189
- new_gdf = gdf[~gdf[col_name].isna()]
190
- return new_gdf
191
-
192
-
193
- def select_null(gdf, col_name):
194
- new_gdf = gdf[gdf[col_name].isna()]
195
- return new_gdf
196
-
197
-
198
- def get_data_dict(name):
199
- in_csv = os.path.join(os.getcwd(), "data/realtor_data_dict.csv")
200
- df = pd.read_csv(in_csv)
201
- label = list(df[df["Name"] == name]["Label"])[0]
202
- desc = list(df[df["Name"] == name]["Description"])[0]
203
- return label, desc
204
-
205
-
206
- def get_weeks(df):
207
- seq = list(set(df[~df["week_end_date"].isnull()]["week_end_date"].tolist()))
208
- weeks = [
209
- datetime.date(int(d.split("/")[2]), int(d.split("/")[0]), int(d.split("/")[1]))
210
- for d in seq
211
- ]
212
- weeks.sort()
213
- return weeks
214
-
215
-
216
- def get_saturday(in_date):
217
- idx = (in_date.weekday() + 1) % 7
218
- sat = in_date + datetime.timedelta(6 - idx)
219
- return sat
220
-
221
-
222
- def app():
223
-
224
- st.title("U.S. Real Estate Data and Market Trends")
225
- st.markdown(
226
- """**Introduction:** This interactive dashboard is designed for visualizing U.S. real estate data and market trends at multiple levels (i.e., national,
227
- state, county, and metro). The data sources include [Real Estate Data](https://www.realtor.com/research/data) from realtor.com and
228
- [Cartographic Boundary Files](https://www.census.gov/geographies/mapping-files/time-series/geo/carto-boundary-file.html) from U.S. Census Bureau.
229
- Several open-source packages are used to process the data and generate the visualizations, e.g., [streamlit](https://streamlit.io),
230
- [geopandas](https://geopandas.org), [leafmap](https://leafmap.org), and [pydeck](https://deckgl.readthedocs.io).
231
- """
232
- )
233
-
234
- with st.expander("See a demo"):
235
- st.image("https://i.imgur.com/Z3dk6Tr.gif")
236
-
237
- row1_col1, row1_col2, row1_col3, row1_col4, row1_col5 = st.columns(
238
- [0.6, 0.8, 0.6, 1.4, 2]
239
- )
240
- with row1_col1:
241
- frequency = st.selectbox("Monthly/weekly data", ["Monthly", "Weekly"])
242
- with row1_col2:
243
- types = ["Current month data", "Historical data"]
244
- if frequency == "Weekly":
245
- types.remove("Current month data")
246
- cur_hist = st.selectbox(
247
- "Current/historical data",
248
- types,
249
- )
250
- with row1_col3:
251
- if frequency == "Monthly":
252
- scale = st.selectbox(
253
- "Scale", ["National", "State", "Metro", "County"], index=3
254
- )
255
- else:
256
- scale = st.selectbox("Scale", ["National", "Metro"], index=1)
257
-
258
- gdf = get_geom_data(scale.lower())
259
-
260
- if frequency == "Weekly":
261
- inventory_df = get_inventory_data(data_links["weekly"][scale.lower()])
262
- weeks = get_weeks(inventory_df)
263
- with row1_col1:
264
- selected_date = st.date_input("Select a date", value=weeks[-1])
265
- saturday = get_saturday(selected_date)
266
- selected_period = saturday.strftime("%-m/%-d/%Y")
267
- if saturday not in weeks:
268
- st.error(
269
- "The selected date is not available in the data. Please select a date between {} and {}".format(
270
- weeks[0], weeks[-1]
271
- )
272
- )
273
- selected_period = weeks[-1].strftime("%-m/%-d/%Y")
274
- inventory_df = get_inventory_data(data_links["weekly"][scale.lower()])
275
- inventory_df = filter_weekly_inventory(inventory_df, selected_period)
276
-
277
- if frequency == "Monthly":
278
- if cur_hist == "Current month data":
279
- inventory_df = get_inventory_data(
280
- data_links["monthly_current"][scale.lower()]
281
- )
282
- selected_period = get_periods(inventory_df)[0]
283
- else:
284
- with row1_col2:
285
- inventory_df = get_inventory_data(
286
- data_links["monthly_historical"][scale.lower()]
287
- )
288
- start_year, end_year = get_start_end_year(inventory_df)
289
- periods = get_periods(inventory_df)
290
- with st.expander("Select year and month", True):
291
- selected_year = st.slider(
292
- "Year",
293
- start_year,
294
- end_year,
295
- value=start_year,
296
- step=1,
297
- )
298
- selected_month = st.slider(
299
- "Month",
300
- min_value=1,
301
- max_value=12,
302
- value=int(periods[0][-2:]),
303
- step=1,
304
- )
305
- selected_period = str(selected_year) + str(selected_month).zfill(2)
306
- if selected_period not in periods:
307
- st.error("Data not available for selected year and month")
308
- selected_period = periods[0]
309
- inventory_df = inventory_df[
310
- inventory_df["month_date_yyyymm"] == int(selected_period)
311
- ]
312
-
313
- data_cols = get_data_columns(inventory_df, scale.lower(), frequency.lower())
314
-
315
- with row1_col4:
316
- selected_col = st.selectbox("Attribute", data_cols)
317
- with row1_col5:
318
- show_desc = st.checkbox("Show attribute description")
319
- if show_desc:
320
- try:
321
- label, desc = get_data_dict(selected_col.strip())
322
- markdown = f"""
323
- **{label}**: {desc}
324
- """
325
- st.markdown(markdown)
326
- except:
327
- st.warning("No description available for selected attribute")
328
-
329
- row2_col1, row2_col2, row2_col3, row2_col4, row2_col5, row2_col6 = st.columns(
330
- [0.6, 0.68, 0.7, 0.7, 1.5, 0.8]
331
- )
332
-
333
- palettes = cm.list_colormaps()
334
- with row2_col1:
335
- palette = st.selectbox("Color palette", palettes, index=palettes.index("Blues"))
336
- with row2_col2:
337
- n_colors = st.slider("Number of colors", min_value=2, max_value=20, value=8)
338
- with row2_col3:
339
- show_nodata = st.checkbox("Show nodata areas", value=True)
340
- with row2_col4:
341
- show_3d = st.checkbox("Show 3D view", value=False)
342
- with row2_col5:
343
- if show_3d:
344
- elev_scale = st.slider(
345
- "Elevation scale", min_value=1, max_value=1000000, value=1, step=10
346
- )
347
- with row2_col6:
348
- st.info("Press Ctrl and move the left mouse button.")
349
- else:
350
- elev_scale = 1
351
-
352
- gdf = join_attributes(gdf, inventory_df, scale.lower())
353
- gdf_null = select_null(gdf, selected_col)
354
- gdf = select_non_null(gdf, selected_col)
355
- gdf = gdf.sort_values(by=selected_col, ascending=True)
356
-
357
- colors = cm.get_palette(palette, n_colors)
358
- colors = [hex_to_rgb(c) for c in colors]
359
-
360
- for i, ind in enumerate(gdf.index):
361
- index = int(i / (len(gdf) / len(colors)))
362
- if index >= len(colors):
363
- index = len(colors) - 1
364
- gdf.loc[ind, "R"] = colors[index][0]
365
- gdf.loc[ind, "G"] = colors[index][1]
366
- gdf.loc[ind, "B"] = colors[index][2]
367
-
368
- initial_view_state = pdk.ViewState(
369
- latitude=40,
370
- longitude=-100,
371
- zoom=3,
372
- max_zoom=16,
373
- pitch=0,
374
- bearing=0,
375
- height=900,
376
- width=None,
377
- )
378
-
379
- min_value = gdf[selected_col].min()
380
- max_value = gdf[selected_col].max()
381
- color = "color"
382
- # color_exp = f"[({selected_col}-{min_value})/({max_value}-{min_value})*255, 0, 0]"
383
- color_exp = f"[R, G, B]"
384
-
385
- geojson = pdk.Layer(
386
- "GeoJsonLayer",
387
- gdf,
388
- pickable=True,
389
- opacity=0.5,
390
- stroked=True,
391
- filled=True,
392
- extruded=show_3d,
393
- wireframe=True,
394
- get_elevation=f"{selected_col}",
395
- elevation_scale=elev_scale,
396
- # get_fill_color="color",
397
- get_fill_color=color_exp,
398
- get_line_color=[0, 0, 0],
399
- get_line_width=2,
400
- line_width_min_pixels=1,
401
- )
402
-
403
- geojson_null = pdk.Layer(
404
- "GeoJsonLayer",
405
- gdf_null,
406
- pickable=True,
407
- opacity=0.2,
408
- stroked=True,
409
- filled=True,
410
- extruded=False,
411
- wireframe=True,
412
- # get_elevation="properties.ALAND/100000",
413
- # get_fill_color="color",
414
- get_fill_color=[200, 200, 200],
415
- get_line_color=[0, 0, 0],
416
- get_line_width=2,
417
- line_width_min_pixels=1,
418
- )
419
-
420
- # tooltip = {"text": "Name: {NAME}"}
421
-
422
- # tooltip_value = f"<b>Value:</b> {median_listing_price}""
423
- tooltip = {
424
- "html": "<b>Name:</b> {NAME}<br><b>Value:</b> {"
425
- + selected_col
426
- + "}<br><b>Date:</b> "
427
- + selected_period
428
- + "",
429
- "style": {"backgroundColor": "steelblue", "color": "white"},
430
- }
431
-
432
- layers = [geojson]
433
- if show_nodata:
434
- layers.append(geojson_null)
435
-
436
- r = pdk.Deck(
437
- layers=layers,
438
- initial_view_state=initial_view_state,
439
- map_style="light",
440
- tooltip=tooltip,
441
- )
442
-
443
- row3_col1, row3_col2 = st.columns([6, 1])
444
-
445
- with row3_col1:
446
- st.pydeck_chart(r)
447
- with row3_col2:
448
- st.write(
449
- cm.create_colormap(
450
- palette,
451
- label=selected_col.replace("_", " ").title(),
452
- width=0.2,
453
- height=3,
454
- orientation="vertical",
455
- vmin=min_value,
456
- vmax=max_value,
457
- font_size=10,
458
- )
459
- )
460
- row4_col1, row4_col2, row4_col3 = st.columns([1, 2, 3])
461
- with row4_col1:
462
- show_data = st.checkbox("Show raw data")
463
- with row4_col2:
464
- show_cols = st.multiselect("Select columns", data_cols)
465
- with row4_col3:
466
- show_colormaps = st.checkbox("Preview all color palettes")
467
- if show_colormaps:
468
- st.write(cm.plot_colormaps(return_fig=True))
469
- if show_data:
470
- if scale == "National":
471
- st.dataframe(gdf[["NAME", "GEOID"] + show_cols])
472
- elif scale == "State":
473
- st.dataframe(gdf[["NAME", "STUSPS"] + show_cols])
474
- elif scale == "County":
475
- st.dataframe(gdf[["NAME", "STATEFP", "COUNTYFP"] + show_cols])
476
- elif scale == "Metro":
477
- st.dataframe(gdf[["NAME", "CBSAFP"] + show_cols])
478
- elif scale == "Zip":
479
- st.dataframe(gdf[["GEOID10"] + show_cols])
480
-
481
-
482
- app()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/{4_🔥_Heatmap.py → 2_🔥_Heatmap.py} RENAMED
@@ -5,15 +5,15 @@ st.set_page_config(layout="wide")
5
 
6
  st.sidebar.info(
7
  """
8
- - Web App URL: <https://streamlit.gishub.org>
9
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
10
  """
11
  )
12
 
13
  st.sidebar.title("Contact")
14
  st.sidebar.info(
15
  """
16
- 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)
17
  """
18
  )
19
 
@@ -21,10 +21,10 @@ st.title("Heatmap")
21
 
22
  with st.expander("See source code"):
23
  with st.echo():
24
- filepath = "https://raw.githubusercontent.com/giswqs/leafmap/master/examples/data/us_cities.csv"
25
- m = leafmap.Map(center=[40, -100], zoom=4, tiles="stamentoner")
26
  m.add_heatmap(
27
- filepath,
28
  latitude="latitude",
29
  longitude="longitude",
30
  value="pop_max",
 
5
 
6
  st.sidebar.info(
7
  """
8
+ - Web App URL: <https://huggingface.co/spaces/yunusserhat/Crime-Map>
9
+ - HuggingFace repository: <https://huggingface.co/spaces/yunusserhat/Crime-Map/tree/main>
10
  """
11
  )
12
 
13
  st.sidebar.title("Contact")
14
  st.sidebar.info(
15
  """
16
+ Yunus Serhat Bıçakçı at [yunusserhat.com](https://yunusserhat.com) | [GitHub](https://github.com/yunusserhat) | [Twitter](https://twitter.com/yunusserhat) | [LinkedIn](https://www.linkedin.com/in/yunusserhat)
17
  """
18
  )
19
 
 
21
 
22
  with st.expander("See source code"):
23
  with st.echo():
24
+ tweets = "https://raw.githubusercontent.com/giswqs/leafmap/master/examples/data/us_cities.csv"
25
+ m = leafmap.Map(center=[51.50, -0.1], zoom=10, tiles="stamentoner")
26
  m.add_heatmap(
27
+ tweets,
28
  latitude="latitude",
29
  longitude="longitude",
30
  value="pop_max",
pages/3_🪟_Split_Map.py DELETED
@@ -1,30 +0,0 @@
1
- import streamlit as st
2
- import leafmap.foliumap as leafmap
3
-
4
- st.set_page_config(layout="wide")
5
-
6
- st.sidebar.info(
7
- """
8
- - Web App URL: <https://streamlit.gishub.org>
9
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
10
- """
11
- )
12
-
13
- st.sidebar.title("Contact")
14
- st.sidebar.info(
15
- """
16
- 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)
17
- """
18
- )
19
-
20
- st.title("Split-panel Map")
21
-
22
- with st.expander("See source code"):
23
- with st.echo():
24
- m = leafmap.Map()
25
- m.split_map(
26
- left_layer='ESA WorldCover 2020 S2 FCC', right_layer='ESA WorldCover 2020'
27
- )
28
- m.add_legend(title='ESA Land Cover', builtin_legend='ESA_WorldCover')
29
-
30
- m.to_streamlit(height=700)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/6_🗺️_Basemaps.py DELETED
@@ -1,63 +0,0 @@
1
- import streamlit as st
2
- import leafmap.foliumap as leafmap
3
-
4
- st.set_page_config(layout="wide")
5
-
6
- st.sidebar.info(
7
- """
8
- - Web App URL: <https://streamlit.gishub.org>
9
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
10
- """
11
- )
12
-
13
- st.sidebar.title("Contact")
14
- st.sidebar.info(
15
- """
16
- 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)
17
- """
18
- )
19
-
20
-
21
- def app():
22
- st.title("Search Basemaps")
23
- st.markdown(
24
- """
25
- This app is a demonstration of searching and loading basemaps from [xyzservices](https://github.com/geopandas/xyzservices) and [Quick Map Services (QMS)](https://github.com/nextgis/quickmapservices). Selecting from 1000+ basemaps with a few clicks.
26
- """
27
- )
28
-
29
- with st.expander("See demo"):
30
- st.image("https://i.imgur.com/0SkUhZh.gif")
31
-
32
- row1_col1, row1_col2 = st.columns([3, 1])
33
- width = 800
34
- height = 600
35
- tiles = None
36
-
37
- with row1_col2:
38
-
39
- checkbox = st.checkbox("Search Quick Map Services (QMS)")
40
- keyword = st.text_input("Enter a keyword to search and press Enter:")
41
- empty = st.empty()
42
-
43
- if keyword:
44
- options = leafmap.search_xyz_services(keyword=keyword)
45
- if checkbox:
46
- qms = leafmap.search_qms(keyword=keyword)
47
- if qms is not None:
48
- options = options + qms
49
-
50
- tiles = empty.multiselect(
51
- "Select XYZ tiles to add to the map:", options)
52
-
53
- with row1_col1:
54
- m = leafmap.Map()
55
-
56
- if tiles is not None:
57
- for tile in tiles:
58
- m.add_xyz_service(tile)
59
-
60
- m.to_streamlit(height=height)
61
-
62
-
63
- app()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/7_📦_Web_Map_Service.py DELETED
@@ -1,87 +0,0 @@
1
- import ast
2
- import streamlit as st
3
- import leafmap.foliumap as leafmap
4
-
5
- st.set_page_config(layout="wide")
6
-
7
- st.sidebar.info(
8
- """
9
- - Web App URL: <https://streamlit.gishub.org>
10
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
11
- """
12
- )
13
-
14
- st.sidebar.title("Contact")
15
- st.sidebar.info(
16
- """
17
- 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)
18
- """
19
- )
20
-
21
-
22
- @st.cache(allow_output_mutation=True)
23
- def get_layers(url):
24
- options = leafmap.get_wms_layers(url)
25
- return options
26
-
27
-
28
- def app():
29
- st.title("Web Map Service (WMS)")
30
- st.markdown(
31
- """
32
- This app is a demonstration of loading Web Map Service (WMS) layers. Simply enter the URL of the WMS service
33
- in the text box below and press Enter to retrieve the layers. Go to https://apps.nationalmap.gov/services to find
34
- some WMS URLs if needed.
35
- """
36
- )
37
-
38
- row1_col1, row1_col2 = st.columns([3, 1.3])
39
- width = 800
40
- height = 600
41
- layers = None
42
-
43
- with row1_col2:
44
-
45
- esa_landcover = "https://services.terrascope.be/wms/v2"
46
- url = st.text_input(
47
- "Enter a WMS URL:", value="https://services.terrascope.be/wms/v2"
48
- )
49
- empty = st.empty()
50
-
51
- if url:
52
- options = get_layers(url)
53
-
54
- default = None
55
- if url == esa_landcover:
56
- default = "WORLDCOVER_2020_MAP"
57
- layers = empty.multiselect(
58
- "Select WMS layers to add to the map:", options, default=default
59
- )
60
- add_legend = st.checkbox("Add a legend to the map", value=True)
61
- if default == "WORLDCOVER_2020_MAP":
62
- legend = str(leafmap.builtin_legends["ESA_WorldCover"])
63
- else:
64
- legend = ""
65
- if add_legend:
66
- legend_text = st.text_area(
67
- "Enter a legend as a dictionary {label: color}",
68
- value=legend,
69
- height=200,
70
- )
71
-
72
- with row1_col1:
73
- m = leafmap.Map(center=(36.3, 0), zoom=2)
74
-
75
- if layers is not None:
76
- for layer in layers:
77
- m.add_wms_layer(
78
- url, layers=layer, name=layer, attribution=" ", transparent=True
79
- )
80
- if add_legend and legend_text:
81
- legend_dict = ast.literal_eval(legend_text)
82
- m.add_legend(legend_dict=legend_dict)
83
-
84
- m.to_streamlit(height=height)
85
-
86
-
87
- app()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/8_🏜️_Raster_Data_Visualization.py DELETED
@@ -1,106 +0,0 @@
1
- import os
2
- import leafmap.foliumap as leafmap
3
- import leafmap.colormaps as cm
4
- import streamlit as st
5
-
6
- st.set_page_config(layout="wide")
7
-
8
- st.sidebar.info(
9
- """
10
- - Web App URL: <https://streamlit.gishub.org>
11
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
12
- """
13
- )
14
-
15
- st.sidebar.title("Contact")
16
- st.sidebar.info(
17
- """
18
- 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)
19
- """
20
- )
21
-
22
-
23
- @st.cache(allow_output_mutation=True)
24
- def load_cog_list():
25
- print(os.getcwd())
26
- in_txt = os.path.join(os.getcwd(), "data/cog_files.txt")
27
- with open(in_txt) as f:
28
- return [line.strip() for line in f.readlines()[1:]]
29
-
30
-
31
- @st.cache(allow_output_mutation=True)
32
- def get_palettes():
33
- return list(cm.palettes.keys())
34
- # palettes = dir(palettable.matplotlib)[:-16]
35
- # return ["matplotlib." + p for p in palettes]
36
-
37
-
38
- st.title("Visualize Raster Datasets")
39
- st.markdown(
40
- """
41
- An interactive web app for visualizing local raster datasets and Cloud Optimized GeoTIFF ([COG](https://www.cogeo.org)). The app was built using [streamlit](https://streamlit.io), [leafmap](https://leafmap.org), and [Titiler](https://developmentseed.org/titiler/).
42
-
43
-
44
- """
45
- )
46
-
47
- row1_col1, row1_col2 = st.columns([2, 1])
48
-
49
- with row1_col1:
50
- cog_list = load_cog_list()
51
- cog = st.selectbox("Select a sample Cloud Opitmized GeoTIFF (COG)", cog_list)
52
-
53
- with row1_col2:
54
- empty = st.empty()
55
-
56
- url = empty.text_input(
57
- "Enter a HTTP URL to a Cloud Optimized GeoTIFF (COG)",
58
- cog,
59
- )
60
-
61
- if url:
62
- try:
63
- options = leafmap.cog_bands(url)
64
- except Exception as e:
65
- st.error(e)
66
- if len(options) > 3:
67
- default = options[:3]
68
- else:
69
- default = options[0]
70
- bands = st.multiselect("Select bands to display", options, default=options)
71
-
72
- if len(bands) == 1 or len(bands) == 3:
73
- pass
74
- else:
75
- st.error("Please select one or three bands")
76
-
77
- add_params = st.checkbox("Add visualization parameters")
78
- if add_params:
79
- vis_params = st.text_area("Enter visualization parameters", "{}")
80
- else:
81
- vis_params = {}
82
-
83
- if len(vis_params) > 0:
84
- try:
85
- vis_params = eval(vis_params)
86
- except Exception as e:
87
- st.error(
88
- f"Invalid visualization parameters. It should be a dictionary. Error: {e}"
89
- )
90
- vis_params = {}
91
-
92
- submit = st.button("Submit")
93
-
94
- m = leafmap.Map(latlon_control=False)
95
-
96
- if submit:
97
- if url:
98
- try:
99
- m.add_cog_layer(url, bands=bands, **vis_params)
100
- except Exception as e:
101
- with row1_col2:
102
- st.error(e)
103
- st.error("Work in progress. Try it again later.")
104
-
105
- with row1_col1:
106
- m.to_streamlit()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/9_🔲_Vector_Data_Visualization.py DELETED
@@ -1,117 +0,0 @@
1
- import os
2
- import fiona
3
- import geopandas as gpd
4
- import streamlit as st
5
-
6
- st.set_page_config(layout="wide")
7
-
8
- st.sidebar.info(
9
- """
10
- - Web App URL: <https://streamlit.gishub.org>
11
- - GitHub repository: <https://github.com/giswqs/streamlit-geospatial>
12
- """
13
- )
14
-
15
- st.sidebar.title("Contact")
16
- st.sidebar.info(
17
- """
18
- 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)
19
- """
20
- )
21
-
22
-
23
- def save_uploaded_file(file_content, file_name):
24
- """
25
- Save the uploaded file to a temporary directory
26
- """
27
- import tempfile
28
- import os
29
- import uuid
30
-
31
- _, file_extension = os.path.splitext(file_name)
32
- file_id = str(uuid.uuid4())
33
- file_path = os.path.join(tempfile.gettempdir(), f"{file_id}{file_extension}")
34
-
35
- with open(file_path, "wb") as file:
36
- file.write(file_content.getbuffer())
37
-
38
- return file_path
39
-
40
-
41
- def app():
42
-
43
- st.title("Upload Vector Data")
44
-
45
- row1_col1, row1_col2 = st.columns([2, 1])
46
- width = 950
47
- height = 600
48
-
49
- with row1_col2:
50
-
51
- backend = st.selectbox(
52
- "Select a plotting backend", ["folium", "kepler.gl", "pydeck"], index=2
53
- )
54
-
55
- if backend == "folium":
56
- import leafmap.foliumap as leafmap
57
- elif backend == "kepler.gl":
58
- import leafmap.kepler as leafmap
59
- elif backend == "pydeck":
60
- import leafmap.deck as leafmap
61
-
62
- url = st.text_input(
63
- "Enter a URL to a vector dataset",
64
- "https://github.com/giswqs/streamlit-geospatial/raw/master/data/us_states.geojson",
65
- )
66
-
67
- data = st.file_uploader(
68
- "Upload a vector dataset", type=["geojson", "kml", "zip", "tab"]
69
- )
70
-
71
- container = st.container()
72
-
73
- if data or url:
74
- if data:
75
- file_path = save_uploaded_file(data, data.name)
76
- layer_name = os.path.splitext(data.name)[0]
77
- elif url:
78
- file_path = url
79
- layer_name = url.split("/")[-1].split(".")[0]
80
-
81
- with row1_col1:
82
- if file_path.lower().endswith(".kml"):
83
- fiona.drvsupport.supported_drivers["KML"] = "rw"
84
- gdf = gpd.read_file(file_path, driver="KML")
85
- else:
86
- gdf = gpd.read_file(file_path)
87
- lon, lat = leafmap.gdf_centroid(gdf)
88
- if backend == "pydeck":
89
-
90
- column_names = gdf.columns.values.tolist()
91
- random_column = None
92
- with container:
93
- random_color = st.checkbox("Apply random colors", True)
94
- if random_color:
95
- random_column = st.selectbox(
96
- "Select a column to apply random colors", column_names
97
- )
98
-
99
- m = leafmap.Map(center=(lat, lon))
100
- m.add_gdf(gdf, random_color_column=random_column)
101
- st.pydeck_chart(m)
102
-
103
- else:
104
- m = leafmap.Map(center=(lat, lon), draw_export=True)
105
- m.add_gdf(gdf, layer_name=layer_name)
106
- # m.add_vector(file_path, layer_name=layer_name)
107
- if backend == "folium":
108
- m.zoom_to_gdf(gdf)
109
- m.to_streamlit(width=width, height=height)
110
-
111
- else:
112
- with row1_col1:
113
- m = leafmap.Map()
114
- st.pydeck_chart(m)
115
-
116
-
117
- app()