merge into single app
Browse files- .gitignore +1 -0
- Esri_XML_to_wayback_csv.ipynb +319 -0
- app.py +267 -496
- functions.py +358 -0
- wayback.csv +176 -0
- wayback.parquet +3 -0
.gitignore
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
*.pyc
|
Esri_XML_to_wayback_csv.ipynb
ADDED
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 8,
|
6 |
+
"metadata": {},
|
7 |
+
"outputs": [],
|
8 |
+
"source": [
|
9 |
+
"import xml.etree.ElementTree as ET\n",
|
10 |
+
"import requests\n",
|
11 |
+
"import csv"
|
12 |
+
]
|
13 |
+
},
|
14 |
+
{
|
15 |
+
"cell_type": "code",
|
16 |
+
"execution_count": 9,
|
17 |
+
"metadata": {},
|
18 |
+
"outputs": [],
|
19 |
+
"source": [
|
20 |
+
"xml_url = \"https://wayback.maptiles.arcgis.com/arcgis/rest/services/world_imagery/mapserver/wmts/1.0.0/wmtscapabilities.xml\""
|
21 |
+
]
|
22 |
+
},
|
23 |
+
{
|
24 |
+
"cell_type": "code",
|
25 |
+
"execution_count": 10,
|
26 |
+
"metadata": {},
|
27 |
+
"outputs": [],
|
28 |
+
"source": [
|
29 |
+
"# parse the xml\n",
|
30 |
+
"xml = requests.get(xml_url).text\n",
|
31 |
+
"root = ET.fromstring(xml)"
|
32 |
+
]
|
33 |
+
},
|
34 |
+
{
|
35 |
+
"cell_type": "code",
|
36 |
+
"execution_count": 12,
|
37 |
+
"metadata": {},
|
38 |
+
"outputs": [],
|
39 |
+
"source": [
|
40 |
+
"# Namespace definitions\n",
|
41 |
+
"namespaces = {\n",
|
42 |
+
" 'ows': 'https://www.opengis.net/ows/1.1',\n",
|
43 |
+
" '': 'https://www.opengis.net/wmts/1.0' # Default namespace\n",
|
44 |
+
"}\n",
|
45 |
+
"\n",
|
46 |
+
"# Open CSV file for writing\n",
|
47 |
+
"with open('wayback.csv', 'w', newline='') as csv_file:\n",
|
48 |
+
" writer = csv.writer(csv_file)\n",
|
49 |
+
"\n",
|
50 |
+
" # Write header row\n",
|
51 |
+
" writer.writerow([\n",
|
52 |
+
" 'Title', \n",
|
53 |
+
" 'Identifier', \n",
|
54 |
+
" 'LowerCorner', \n",
|
55 |
+
" 'UpperCorner', \n",
|
56 |
+
" 'Format', \n",
|
57 |
+
" 'TileMatrixSetLinks', \n",
|
58 |
+
" 'ResourceURL_Template'\n",
|
59 |
+
" ])\n",
|
60 |
+
"\n",
|
61 |
+
" # Extract and write data\n",
|
62 |
+
" for layer in root.findall('.//Layer', namespaces):\n",
|
63 |
+
" title = layer.find('ows:Title', namespaces).text\n",
|
64 |
+
" identifier = layer.find('ows:Identifier', namespaces).text\n",
|
65 |
+
"\n",
|
66 |
+
" bounding_box = layer.find('ows:BoundingBox/ows:LowerCorner', namespaces)\n",
|
67 |
+
" lower_corner = bounding_box.text if bounding_box is not None else ''\n",
|
68 |
+
"\n",
|
69 |
+
" bounding_box = layer.find('ows:BoundingBox/ows:UpperCorner', namespaces)\n",
|
70 |
+
" upper_corner = bounding_box.text if bounding_box is not None else ''\n",
|
71 |
+
"\n",
|
72 |
+
" fmt = layer.find('Format', namespaces).text if layer.find('Format', namespaces) else ''\n",
|
73 |
+
"\n",
|
74 |
+
" tile_matrix_links = [tms.text for tms in layer.findall('TileMatrixSetLink/TileMatrixSet', namespaces)]\n",
|
75 |
+
" tile_matrix_set_links = ', '.join(tile_matrix_links)\n",
|
76 |
+
"\n",
|
77 |
+
" resource_url = layer.find('ResourceURL', namespaces)\n",
|
78 |
+
" resource_url_template = resource_url.get('template') if resource_url is not None else ''\n",
|
79 |
+
"\n",
|
80 |
+
" writer.writerow([\n",
|
81 |
+
" title,\n",
|
82 |
+
" identifier,\n",
|
83 |
+
" lower_corner,\n",
|
84 |
+
" upper_corner,\n",
|
85 |
+
" fmt,\n",
|
86 |
+
" tile_matrix_set_links,\n",
|
87 |
+
" resource_url_template\n",
|
88 |
+
" ])"
|
89 |
+
]
|
90 |
+
},
|
91 |
+
{
|
92 |
+
"cell_type": "markdown",
|
93 |
+
"metadata": {},
|
94 |
+
"source": [
|
95 |
+
"# Parse dates"
|
96 |
+
]
|
97 |
+
},
|
98 |
+
{
|
99 |
+
"cell_type": "code",
|
100 |
+
"execution_count": 1,
|
101 |
+
"metadata": {},
|
102 |
+
"outputs": [
|
103 |
+
{
|
104 |
+
"data": {
|
105 |
+
"text/html": [
|
106 |
+
"<div>\n",
|
107 |
+
"<style scoped>\n",
|
108 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
109 |
+
" vertical-align: middle;\n",
|
110 |
+
" }\n",
|
111 |
+
"\n",
|
112 |
+
" .dataframe tbody tr th {\n",
|
113 |
+
" vertical-align: top;\n",
|
114 |
+
" }\n",
|
115 |
+
"\n",
|
116 |
+
" .dataframe thead th {\n",
|
117 |
+
" text-align: right;\n",
|
118 |
+
" }\n",
|
119 |
+
"</style>\n",
|
120 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
121 |
+
" <thead>\n",
|
122 |
+
" <tr style=\"text-align: right;\">\n",
|
123 |
+
" <th></th>\n",
|
124 |
+
" <th>Title</th>\n",
|
125 |
+
" <th>Identifier</th>\n",
|
126 |
+
" <th>LowerCorner</th>\n",
|
127 |
+
" <th>UpperCorner</th>\n",
|
128 |
+
" <th>Format</th>\n",
|
129 |
+
" <th>TileMatrixSetLinks</th>\n",
|
130 |
+
" <th>ResourceURL_Template</th>\n",
|
131 |
+
" </tr>\n",
|
132 |
+
" </thead>\n",
|
133 |
+
" <tbody>\n",
|
134 |
+
" <tr>\n",
|
135 |
+
" <th>0</th>\n",
|
136 |
+
" <td>World Imagery (Wayback 2024-10-10)</td>\n",
|
137 |
+
" <td>WB_2024_R11</td>\n",
|
138 |
+
" <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
|
139 |
+
" <td>2.003750722959434E7 2.003750722959434E7</td>\n",
|
140 |
+
" <td>NaN</td>\n",
|
141 |
+
" <td>default028mm, GoogleMapsCompatible</td>\n",
|
142 |
+
" <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
|
143 |
+
" </tr>\n",
|
144 |
+
" <tr>\n",
|
145 |
+
" <th>1</th>\n",
|
146 |
+
" <td>World Imagery (Wayback 2024-09-19)</td>\n",
|
147 |
+
" <td>WB_2024_R10</td>\n",
|
148 |
+
" <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
|
149 |
+
" <td>2.003750722959434E7 2.003750722959434E7</td>\n",
|
150 |
+
" <td>NaN</td>\n",
|
151 |
+
" <td>default028mm, GoogleMapsCompatible</td>\n",
|
152 |
+
" <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
|
153 |
+
" </tr>\n",
|
154 |
+
" </tbody>\n",
|
155 |
+
"</table>\n",
|
156 |
+
"</div>"
|
157 |
+
],
|
158 |
+
"text/plain": [
|
159 |
+
" Title Identifier \\\n",
|
160 |
+
"0 World Imagery (Wayback 2024-10-10) WB_2024_R11 \n",
|
161 |
+
"1 World Imagery (Wayback 2024-09-19) WB_2024_R10 \n",
|
162 |
+
"\n",
|
163 |
+
" LowerCorner \\\n",
|
164 |
+
"0 -2.003750722959434E7 -2.003750722959434E7 \n",
|
165 |
+
"1 -2.003750722959434E7 -2.003750722959434E7 \n",
|
166 |
+
"\n",
|
167 |
+
" UpperCorner Format \\\n",
|
168 |
+
"0 2.003750722959434E7 2.003750722959434E7 NaN \n",
|
169 |
+
"1 2.003750722959434E7 2.003750722959434E7 NaN \n",
|
170 |
+
"\n",
|
171 |
+
" TileMatrixSetLinks \\\n",
|
172 |
+
"0 default028mm, GoogleMapsCompatible \n",
|
173 |
+
"1 default028mm, GoogleMapsCompatible \n",
|
174 |
+
"\n",
|
175 |
+
" ResourceURL_Template \n",
|
176 |
+
"0 https://wayback.maptiles.arcgis.com/arcgis/res... \n",
|
177 |
+
"1 https://wayback.maptiles.arcgis.com/arcgis/res... "
|
178 |
+
]
|
179 |
+
},
|
180 |
+
"execution_count": 1,
|
181 |
+
"metadata": {},
|
182 |
+
"output_type": "execute_result"
|
183 |
+
}
|
184 |
+
],
|
185 |
+
"source": [
|
186 |
+
"import pandas as pd\n",
|
187 |
+
"\n",
|
188 |
+
"df = pd.read_csv('wayback.csv')\n",
|
189 |
+
"df.head(2)"
|
190 |
+
]
|
191 |
+
},
|
192 |
+
{
|
193 |
+
"cell_type": "code",
|
194 |
+
"execution_count": 3,
|
195 |
+
"metadata": {},
|
196 |
+
"outputs": [
|
197 |
+
{
|
198 |
+
"data": {
|
199 |
+
"text/html": [
|
200 |
+
"<div>\n",
|
201 |
+
"<style scoped>\n",
|
202 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
203 |
+
" vertical-align: middle;\n",
|
204 |
+
" }\n",
|
205 |
+
"\n",
|
206 |
+
" .dataframe tbody tr th {\n",
|
207 |
+
" vertical-align: top;\n",
|
208 |
+
" }\n",
|
209 |
+
"\n",
|
210 |
+
" .dataframe thead th {\n",
|
211 |
+
" text-align: right;\n",
|
212 |
+
" }\n",
|
213 |
+
"</style>\n",
|
214 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
215 |
+
" <thead>\n",
|
216 |
+
" <tr style=\"text-align: right;\">\n",
|
217 |
+
" <th></th>\n",
|
218 |
+
" <th>Title</th>\n",
|
219 |
+
" <th>Identifier</th>\n",
|
220 |
+
" <th>LowerCorner</th>\n",
|
221 |
+
" <th>UpperCorner</th>\n",
|
222 |
+
" <th>Format</th>\n",
|
223 |
+
" <th>TileMatrixSetLinks</th>\n",
|
224 |
+
" <th>ResourceURL_Template</th>\n",
|
225 |
+
" <th>date</th>\n",
|
226 |
+
" </tr>\n",
|
227 |
+
" </thead>\n",
|
228 |
+
" <tbody>\n",
|
229 |
+
" <tr>\n",
|
230 |
+
" <th>0</th>\n",
|
231 |
+
" <td>World Imagery (Wayback 2024-10-10)</td>\n",
|
232 |
+
" <td>WB_2024_R11</td>\n",
|
233 |
+
" <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
|
234 |
+
" <td>2.003750722959434E7 2.003750722959434E7</td>\n",
|
235 |
+
" <td>NaN</td>\n",
|
236 |
+
" <td>default028mm, GoogleMapsCompatible</td>\n",
|
237 |
+
" <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
|
238 |
+
" <td>2024-10-10</td>\n",
|
239 |
+
" </tr>\n",
|
240 |
+
" <tr>\n",
|
241 |
+
" <th>1</th>\n",
|
242 |
+
" <td>World Imagery (Wayback 2024-09-19)</td>\n",
|
243 |
+
" <td>WB_2024_R10</td>\n",
|
244 |
+
" <td>-2.003750722959434E7 -2.003750722959434E7</td>\n",
|
245 |
+
" <td>2.003750722959434E7 2.003750722959434E7</td>\n",
|
246 |
+
" <td>NaN</td>\n",
|
247 |
+
" <td>default028mm, GoogleMapsCompatible</td>\n",
|
248 |
+
" <td>https://wayback.maptiles.arcgis.com/arcgis/res...</td>\n",
|
249 |
+
" <td>2024-09-19</td>\n",
|
250 |
+
" </tr>\n",
|
251 |
+
" </tbody>\n",
|
252 |
+
"</table>\n",
|
253 |
+
"</div>"
|
254 |
+
],
|
255 |
+
"text/plain": [
|
256 |
+
" Title Identifier \\\n",
|
257 |
+
"0 World Imagery (Wayback 2024-10-10) WB_2024_R11 \n",
|
258 |
+
"1 World Imagery (Wayback 2024-09-19) WB_2024_R10 \n",
|
259 |
+
"\n",
|
260 |
+
" LowerCorner \\\n",
|
261 |
+
"0 -2.003750722959434E7 -2.003750722959434E7 \n",
|
262 |
+
"1 -2.003750722959434E7 -2.003750722959434E7 \n",
|
263 |
+
"\n",
|
264 |
+
" UpperCorner Format \\\n",
|
265 |
+
"0 2.003750722959434E7 2.003750722959434E7 NaN \n",
|
266 |
+
"1 2.003750722959434E7 2.003750722959434E7 NaN \n",
|
267 |
+
"\n",
|
268 |
+
" TileMatrixSetLinks \\\n",
|
269 |
+
"0 default028mm, GoogleMapsCompatible \n",
|
270 |
+
"1 default028mm, GoogleMapsCompatible \n",
|
271 |
+
"\n",
|
272 |
+
" ResourceURL_Template date \n",
|
273 |
+
"0 https://wayback.maptiles.arcgis.com/arcgis/res... 2024-10-10 \n",
|
274 |
+
"1 https://wayback.maptiles.arcgis.com/arcgis/res... 2024-09-19 "
|
275 |
+
]
|
276 |
+
},
|
277 |
+
"execution_count": 3,
|
278 |
+
"metadata": {},
|
279 |
+
"output_type": "execute_result"
|
280 |
+
}
|
281 |
+
],
|
282 |
+
"source": [
|
283 |
+
"df['date'] = df['Title'].str.extract(r'(\\d{4}-\\d{2}-\\d{2})')\n",
|
284 |
+
"df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')\n",
|
285 |
+
"df.head(2)"
|
286 |
+
]
|
287 |
+
},
|
288 |
+
{
|
289 |
+
"cell_type": "code",
|
290 |
+
"execution_count": 4,
|
291 |
+
"metadata": {},
|
292 |
+
"outputs": [],
|
293 |
+
"source": [
|
294 |
+
"df.to_parquet('wayback.parquet', index=False)"
|
295 |
+
]
|
296 |
+
}
|
297 |
+
],
|
298 |
+
"metadata": {
|
299 |
+
"kernelspec": {
|
300 |
+
"display_name": "zeel_py310",
|
301 |
+
"language": "python",
|
302 |
+
"name": "python3"
|
303 |
+
},
|
304 |
+
"language_info": {
|
305 |
+
"codemirror_mode": {
|
306 |
+
"name": "ipython",
|
307 |
+
"version": 3
|
308 |
+
},
|
309 |
+
"file_extension": ".py",
|
310 |
+
"mimetype": "text/x-python",
|
311 |
+
"name": "python",
|
312 |
+
"nbconvert_exporter": "python",
|
313 |
+
"pygments_lexer": "ipython3",
|
314 |
+
"version": "3.10.15"
|
315 |
+
}
|
316 |
+
},
|
317 |
+
"nbformat": 4,
|
318 |
+
"nbformat_minor": 2
|
319 |
+
}
|
app.py
CHANGED
@@ -1,41 +1,26 @@
|
|
|
|
|
|
|
|
|
|
1 |
import os
|
2 |
from datetime import datetime
|
3 |
import ee
|
4 |
import json
|
5 |
-
import geemap
|
6 |
import numpy as np
|
7 |
import geemap.foliumap as gee_folium
|
8 |
import leafmap.foliumap as leaf_folium
|
9 |
import streamlit as st
|
10 |
import pandas as pd
|
11 |
-
import geopandas as gpd
|
12 |
-
from shapely.ops import transform
|
13 |
-
from functools import reduce
|
14 |
import plotly.express as px
|
15 |
import branca.colormap as cm
|
16 |
-
import folium
|
17 |
-
import pyproj
|
18 |
-
from io import StringIO, BytesIO
|
19 |
-
import requests
|
20 |
-
import kml2geojson
|
21 |
|
22 |
-
|
23 |
-
print(folium.__version__)
|
24 |
-
print(geemap.Report())
|
25 |
|
26 |
st.set_page_config(layout="wide")
|
27 |
-
m = st.markdown(
|
28 |
-
"""
|
29 |
-
<style>
|
30 |
-
div.stButton > button:first-child {
|
31 |
-
background-color: #006400;
|
32 |
-
color:#ffffff;
|
33 |
-
}
|
34 |
-
</style>""",
|
35 |
-
unsafe_allow_html=True,
|
36 |
-
)
|
37 |
|
38 |
-
|
|
|
|
|
39 |
st.write(
|
40 |
f"""
|
41 |
<div style="display: flex; justify-content: space-between; align-items: center;">
|
@@ -46,42 +31,57 @@ st.write(
|
|
46 |
unsafe_allow_html=True,
|
47 |
)
|
48 |
|
49 |
-
|
50 |
# Title
|
51 |
-
|
|
|
52 |
st.markdown(
|
53 |
f"""
|
54 |
-
<h1 style="text-align: center;">
|
55 |
""",
|
56 |
unsafe_allow_html=True,
|
57 |
)
|
58 |
|
59 |
############################################
|
60 |
-
#
|
61 |
############################################
|
62 |
-
st.write("<h2><div style='text-align: center;'>User Inputs</div></h2>", unsafe_allow_html=True)
|
63 |
|
64 |
# Input: GeoJSON/KML file
|
65 |
file_url = st.query_params.get("file_url", None)
|
66 |
if file_url is None:
|
67 |
-
file_url = st.file_uploader("Upload KML/GeoJSON file", type=["geojson", "kml"
|
68 |
|
69 |
-
def show_credits():
|
70 |
-
# Add credits
|
71 |
-
st.write(
|
72 |
-
"""
|
73 |
-
<div style="display: flex; justify-content: center; align-items: center; margin-top: 20px;">
|
74 |
-
<p style="text-align: left;">This tool is developed by <a href="https://sustainability-lab.github.io/">Sustainability Lab</a>, <a href="https://www.iitgn.ac.in/">IIT Gandhinagar</a> and supported by <a href="https://forests.gujarat.gov.in/">Gujarat Forest Department</a></p>""",
|
75 |
-
unsafe_allow_html=True,
|
76 |
-
)
|
77 |
-
|
78 |
if file_url is None:
|
79 |
st.warning(
|
80 |
-
|
81 |
)
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
with st.expander("Advanced Settings"):
|
86 |
st.write("Select the vegetation indices to calculate:")
|
87 |
all_veg_indices = ["NDVI", "EVI", "EVI2"]
|
@@ -102,384 +102,36 @@ with st.expander("Advanced Settings"):
|
|
102 |
value = col.number_input(f"{name}", value=default)
|
103 |
evi_vars[name] = value
|
104 |
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
elif file_url.startswith("https://drive.google.com/open?id="):
|
117 |
-
ID = file_url.replace("https://drive.google.com/open?id=", "")
|
118 |
-
file_url = f"https://drive.google.com/uc?id={ID}"
|
119 |
-
|
120 |
-
response = requests.get(file_url)
|
121 |
-
bytes_data = BytesIO(response.content)
|
122 |
-
string_data = response.text
|
123 |
-
else:
|
124 |
-
bytes_data = BytesIO(file_url.getvalue())
|
125 |
-
string_data = file_url.getvalue().decode("utf-8")
|
126 |
-
|
127 |
-
if string_data.startswith("<?xml"):
|
128 |
-
geojson = kml2geojson.convert(bytes_data)
|
129 |
-
features = geojson[0]["features"]
|
130 |
-
epsg = 4326
|
131 |
-
input_gdf = gpd.GeoDataFrame.from_features(features, crs=f"EPSG:{epsg}")
|
132 |
-
else:
|
133 |
-
input_gdf = gpd.read_file(bytes_data)
|
134 |
-
|
135 |
-
return input_gdf
|
136 |
-
|
137 |
-
def find_best_epsg(geometry):
|
138 |
-
if geometry.geom_type == 'Polygon':
|
139 |
-
centroid = geometry.centroid
|
140 |
-
else:
|
141 |
-
st.error("Geometry is not Polygon !!!")
|
142 |
-
st.stop()
|
143 |
-
common_epsg_codes = [7756, #Andhra Pradesh
|
144 |
-
7757, #Arunachal Pradesh
|
145 |
-
7758, #Assam
|
146 |
-
7759, #Bihar
|
147 |
-
7760, #Delhi
|
148 |
-
7761, #Gujarat
|
149 |
-
7762, #Haryana
|
150 |
-
7763, #HimachalPradesh
|
151 |
-
7764, #JammuAndKashmir
|
152 |
-
7765, #Jharkhand
|
153 |
-
7766, #MadhyaPradesh
|
154 |
-
7767, #Maharastra
|
155 |
-
7768, #Manipur
|
156 |
-
7769, #Meghalaya
|
157 |
-
7770, #Nagaland
|
158 |
-
7772, #Orissa
|
159 |
-
7773, #Punjab
|
160 |
-
7774, #Rajasthan
|
161 |
-
7775, #UttarPradesh
|
162 |
-
7776, #Uttaranchal
|
163 |
-
7777, #A&N
|
164 |
-
7778, #Chattisgarh
|
165 |
-
7779, #Goa
|
166 |
-
7780, #Karnataka
|
167 |
-
7781, #Kerala
|
168 |
-
7782, #Lakshadweep
|
169 |
-
7783, #Mizoram
|
170 |
-
7784, #Sikkim
|
171 |
-
7785, #TamilNadu
|
172 |
-
7786, #Tripura
|
173 |
-
7787, #WestBengal
|
174 |
-
7771, #NE India
|
175 |
-
7755, #India
|
176 |
-
]
|
177 |
-
|
178 |
-
|
179 |
-
for epsg in common_epsg_codes:
|
180 |
-
crs = pyproj.CRS.from_epsg(epsg)
|
181 |
-
area_of_use = crs.area_of_use.bounds # Get the bounding box of the area of use
|
182 |
-
|
183 |
-
#check if centroid of polygon lies in teh bounds of the crs
|
184 |
-
if (area_of_use[0] <= centroid.x <= area_of_use[2]) and (area_of_use[1] <= centroid.y <= area_of_use[3]):
|
185 |
-
return epsg # Return the best suitable EPSG code
|
186 |
-
|
187 |
-
def daterange_str_to_dates(daterange_str):
|
188 |
-
start_date, end_date = daterange_str.split("-")
|
189 |
-
start_date = pd.to_datetime(start_date)
|
190 |
-
end_date = pd.to_datetime(end_date)
|
191 |
-
return start_date, end_date
|
192 |
-
|
193 |
-
|
194 |
-
def daterange_dates_to_str(start_date, end_date):
|
195 |
-
return f"{start_date.strftime('%Y/%m/%d')}-{end_date.strftime('%Y/%m/%d')}"
|
196 |
-
|
197 |
-
|
198 |
-
def daterange_str_to_year(daterange_str):
|
199 |
-
start_date, _ = daterange_str.split("-")
|
200 |
-
year = pd.to_datetime(start_date).year
|
201 |
-
return year
|
202 |
-
|
203 |
-
|
204 |
-
def shape_3d_to_2d(shape):
|
205 |
-
if shape.has_z:
|
206 |
-
return transform(lambda x, y, z: (x, y), shape)
|
207 |
-
else:
|
208 |
-
return shape
|
209 |
-
|
210 |
-
def preprocess_gdf(gdf):
|
211 |
-
gdf["geometry"] = gdf["geometry"].apply(shape_3d_to_2d)
|
212 |
-
gdf["geometry"] = gdf.buffer(0) # Fixes some invalid geometries
|
213 |
-
return gdf
|
214 |
-
|
215 |
-
def to_best_crs(gdf):
|
216 |
-
best_epsg_code = find_best_epsg(gdf["geometry"].iloc[0])
|
217 |
-
gdf = gdf.to_crs(epsg=best_epsg_code)
|
218 |
-
return gdf
|
219 |
-
|
220 |
-
def is_valid_polygon(geometry_gdf):
|
221 |
-
geometry = geometry_gdf.geometry.item()
|
222 |
-
return (geometry.type == "Polygon") and (not geometry.is_empty)
|
223 |
-
|
224 |
-
def add_geometry_to_maps(map_list, opacity=0.0):
|
225 |
-
for m in map_list:
|
226 |
-
m.add_gdf(
|
227 |
-
buffer_geometry_gdf,
|
228 |
-
layer_name="Geometry Buffer",
|
229 |
-
style_function=lambda x: {"color": "red", "fillOpacity": opacity, "fillColor": "red"},
|
230 |
-
)
|
231 |
-
m.add_gdf(
|
232 |
-
geometry_gdf,
|
233 |
-
layer_name="Geometry",
|
234 |
-
style_function=lambda x: {"color": "blue", "fillOpacity": opacity, "fillColor": "blue"},
|
235 |
-
)
|
236 |
-
|
237 |
-
|
238 |
-
def get_dem_slope_maps(buffer_ee_geometry):
|
239 |
-
# Create the map for DEM
|
240 |
-
dem_map = gee_folium.Map(controls={'scale':'bottomleft'})
|
241 |
-
dem_map.add_tile_layer(
|
242 |
-
wayback_mapping[latest_date], name=f"Esri Wayback - {latest_date.replace('-', '/')}", attribution="Esri"
|
243 |
-
)
|
244 |
-
|
245 |
-
dem_layer = ee.Image("USGS/SRTMGL1_003")
|
246 |
-
# Set the target resolution to 10 meters
|
247 |
-
target_resolution = 10
|
248 |
-
dem_layer = (
|
249 |
-
dem_layer.resample("bilinear").reproject(crs="EPSG:4326", scale=target_resolution).clip(buffer_ee_geometry)
|
250 |
-
)
|
251 |
-
|
252 |
-
# Generate contour lines using elevation thresholds
|
253 |
-
terrain = ee.Algorithms.Terrain(dem_layer)
|
254 |
-
contour_interval = 1
|
255 |
-
contours = (
|
256 |
-
terrain.select("elevation").subtract(terrain.select("elevation").mod(contour_interval)).rename("contours")
|
257 |
-
)
|
258 |
-
|
259 |
-
# Calculate the minimum and maximum values
|
260 |
-
stats = contours.reduceRegion(reducer=ee.Reducer.minMax(), scale=10, maxPixels=1e13)
|
261 |
-
max_value = stats.get("contours_max").getInfo()
|
262 |
-
min_value = stats.get("contours_min").getInfo()
|
263 |
-
vis_params = {"min": min_value, "max": max_value, "palette": ["blue", "green", "yellow", "red"]}
|
264 |
-
dem_map.addLayer(contours, vis_params, "Contours")
|
265 |
-
# Create a colormap
|
266 |
-
cmap = cm.LinearColormap(colors=vis_params["palette"], vmin=vis_params["min"], vmax=vis_params["max"])
|
267 |
-
tick_size = int((max_value-min_value)/4)
|
268 |
-
dem_map.add_legend(title="Elevation (m)",
|
269 |
-
legend_dict={'{}-{} m'.format(min_value, min_value+tick_size): '#0000FF',
|
270 |
-
'{}-{} m'.format(min_value+tick_size, min_value+2*tick_size): '#00FF00',
|
271 |
-
'{}-{} m'.format(min_value+2*tick_size, min_value+3*tick_size): '#FFFF00',
|
272 |
-
'{}-{} m'.format(min_value+3*tick_size, max_value): '#FF0000'},
|
273 |
-
position='bottomright', draggable=False)
|
274 |
-
|
275 |
-
# Create the map for Slope
|
276 |
-
slope_map = gee_folium.Map(controls={'scale':'bottomleft'})
|
277 |
-
slope_map.add_tile_layer(
|
278 |
-
wayback_mapping[latest_date], name=f"Esri Wayback - {latest_date.replace('-', '/')}", attribution="Esri"
|
279 |
)
|
|
|
|
|
|
|
|
|
|
|
280 |
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
.clip(buffer_ee_geometry)
|
287 |
-
.rename("slope")
|
288 |
-
)
|
289 |
-
# Calculate the minimum and maximum values
|
290 |
-
stats = slope_layer.reduceRegion(reducer=ee.Reducer.minMax(), scale=10, maxPixels=1e13)
|
291 |
-
max_value = int(stats.get("slope_max").getInfo())
|
292 |
-
min_value = int(stats.get("slope_min").getInfo())
|
293 |
-
vis_params = {"min": min_value, "max": max_value, "palette": ["blue", "green", "yellow", "red"]}
|
294 |
-
slope_map.addLayer(slope_layer, vis_params, "Slope Layer")
|
295 |
-
# Create a colormap
|
296 |
-
colormap = cm.LinearColormap(colors=vis_params["palette"], vmin=vis_params["min"], vmax=vis_params["max"])
|
297 |
-
tick_size=int((max_value-min_value)/4)
|
298 |
-
slope_map.add_legend(title="Slope (degrees)",
|
299 |
-
legend_dict={'{}-{} deg'.format(min_value, min_value+tick_size): '#0000FF',
|
300 |
-
'{}-{} deg'.format(min_value+tick_size, min_value+2*tick_size): '#00FF00',
|
301 |
-
'{}-{} deg'.format(min_value+2*tick_size, min_value+3*tick_size): '#FFFF00',
|
302 |
-
'{}-{} deg'.format(min_value+3*tick_size, max_value): '#FF0000'},
|
303 |
-
position='bottomright', draggable=False)
|
304 |
-
return dem_map, slope_map
|
305 |
-
|
306 |
-
|
307 |
-
def add_indices(image, nir_band, red_band, blue_band):
|
308 |
-
# Add negative cloud
|
309 |
-
neg_cloud = image.select("MSK_CLDPRB").multiply(-1).rename("Neg_MSK_CLDPRB")
|
310 |
-
nir = image.select(nir_band).divide(10000)
|
311 |
-
red = image.select(red_band).divide(10000)
|
312 |
-
blue = image.select(blue_band).divide(10000)
|
313 |
-
numerator = nir.subtract(red)
|
314 |
-
ndvi = (numerator).divide(nir.add(red)).rename("NDVI").clamp(-1, 1)
|
315 |
-
# EVI formula taken from: https://en.wikipedia.org/wiki/Enhanced_vegetation_index
|
316 |
-
|
317 |
-
denominator = nir.add(red.multiply(evi_vars["C1"])).subtract(blue.multiply(evi_vars["C2"])).add(evi_vars["L"])
|
318 |
-
evi = numerator.divide(denominator).multiply(evi_vars["G"]).rename("EVI").clamp(-1, 1)
|
319 |
-
evi2 = (
|
320 |
-
numerator.divide(nir.add(evi_vars["L"]).add(red.multiply(evi_vars["C"])))
|
321 |
-
.multiply(evi_vars["G"])
|
322 |
-
.rename("EVI2")
|
323 |
-
.clamp(-1, 1)
|
324 |
)
|
325 |
-
return image.addBands([neg_cloud, ndvi, evi, evi2])
|
326 |
-
|
327 |
-
def get_histogram(image, geometry, bins):
|
328 |
-
# Get image values as a list
|
329 |
-
values = image.reduceRegion(
|
330 |
-
reducer=ee.Reducer.toList(),
|
331 |
-
geometry=geometry,
|
332 |
-
scale=10,
|
333 |
-
maxPixels=1e13
|
334 |
-
).get('NDVI')
|
335 |
-
|
336 |
-
# Convert values to a NumPy array
|
337 |
-
values_array = np.array(values.getInfo())
|
338 |
-
|
339 |
-
# Compute the histogram on bins
|
340 |
-
hist, bin_edges = np.histogram(values_array, bins=bins)
|
341 |
-
|
342 |
-
return hist, bin_edges
|
343 |
-
|
344 |
-
|
345 |
-
def process_date(daterange, satellite, veg_indices):
|
346 |
-
start_date, end_date = daterange
|
347 |
-
daterange_str = daterange_dates_to_str(start_date, end_date)
|
348 |
-
prefix = f"Processing {satellite} - {daterange_str}"
|
349 |
-
try:
|
350 |
-
attrs = satellites[satellite]
|
351 |
-
collection = attrs["collection"]
|
352 |
-
collection = collection.filterBounds(buffer_ee_geometry)
|
353 |
-
collection = collection.filterDate(start_date, end_date)
|
354 |
-
|
355 |
-
bucket = {}
|
356 |
-
for veg_index in veg_indices:
|
357 |
-
mosaic_veg_index = collection.qualityMosaic(veg_index)
|
358 |
-
fc = geemap.zonal_stats(
|
359 |
-
mosaic_veg_index, ee_feature_collection, scale=attrs["scale"], return_fc=True
|
360 |
-
).getInfo()
|
361 |
-
mean_veg_index = fc["features"][0]["properties"][veg_index]
|
362 |
-
bucket[veg_index] = mean_veg_index
|
363 |
-
fc = geemap.zonal_stats(
|
364 |
-
mosaic_veg_index, buffer_ee_feature_collection, scale=attrs["scale"], return_fc=True
|
365 |
-
).getInfo()
|
366 |
-
buffer_mean_veg_index = fc["features"][0]["properties"][veg_index]
|
367 |
-
bucket[f"{veg_index}_buffer"] = buffer_mean_veg_index
|
368 |
-
bucket[f"{veg_index}_ratio"] = mean_veg_index / buffer_mean_veg_index
|
369 |
-
bucket[f"mosaic_{veg_index}"] = mosaic_veg_index
|
370 |
-
|
371 |
-
# Get median mosaic
|
372 |
-
bucket["mosaic_visual_max_ndvi"] = collection.qualityMosaic("NDVI")
|
373 |
-
bucket["mosaic_visual_median"] = collection.median()
|
374 |
-
bucket["image_visual_least_cloud"] = collection.sort("CLOUDY_PIXEL_PERCENTAGE").first()
|
375 |
-
|
376 |
-
if satellite == "COPERNICUS/S2_SR_HARMONIZED":
|
377 |
-
cloud_mask_probability = fc["features"][0]["properties"]["MSK_CLDPRB"] / 100
|
378 |
-
else:
|
379 |
-
cloud_mask_probability = None
|
380 |
-
bucket["Cloud (0 to 1)"] = cloud_mask_probability
|
381 |
-
result_df.loc[daterange_str, list(bucket.keys())] = list(bucket.values())
|
382 |
-
count = collection.size().getInfo()
|
383 |
-
suffix = f" - Processed {count} images"
|
384 |
-
write_info(f"{prefix}{suffix}")
|
385 |
-
except Exception as e:
|
386 |
-
print(e)
|
387 |
-
suffix = f" - Imagery not available"
|
388 |
-
write_info(f"{prefix}{suffix}")
|
389 |
-
|
390 |
-
|
391 |
-
def write_info(info):
|
392 |
-
st.write(f"<span style='color:#006400;'>{info}</span>", unsafe_allow_html=True)
|
393 |
-
|
394 |
-
|
395 |
-
############################################
|
396 |
-
# One time setup
|
397 |
-
############################################
|
398 |
-
|
399 |
-
|
400 |
-
def one_time_setup():
|
401 |
-
credentials_path = os.path.expanduser("~/.config/earthengine/credentials")
|
402 |
-
if os.path.exists(credentials_path):
|
403 |
-
pass # Earth Engine credentials already exist
|
404 |
-
elif "EE" in os.environ: # write the credentials to the file
|
405 |
-
ee_credentials = os.environ.get("EE")
|
406 |
-
os.makedirs(os.path.dirname(credentials_path), exist_ok=True)
|
407 |
-
with open(credentials_path, "w") as f:
|
408 |
-
f.write(ee_credentials)
|
409 |
-
else:
|
410 |
-
raise ValueError(
|
411 |
-
f"Earth Engine credentials not found at {credentials_path} or in the environment variable 'EE'"
|
412 |
-
)
|
413 |
-
|
414 |
-
ee.Initialize()
|
415 |
-
|
416 |
-
satellites = {
|
417 |
-
"COPERNICUS/S2_SR_HARMONIZED": {
|
418 |
-
"scale": 10,
|
419 |
-
"collection": ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")
|
420 |
-
.select(
|
421 |
-
["B2", "B4", "B8", "MSK_CLDPRB", "TCI_R", "TCI_G", "TCI_B"],
|
422 |
-
["Blue", "Red", "NIR", "MSK_CLDPRB", "R", "G", "B"],
|
423 |
-
)
|
424 |
-
.map(lambda image: add_indices(image, nir_band="NIR", red_band="Red", blue_band="Blue")),
|
425 |
-
},
|
426 |
-
}
|
427 |
-
st.session_state.satellites = satellites
|
428 |
-
with open("wayback_imagery.json") as f:
|
429 |
-
st.session_state.wayback_mapping = json.load(f)
|
430 |
-
|
431 |
-
|
432 |
-
if "one_time_setup_done" not in st.session_state:
|
433 |
-
one_time_setup()
|
434 |
-
st.session_state.one_time_setup_done = True
|
435 |
-
|
436 |
-
satellites = st.session_state.satellites
|
437 |
-
wayback_mapping = st.session_state.wayback_mapping
|
438 |
-
|
439 |
-
############################################
|
440 |
-
# App
|
441 |
-
############################################
|
442 |
-
|
443 |
-
# Input: Satellite Sources
|
444 |
-
st.markdown(f"Satellite source: `{list(satellites.keys())[0]}`")
|
445 |
-
satellite_selected = {}
|
446 |
-
for satellite in satellites:
|
447 |
-
satellite_selected[satellite] = satellite
|
448 |
-
|
449 |
-
# Date range input
|
450 |
-
max_year = datetime.now().year
|
451 |
-
jan_1 = pd.to_datetime(f"{max_year}/01/01", format="%Y/%m/%d")
|
452 |
-
dec_31 = pd.to_datetime(f"{max_year}/12/31", format="%Y/%m/%d")
|
453 |
-
nov_15 = pd.to_datetime(f"{max_year}/11/15", format="%Y/%m/%d")
|
454 |
-
dec_15 = pd.to_datetime(f"{max_year}/12/15", format="%Y/%m/%d")
|
455 |
-
input_daterange = st.date_input(
|
456 |
-
"Date Range (Ignore year. App will compute indices for this date range in each year starting from \"Minimum Year\" to \"Maximum Year\")", (nov_15, dec_15), jan_1, dec_31
|
457 |
-
)
|
458 |
-
cols = st.columns(2)
|
459 |
-
with cols[0]:
|
460 |
-
min_year = int(st.number_input("Minimum Year", value=2019, min_value=2015, step=1))
|
461 |
-
with cols[1]:
|
462 |
-
max_year = int(st.number_input("Maximum Year", value=max_year, min_value=2015, step=1))
|
463 |
-
|
464 |
-
buffer = st.number_input("Buffer (m)", value=50, min_value=0, step=1)
|
465 |
-
|
466 |
-
input_gdf = get_gdf_from_file_url(file_url)
|
467 |
-
input_gdf = preprocess_gdf(input_gdf)
|
468 |
|
469 |
if len(input_gdf) > 1:
|
470 |
st.warning(f"Only the first polygon in the KML will be processed; all other geometries will be ignored.")
|
471 |
|
472 |
# input_geometry_idx = st.selectbox("Select the geometry", input_gdf.index, format_func=format_fn)
|
473 |
|
474 |
-
for i in range(len(input_gdf)):
|
475 |
-
geometry_gdf = input_gdf[input_gdf.index == i]
|
476 |
-
if is_valid_polygon(geometry_gdf):
|
477 |
-
break
|
478 |
-
else:
|
479 |
-
st.error(f"No polygon found inside KML. Please check the KML file.")
|
480 |
-
st.stop()
|
481 |
-
|
482 |
-
geometry_gdf = to_best_crs(geometry_gdf)
|
483 |
outer_geometry_gdf = geometry_gdf.copy()
|
484 |
outer_geometry_gdf["geometry"] = outer_geometry_gdf["geometry"].buffer(buffer)
|
485 |
buffer_geometry_gdf = (
|
@@ -487,81 +139,178 @@ buffer_geometry_gdf = (
|
|
487 |
) # reset index forces GeoSeries to GeoDataFrame
|
488 |
buffer_geometry_gdf["Name"] = "Buffer"
|
489 |
|
490 |
-
# Derived Inputs
|
491 |
-
ee_geometry = ee.Geometry(geometry_gdf.to_crs(4326).geometry.item().__geo_interface__)
|
492 |
-
ee_feature_collection = ee.FeatureCollection(ee_geometry)
|
493 |
-
buffer_ee_geometry = ee.Geometry(buffer_geometry_gdf.to_crs(4326).geometry.item().__geo_interface__)
|
494 |
-
buffer_ee_feature_collection = ee.FeatureCollection(buffer_ee_geometry)
|
495 |
-
outer_ee_geometry = ee.Geometry(outer_geometry_gdf.to_crs(4326).geometry.item().__geo_interface__)
|
496 |
-
outer_ee_feature_collection = ee.FeatureCollection(outer_ee_geometry)
|
497 |
-
|
498 |
# visualize the geometry
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
|
|
|
|
|
|
|
|
504 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
505 |
# m.add_layer(buffer_ee_feature_collection)
|
506 |
-
add_geometry_to_maps([m], opacity=0.3)
|
507 |
-
write_info(
|
508 |
-
|
509 |
-
<div style="text-align: center;">
|
510 |
-
|
511 |
-
</div>
|
512 |
-
"""
|
513 |
-
)
|
514 |
m.to_streamlit()
|
515 |
|
516 |
# Generate stats
|
|
|
|
|
|
|
517 |
stats_df = pd.DataFrame(
|
518 |
{
|
519 |
"Area (m^2)": geometry_gdf.area.item(),
|
520 |
"Perimeter (m)": geometry_gdf.length.item(),
|
521 |
"Points": str(json.loads(geometry_gdf.to_crs(4326).to_json())["features"][0]["geometry"]["coordinates"]),
|
522 |
-
|
|
|
|
|
523 |
)
|
524 |
-
|
525 |
-
|
526 |
-
# f"""| Metric | Value |
|
527 |
-
# | --- | --- |
|
528 |
-
# | Area (m^2) | {stats_df['Area (m^2)'].item():.2f} m^2 = {stats_df['Area (m^2)'].item()/10000:.2f} ha |
|
529 |
-
# | Perimeter (m) | {stats_df['Perimeter (m)'].item():.2f} m |
|
530 |
-
# """
|
531 |
-
# )
|
532 |
st.markdown(
|
533 |
f"""
|
534 |
<div style="display: flex; justify-content: center;">
|
535 |
-
<table style="border-collapse: collapse;
|
536 |
<tr>
|
537 |
-
<th style="border: 1px solid black;
|
538 |
-
<th style="border: 1px solid black;
|
|
|
539 |
</tr>
|
540 |
<tr>
|
541 |
-
<td style="border: 1px solid black;
|
542 |
-
<td style="border: 1px solid black;
|
|
|
543 |
</tr>
|
544 |
<tr>
|
545 |
-
<td style="border: 1px solid black;
|
546 |
-
<td style="border: 1px solid black;
|
|
|
547 |
</tr>
|
|
|
|
|
|
|
|
|
548 |
</table>
|
549 |
</div>
|
|
|
|
|
|
|
|
|
|
|
550 |
""",
|
551 |
-
unsafe_allow_html=True
|
552 |
)
|
553 |
|
554 |
stats_csv = stats_df.to_csv(index=False)
|
555 |
st.download_button("Download Geometry Metrics", stats_csv, "geometry_metrics.csv", "text/csv", use_container_width=True)
|
556 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
557 |
# Submit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
558 |
submit = st.button("Calculate Vegetation Indices", use_container_width=True)
|
559 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
560 |
if submit:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
561 |
st.write("<h2><div style='text-align: center;'>Results</div></h2>", unsafe_allow_html=True)
|
562 |
if not any(satellite_selected.values()):
|
563 |
st.error("Please select at least one satellite source")
|
564 |
-
|
565 |
|
566 |
# Create range
|
567 |
start_day = input_daterange[0].day
|
@@ -583,7 +332,16 @@ if submit:
|
|
583 |
with st.spinner(f"Processing {satellite} ..."):
|
584 |
progress_bar = st.progress(0)
|
585 |
for i, daterange in enumerate(dates):
|
586 |
-
process_date(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
587 |
progress_bar.progress((i + 1) / len(dates))
|
588 |
|
589 |
st.session_state.result = result_df
|
@@ -591,6 +349,9 @@ if submit:
|
|
591 |
print("Printing result...")
|
592 |
if "result" in st.session_state:
|
593 |
result_df = st.session_state.result
|
|
|
|
|
|
|
594 |
print(result_df.columns)
|
595 |
|
596 |
# drop rows with all NaN values
|
@@ -606,8 +367,13 @@ if "result" in st.session_state:
|
|
606 |
result_df[column] = pd.to_numeric(result_df[column], errors="ignore")
|
607 |
|
608 |
df_numeric = result_df.select_dtypes(include=["float64"])
|
609 |
-
|
610 |
-
|
|
|
|
|
|
|
|
|
|
|
611 |
df_numeric_csv = df_numeric.to_csv(index=True)
|
612 |
st.download_button(
|
613 |
"Download Time Series Data", df_numeric_csv, "vegetation_indices.csv", "text/csv", use_container_width=True
|
@@ -619,23 +385,6 @@ if "result" in st.session_state:
|
|
619 |
fig.update_layout(xaxis=dict(tickvals=df_numeric.index, ticktext=df_numeric.index))
|
620 |
st.plotly_chart(fig)
|
621 |
|
622 |
-
st.write(
|
623 |
-
"<h3><div style='text-align: center;'>DEM and Slope from SRTM at 30m resolution</div></h3>",
|
624 |
-
unsafe_allow_html=True,
|
625 |
-
)
|
626 |
-
cols = st.columns(2)
|
627 |
-
dem_map, slope_map = get_dem_slope_maps(ee.Geometry(geometry_gdf.to_crs(4326).geometry.item().__geo_interface__))
|
628 |
-
for col, param_map, title in zip(cols, [dem_map, slope_map], ["DEM Map", "Slope Map"]):
|
629 |
-
with col:
|
630 |
-
param_map.add_gdf(
|
631 |
-
geometry_gdf,
|
632 |
-
layer_name="Geometry",
|
633 |
-
style_function=lambda x: {"color": "blue", "fillOpacity": 0.0, "fillColor": "blue"},
|
634 |
-
)
|
635 |
-
write_info(f"""<div style="text-align: center;">{title}</div>""")
|
636 |
-
param_map.addLayerControl()
|
637 |
-
param_map.to_streamlit()
|
638 |
-
|
639 |
st.write(
|
640 |
"<h3><div style='text-align: center;'>Visual Comparison between Two Years</div></h3>", unsafe_allow_html=True
|
641 |
)
|
@@ -660,7 +409,11 @@ if "result" in st.session_state:
|
|
660 |
mosaic = result_df.loc[daterange_str, f"mosaic_{veg_index}"]
|
661 |
with col:
|
662 |
m = gee_folium.Map()
|
663 |
-
m.add_tile_layer(
|
|
|
|
|
|
|
|
|
664 |
veg_index_layer = gee_folium.ee_tile_layer(mosaic, {"bands": [veg_index], "min": 0, "max": 1})
|
665 |
|
666 |
if satellite == "COPERNICUS/S2_SR_HARMONIZED":
|
@@ -669,34 +422,40 @@ if "result" in st.session_state:
|
|
669 |
else:
|
670 |
raise ValueError(f"Unknown satellite: {satellite}")
|
671 |
|
672 |
-
if veg_index==
|
673 |
-
bins=[-1, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 1]
|
674 |
histogram, bin_edges = get_histogram(mosaic.select(veg_index), ee_geometry, bins)
|
675 |
total_pix = np.sum(histogram)
|
676 |
formatted_histogram = [f"{h*100/total_pix:.2f}" for h in histogram]
|
677 |
print(histogram, bin_edges, bins, formatted_histogram)
|
678 |
-
m.add_legend(
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
691 |
m.add_layer(mosaic.select(veg_index).clip(outer_ee_geometry), ndvi_vis_params)
|
692 |
-
|
693 |
# add colorbar
|
694 |
# m.add_colorbar(colors=["#000000", "#00FF00"], vmin=0.0, vmax=1.0)
|
695 |
-
|
696 |
-
if veg_index!=
|
697 |
m.add_layer(mosaic.select(veg_index).clip(outer_ee_geometry), vis_params)
|
698 |
m.add_child(colormap)
|
699 |
-
add_geometry_to_maps([m])
|
700 |
m.to_streamlit()
|
701 |
|
702 |
for name, key in zip(
|
@@ -708,14 +467,13 @@ if "result" in st.session_state:
|
|
708 |
for col, daterange_str in zip(cols, [year_1, year_2]):
|
709 |
start_date, end_date = daterange_str_to_dates(daterange_str)
|
710 |
mid_date = start_date + (end_date - start_date) / 2
|
711 |
-
esri_date = min(wayback_mapping.keys(), key=lambda x: abs(pd.to_datetime(x) - mid_date))
|
712 |
with col:
|
713 |
m = gee_folium.Map()
|
714 |
visual_mosaic = result_df.loc[daterange_str, key]
|
715 |
# visual_layer = gee_folium.ee_tile_layer(mosaic, {"bands": ["R", "G", "B"], "min": min_all, "max": max_all})
|
716 |
|
717 |
m.add_layer(visual_mosaic.select(["R", "G", "B"]))
|
718 |
-
add_geometry_to_maps([m])
|
719 |
m.to_streamlit()
|
720 |
|
721 |
st.write("<h3><div style='text-align: center;'>Esri RGB Imagery</div></h3>", unsafe_allow_html=True)
|
@@ -723,18 +481,31 @@ if "result" in st.session_state:
|
|
723 |
for col, daterange_str in zip(cols, [year_1, year_2]):
|
724 |
start_date, end_date = daterange_str_to_dates(daterange_str)
|
725 |
mid_date = start_date + (end_date - start_date) / 2
|
726 |
-
esri_date = min(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
727 |
with col:
|
728 |
m = leaf_folium.Map()
|
729 |
-
m.add_tile_layer(
|
730 |
-
|
|
|
|
|
|
|
|
|
731 |
write_info(
|
732 |
f"""
|
733 |
<div style="text-align: center;">
|
734 |
-
Esri Imagery - {esri_date.
|
735 |
</div>
|
736 |
"""
|
737 |
)
|
738 |
m.to_streamlit()
|
739 |
|
740 |
-
|
|
|
|
1 |
+
##############################################
|
2 |
+
# Imports
|
3 |
+
##############################################
|
4 |
+
|
5 |
import os
|
6 |
from datetime import datetime
|
7 |
import ee
|
8 |
import json
|
|
|
9 |
import numpy as np
|
10 |
import geemap.foliumap as gee_folium
|
11 |
import leafmap.foliumap as leaf_folium
|
12 |
import streamlit as st
|
13 |
import pandas as pd
|
|
|
|
|
|
|
14 |
import plotly.express as px
|
15 |
import branca.colormap as cm
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
+
from functions import *
|
|
|
|
|
18 |
|
19 |
st.set_page_config(layout="wide")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
+
############################################
|
22 |
+
# IITGN and GDF Logo
|
23 |
+
############################################
|
24 |
st.write(
|
25 |
f"""
|
26 |
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
|
31 |
unsafe_allow_html=True,
|
32 |
)
|
33 |
|
34 |
+
############################################
|
35 |
# Title
|
36 |
+
############################################
|
37 |
+
|
38 |
st.markdown(
|
39 |
f"""
|
40 |
+
<h1 style="text-align: center;">Kamlan: KML Analyzer</h1>
|
41 |
""",
|
42 |
unsafe_allow_html=True,
|
43 |
)
|
44 |
|
45 |
############################################
|
46 |
+
# KML/GeoJSON input
|
47 |
############################################
|
|
|
48 |
|
49 |
# Input: GeoJSON/KML file
|
50 |
file_url = st.query_params.get("file_url", None)
|
51 |
if file_url is None:
|
52 |
+
file_url = st.file_uploader("Upload KML/GeoJSON file", type=["geojson", "kml"])
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
if file_url is None:
|
55 |
st.warning(
|
56 |
+
"Please provide a KML or GeoJSON URL as a query parameter, e.g., `https://sustainabilitylabiitgn-ndvi-perg.hf.space?file_url=<your_file_url>` or upload a file."
|
57 |
)
|
58 |
+
force_stop()
|
59 |
+
|
60 |
+
# process the file
|
61 |
+
|
62 |
+
if ("cached_file_url" in st.session_state) and (st.session_state.cached_file_url == file_url):
|
63 |
+
input_gdf = st.session_state.input_gdf
|
64 |
+
geometry_gdf = st.session_state.geometry_gdf
|
65 |
+
else:
|
66 |
+
input_gdf = get_gdf_from_file_url(file_url)
|
67 |
+
input_gdf = preprocess_gdf(input_gdf)
|
68 |
+
|
69 |
+
for i in range(len(input_gdf)):
|
70 |
+
geometry_gdf = input_gdf[input_gdf.index == i]
|
71 |
+
if is_valid_polygon(geometry_gdf):
|
72 |
+
break
|
73 |
+
else:
|
74 |
+
st.error(f"No polygon found inside KML. Please check the KML file.")
|
75 |
+
force_stop()
|
76 |
|
77 |
+
geometry_gdf = to_best_crs(geometry_gdf)
|
78 |
+
st.session_state.input_gdf = input_gdf
|
79 |
+
st.session_state.geometry_gdf = geometry_gdf
|
80 |
+
st.session_state.cached_file_url = file_url
|
81 |
+
|
82 |
+
############################################
|
83 |
+
# App
|
84 |
+
############################################
|
85 |
with st.expander("Advanced Settings"):
|
86 |
st.write("Select the vegetation indices to calculate:")
|
87 |
all_veg_indices = ["NDVI", "EVI", "EVI2"]
|
|
|
102 |
value = col.number_input(f"{name}", value=default)
|
103 |
evi_vars[name] = value
|
104 |
|
105 |
+
# Date range input
|
106 |
+
max_year = datetime.now().year
|
107 |
+
jan_1 = pd.to_datetime(f"{max_year}/01/01", format="%Y/%m/%d")
|
108 |
+
dec_31 = pd.to_datetime(f"{max_year}/12/31", format="%Y/%m/%d")
|
109 |
+
nov_15 = pd.to_datetime(f"{max_year}/11/15", format="%Y/%m/%d")
|
110 |
+
dec_15 = pd.to_datetime(f"{max_year}/12/15", format="%Y/%m/%d")
|
111 |
+
input_daterange = st.date_input(
|
112 |
+
'Date Range (Ignore year. App will compute indices for this date range in each year starting from "Minimum Year" to "Maximum Year")',
|
113 |
+
(nov_15, dec_15),
|
114 |
+
jan_1,
|
115 |
+
dec_31,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
)
|
117 |
+
cols = st.columns(2)
|
118 |
+
with cols[0]:
|
119 |
+
min_year = int(st.number_input("Minimum Year", value=2019, min_value=2015, step=1))
|
120 |
+
with cols[1]:
|
121 |
+
max_year = int(st.number_input("Maximum Year", value=max_year, min_value=2015, step=1))
|
122 |
|
123 |
+
buffer = st.number_input("Buffer (m)", value=50, min_value=0, step=1)
|
124 |
+
map_type = st.radio(
|
125 |
+
"",
|
126 |
+
["Esri Satellite Map", "Google Hybrid Map (displays place names)", "Google Satellite Map"],
|
127 |
+
horizontal=True,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
|
130 |
if len(input_gdf) > 1:
|
131 |
st.warning(f"Only the first polygon in the KML will be processed; all other geometries will be ignored.")
|
132 |
|
133 |
# input_geometry_idx = st.selectbox("Select the geometry", input_gdf.index, format_func=format_fn)
|
134 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
outer_geometry_gdf = geometry_gdf.copy()
|
136 |
outer_geometry_gdf["geometry"] = outer_geometry_gdf["geometry"].buffer(buffer)
|
137 |
buffer_geometry_gdf = (
|
|
|
139 |
) # reset index forces GeoSeries to GeoDataFrame
|
140 |
buffer_geometry_gdf["Name"] = "Buffer"
|
141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
# visualize the geometry
|
143 |
+
wayback_df = pd.read_parquet("./wayback.parquet").set_index("date")
|
144 |
+
first_item = wayback_df.iloc[0]
|
145 |
+
wayback_title = "Esri " + first_item["Title"]
|
146 |
+
wayback_url = (
|
147 |
+
first_item["ResourceURL_Template"]
|
148 |
+
.replace("{TileMatrixSet}", "GoogleMapsCompatible")
|
149 |
+
.replace("{TileMatrix}", "{z}")
|
150 |
+
.replace("{TileRow}", "{y}")
|
151 |
+
.replace("{TileCol}", "{x}")
|
152 |
)
|
153 |
+
# print(wayback_url)
|
154 |
+
|
155 |
+
m = leaf_folium.Map()
|
156 |
+
if map_type == "Google Hybrid Map (displays place names)":
|
157 |
+
m.add_basemap("HYBRID")
|
158 |
+
elif map_type == "Google Satellite Map":
|
159 |
+
m.add_basemap("SATELLITE")
|
160 |
+
elif map_type == "Esri Satellite Map":
|
161 |
+
m.add_wms_layer(
|
162 |
+
wayback_url,
|
163 |
+
layers="0",
|
164 |
+
name=wayback_title,
|
165 |
+
attribution="Esri",
|
166 |
+
)
|
167 |
+
else:
|
168 |
+
st.error("Invalid map type")
|
169 |
+
force_stop()
|
170 |
+
|
171 |
# m.add_layer(buffer_ee_feature_collection)
|
172 |
+
add_geometry_to_maps([m], geometry_gdf, buffer_geometry_gdf, opacity=0.3)
|
173 |
+
# write_info(
|
174 |
+
# f"""
|
175 |
+
# <div style="text-align: center;">
|
176 |
+
# Latest Esri Imagery - {latest_date.replace('-', '/')}
|
177 |
+
# </div>
|
178 |
+
# """
|
179 |
+
# )
|
180 |
m.to_streamlit()
|
181 |
|
182 |
# Generate stats
|
183 |
+
centroid = geometry_gdf.to_crs(4326).centroid.item()
|
184 |
+
centroid_lon = centroid.xy[0][0]
|
185 |
+
centroid_lat = centroid.xy[1][0]
|
186 |
stats_df = pd.DataFrame(
|
187 |
{
|
188 |
"Area (m^2)": geometry_gdf.area.item(),
|
189 |
"Perimeter (m)": geometry_gdf.length.item(),
|
190 |
"Points": str(json.loads(geometry_gdf.to_crs(4326).to_json())["features"][0]["geometry"]["coordinates"]),
|
191 |
+
"Centroid": f"({centroid_lat:.6f}, {centroid_lon:.6f})",
|
192 |
+
},
|
193 |
+
index=[0],
|
194 |
)
|
195 |
+
|
196 |
+
gmaps_redirect_url = f"http://maps.google.com/maps?q={centroid_lat},{centroid_lon}&layer=satellite"
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
st.markdown(
|
198 |
f"""
|
199 |
<div style="display: flex; justify-content: center;">
|
200 |
+
<table style="border-collapse: collapse; text-align: center;">
|
201 |
<tr>
|
202 |
+
<th style="border: 1px solid black; text-align: left;">Metric</th>
|
203 |
+
<th style="border: 1px solid black; text-align: right;">Value</th>
|
204 |
+
<th style="border: 1px solid black; text-align: left;">Unit</th>
|
205 |
</tr>
|
206 |
<tr>
|
207 |
+
<td style="border: 1px solid black; text-align: left;">Area</td>
|
208 |
+
<td style="border: 1px solid black; text-align: right;">{stats_df['Area (m^2)'].item()/10000:.2f}</td>
|
209 |
+
<td style="border: 1px solid black; text-align: left;">ha</td>
|
210 |
</tr>
|
211 |
<tr>
|
212 |
+
<td style="border: 1px solid black; text-align: left;">Perimeter</td>
|
213 |
+
<td style="border: 1px solid black; text-align: right;">{stats_df['Perimeter (m)'].item():.2f}</td>
|
214 |
+
<td style="border: 1px solid black; text-align: left;">m</td>
|
215 |
</tr>
|
216 |
+
<tr>
|
217 |
+
<td style="border: 1px solid black; text-align: left;">Centroid</td>
|
218 |
+
<td style="border: 1px solid black; text-align: right;">({centroid_lat:.6f}, {centroid_lon:.6f})</td>
|
219 |
+
<td style="border: 1px solid black; text-align: left;">(lat, lon)</td>
|
220 |
</table>
|
221 |
</div>
|
222 |
+
<div style="text-align: center; margin-bottom: 10px;">
|
223 |
+
<a href="{gmaps_redirect_url}" target="_blank">
|
224 |
+
<button>View on Google Maps</button>
|
225 |
+
</a>
|
226 |
+
</div>
|
227 |
""",
|
228 |
+
unsafe_allow_html=True,
|
229 |
)
|
230 |
|
231 |
stats_csv = stats_df.to_csv(index=False)
|
232 |
st.download_button("Download Geometry Metrics", stats_csv, "geometry_metrics.csv", "text/csv", use_container_width=True)
|
233 |
|
234 |
+
st.write(
|
235 |
+
"<h3><div style='text-align: center;'>DEM and Slope from SRTM at 30m resolution</div></h3>",
|
236 |
+
unsafe_allow_html=True,
|
237 |
+
)
|
238 |
+
cols = st.columns(2)
|
239 |
+
|
240 |
+
if ("cached_dem_maps" in st.session_state) and (st.session_state.cached_file_url == file_url):
|
241 |
+
dem_map = st.session_state.dem_map
|
242 |
+
slope_map = st.session_state.slope_map
|
243 |
+
else:
|
244 |
+
dem_map, slope_map = get_dem_slope_maps(
|
245 |
+
ee.Geometry(geometry_gdf.to_crs(4326).geometry.item().__geo_interface__), wayback_url, wayback_title
|
246 |
+
)
|
247 |
+
st.session_state.dem_map = dem_map
|
248 |
+
st.session_state.slope_map = slope_map
|
249 |
+
st.session_state.cached_dem_maps = True
|
250 |
+
|
251 |
+
for col, param_map, title in zip(cols, [dem_map, slope_map], ["DEM Map", "Slope Map"]):
|
252 |
+
with col:
|
253 |
+
param_map.add_gdf(
|
254 |
+
geometry_gdf,
|
255 |
+
layer_name="Geometry",
|
256 |
+
style_function=lambda x: {"color": "blue", "fillOpacity": 0.0, "fillColor": "blue"},
|
257 |
+
)
|
258 |
+
write_info(f"""<div style="text-align: center;">{title}</div>""")
|
259 |
+
param_map.addLayerControl()
|
260 |
+
param_map.to_streamlit()
|
261 |
+
|
262 |
# Submit
|
263 |
+
m = st.markdown(
|
264 |
+
"""
|
265 |
+
<style>
|
266 |
+
div.stButton > button:first-child {
|
267 |
+
background-color: #006400;
|
268 |
+
color:#ffffff;
|
269 |
+
}
|
270 |
+
</style>""",
|
271 |
+
unsafe_allow_html=True,
|
272 |
+
)
|
273 |
submit = st.button("Calculate Vegetation Indices", use_container_width=True)
|
274 |
|
275 |
+
# Derived Inputs
|
276 |
+
ee_geometry = ee.Geometry(geometry_gdf.to_crs(4326).geometry.item().__geo_interface__)
|
277 |
+
ee_feature_collection = ee.FeatureCollection(ee_geometry)
|
278 |
+
buffer_ee_geometry = ee.Geometry(buffer_geometry_gdf.to_crs(4326).geometry.item().__geo_interface__)
|
279 |
+
buffer_ee_feature_collection = ee.FeatureCollection(buffer_ee_geometry)
|
280 |
+
outer_ee_geometry = ee.Geometry(outer_geometry_gdf.to_crs(4326).geometry.item().__geo_interface__)
|
281 |
+
outer_ee_feature_collection = ee.FeatureCollection(outer_ee_geometry)
|
282 |
+
|
283 |
if submit:
|
284 |
+
satellites = {
|
285 |
+
"COPERNICUS/S2_SR_HARMONIZED": {
|
286 |
+
"scale": 10,
|
287 |
+
"collection": ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")
|
288 |
+
.select(
|
289 |
+
["B2", "B4", "B8", "MSK_CLDPRB", "TCI_R", "TCI_G", "TCI_B"],
|
290 |
+
["Blue", "Red", "NIR", "MSK_CLDPRB", "R", "G", "B"],
|
291 |
+
)
|
292 |
+
.map(lambda image: add_indices(image, nir_band="NIR", red_band="Red", blue_band="Blue", evi_vars=evi_vars)),
|
293 |
+
},
|
294 |
+
}
|
295 |
+
satellite = list(satellites.keys())[0]
|
296 |
+
st.session_state.satellites = satellites
|
297 |
+
st.session_state.satellite = satellite
|
298 |
+
|
299 |
+
# Run one-time setup
|
300 |
+
if "one_time_setup_done" not in st.session_state:
|
301 |
+
one_time_setup()
|
302 |
+
st.session_state.one_time_setup_done = True
|
303 |
+
|
304 |
+
# Input: Satellite Sources
|
305 |
+
st.markdown(f"Satellite source: `{satellite}`")
|
306 |
+
satellite_selected = {}
|
307 |
+
for satellite in satellites:
|
308 |
+
satellite_selected[satellite] = satellite
|
309 |
+
|
310 |
st.write("<h2><div style='text-align: center;'>Results</div></h2>", unsafe_allow_html=True)
|
311 |
if not any(satellite_selected.values()):
|
312 |
st.error("Please select at least one satellite source")
|
313 |
+
force_stop()
|
314 |
|
315 |
# Create range
|
316 |
start_day = input_daterange[0].day
|
|
|
332 |
with st.spinner(f"Processing {satellite} ..."):
|
333 |
progress_bar = st.progress(0)
|
334 |
for i, daterange in enumerate(dates):
|
335 |
+
process_date(
|
336 |
+
daterange,
|
337 |
+
satellite,
|
338 |
+
veg_indices,
|
339 |
+
satellites,
|
340 |
+
buffer_ee_geometry,
|
341 |
+
ee_feature_collection,
|
342 |
+
buffer_ee_feature_collection,
|
343 |
+
result_df,
|
344 |
+
)
|
345 |
progress_bar.progress((i + 1) / len(dates))
|
346 |
|
347 |
st.session_state.result = result_df
|
|
|
349 |
print("Printing result...")
|
350 |
if "result" in st.session_state:
|
351 |
result_df = st.session_state.result
|
352 |
+
satellites = st.session_state.satellites
|
353 |
+
satellite = st.session_state.satellite
|
354 |
+
|
355 |
print(result_df.columns)
|
356 |
|
357 |
# drop rows with all NaN values
|
|
|
367 |
result_df[column] = pd.to_numeric(result_df[column], errors="ignore")
|
368 |
|
369 |
df_numeric = result_df.select_dtypes(include=["float64"])
|
370 |
+
# df_numeric.index.name = "Date Range"
|
371 |
+
html = df_numeric.style.format(precision=2).set_properties(**{"text-align": "right"}).to_html()
|
372 |
+
st.write(
|
373 |
+
f"""<div style="display: flex; justify-content: center;">
|
374 |
+
{html}</div>""",
|
375 |
+
unsafe_allow_html=True,
|
376 |
+
)
|
377 |
df_numeric_csv = df_numeric.to_csv(index=True)
|
378 |
st.download_button(
|
379 |
"Download Time Series Data", df_numeric_csv, "vegetation_indices.csv", "text/csv", use_container_width=True
|
|
|
385 |
fig.update_layout(xaxis=dict(tickvals=df_numeric.index, ticktext=df_numeric.index))
|
386 |
st.plotly_chart(fig)
|
387 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
388 |
st.write(
|
389 |
"<h3><div style='text-align: center;'>Visual Comparison between Two Years</div></h3>", unsafe_allow_html=True
|
390 |
)
|
|
|
409 |
mosaic = result_df.loc[daterange_str, f"mosaic_{veg_index}"]
|
410 |
with col:
|
411 |
m = gee_folium.Map()
|
412 |
+
m.add_tile_layer(
|
413 |
+
wayback_url,
|
414 |
+
name=wayback_title,
|
415 |
+
attribution="Esri",
|
416 |
+
)
|
417 |
veg_index_layer = gee_folium.ee_tile_layer(mosaic, {"bands": [veg_index], "min": 0, "max": 1})
|
418 |
|
419 |
if satellite == "COPERNICUS/S2_SR_HARMONIZED":
|
|
|
422 |
else:
|
423 |
raise ValueError(f"Unknown satellite: {satellite}")
|
424 |
|
425 |
+
if veg_index == "NDVI":
|
426 |
+
bins = [-1, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 1]
|
427 |
histogram, bin_edges = get_histogram(mosaic.select(veg_index), ee_geometry, bins)
|
428 |
total_pix = np.sum(histogram)
|
429 |
formatted_histogram = [f"{h*100/total_pix:.2f}" for h in histogram]
|
430 |
print(histogram, bin_edges, bins, formatted_histogram)
|
431 |
+
m.add_legend(
|
432 |
+
title="NDVI Class/Value",
|
433 |
+
legend_dict={
|
434 |
+
"<0:Waterbody ({}%)".format(formatted_histogram[0]): "#0000FF",
|
435 |
+
"0-0.1: Open ({}%)".format(formatted_histogram[1]): "#FF0000",
|
436 |
+
"0.1-0.2: Highly Degraded ({}%)".format(formatted_histogram[2]): "#FFFF00",
|
437 |
+
"0.2-0.3: Degraded ({}%)".format(formatted_histogram[3]): "#FFA500",
|
438 |
+
"0.3-0.4: Moderately Degraded ({}%)".format(formatted_histogram[4]): "#00FE00",
|
439 |
+
"0.4-0.5: Dense ({}%)".format(formatted_histogram[5]): "#00A400",
|
440 |
+
">0.5: Very Dense ({}%)".format(formatted_histogram[6]): "#006D00",
|
441 |
+
},
|
442 |
+
position="bottomright",
|
443 |
+
draggable=False,
|
444 |
+
)
|
445 |
+
ndvi_vis_params = {
|
446 |
+
"min": -0.1,
|
447 |
+
"max": 0.6,
|
448 |
+
"palette": ["#0000FF", "#FF0000", "#FFFF00", "#FFA500", "#00FE00", "#00A400", "#006D00"],
|
449 |
+
}
|
450 |
m.add_layer(mosaic.select(veg_index).clip(outer_ee_geometry), ndvi_vis_params)
|
451 |
+
|
452 |
# add colorbar
|
453 |
# m.add_colorbar(colors=["#000000", "#00FF00"], vmin=0.0, vmax=1.0)
|
454 |
+
|
455 |
+
if veg_index != "NDVI":
|
456 |
m.add_layer(mosaic.select(veg_index).clip(outer_ee_geometry), vis_params)
|
457 |
m.add_child(colormap)
|
458 |
+
add_geometry_to_maps([m], geometry_gdf, buffer_geometry_gdf)
|
459 |
m.to_streamlit()
|
460 |
|
461 |
for name, key in zip(
|
|
|
467 |
for col, daterange_str in zip(cols, [year_1, year_2]):
|
468 |
start_date, end_date = daterange_str_to_dates(daterange_str)
|
469 |
mid_date = start_date + (end_date - start_date) / 2
|
|
|
470 |
with col:
|
471 |
m = gee_folium.Map()
|
472 |
visual_mosaic = result_df.loc[daterange_str, key]
|
473 |
# visual_layer = gee_folium.ee_tile_layer(mosaic, {"bands": ["R", "G", "B"], "min": min_all, "max": max_all})
|
474 |
|
475 |
m.add_layer(visual_mosaic.select(["R", "G", "B"]))
|
476 |
+
add_geometry_to_maps([m], geometry_gdf, buffer_geometry_gdf)
|
477 |
m.to_streamlit()
|
478 |
|
479 |
st.write("<h3><div style='text-align: center;'>Esri RGB Imagery</div></h3>", unsafe_allow_html=True)
|
|
|
481 |
for col, daterange_str in zip(cols, [year_1, year_2]):
|
482 |
start_date, end_date = daterange_str_to_dates(daterange_str)
|
483 |
mid_date = start_date + (end_date - start_date) / 2
|
484 |
+
esri_date = min(wayback_df.index, key=lambda x: abs(x - mid_date))
|
485 |
+
esri_url = (
|
486 |
+
wayback_df.loc[esri_date, "ResourceURL_Template"]
|
487 |
+
.replace("{TileMatrixSet}", "GoogleMapsCompatible")
|
488 |
+
.replace("{TileMatrix}", "{z}")
|
489 |
+
.replace("{TileRow}", "{y}")
|
490 |
+
.replace("{TileCol}", "{x}")
|
491 |
+
)
|
492 |
+
esri_title = "Esri " + wayback_df.loc[esri_date, "Title"]
|
493 |
with col:
|
494 |
m = leaf_folium.Map()
|
495 |
+
m.add_tile_layer(
|
496 |
+
esri_url,
|
497 |
+
name=esri_title,
|
498 |
+
attribution="Esri",
|
499 |
+
)
|
500 |
+
add_geometry_to_maps([m], geometry_gdf, buffer_geometry_gdf)
|
501 |
write_info(
|
502 |
f"""
|
503 |
<div style="text-align: center;">
|
504 |
+
Esri Imagery - {esri_date.strftime('%Y-%m-%d')}
|
505 |
</div>
|
506 |
"""
|
507 |
)
|
508 |
m.to_streamlit()
|
509 |
|
510 |
+
|
511 |
+
show_credits()
|
functions.py
ADDED
@@ -0,0 +1,358 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from datetime import datetime
|
3 |
+
import ee
|
4 |
+
import json
|
5 |
+
import geemap
|
6 |
+
import numpy as np
|
7 |
+
import geemap.foliumap as gee_folium
|
8 |
+
import leafmap.foliumap as leaf_folium
|
9 |
+
import streamlit as st
|
10 |
+
import pandas as pd
|
11 |
+
import geopandas as gpd
|
12 |
+
from shapely.ops import transform
|
13 |
+
from functools import reduce
|
14 |
+
import plotly.express as px
|
15 |
+
import branca.colormap as cm
|
16 |
+
import folium
|
17 |
+
import pyproj
|
18 |
+
from io import StringIO, BytesIO
|
19 |
+
import requests
|
20 |
+
import kml2geojson
|
21 |
+
|
22 |
+
|
23 |
+
def force_stop():
|
24 |
+
show_credits()
|
25 |
+
st.stop()
|
26 |
+
|
27 |
+
|
28 |
+
def one_time_setup():
|
29 |
+
credentials_path = os.path.expanduser("~/.config/earthengine/credentials")
|
30 |
+
if os.path.exists(credentials_path):
|
31 |
+
pass # Earth Engine credentials already exist
|
32 |
+
elif "EE" in os.environ: # write the credentials to the file
|
33 |
+
ee_credentials = os.environ.get("EE")
|
34 |
+
os.makedirs(os.path.dirname(credentials_path), exist_ok=True)
|
35 |
+
with open(credentials_path, "w") as f:
|
36 |
+
f.write(ee_credentials)
|
37 |
+
else:
|
38 |
+
raise ValueError(
|
39 |
+
f"Earth Engine credentials not found at {credentials_path} or in the environment variable 'EE'"
|
40 |
+
)
|
41 |
+
|
42 |
+
ee.Initialize()
|
43 |
+
|
44 |
+
|
45 |
+
def show_credits():
|
46 |
+
# Add credits
|
47 |
+
st.write(
|
48 |
+
"""
|
49 |
+
<div style="display: flex; justify-content: center; align-items: center; margin-top: 20px;">
|
50 |
+
<p style="text-align: center;">Developed by <a href="https://sustainability-lab.github.io/">Sustainability Lab</a>, <a href="https://www.iitgn.ac.in/">IIT Gandhinagar</a></p>
|
51 |
+
</div>
|
52 |
+
<div style="display: flex; justify-content: center; align-items: center;">
|
53 |
+
<p style="text-align: center;"> Supported by <a href="https://forests.gujarat.gov.in/">Gujarat Forest Department</a>
|
54 |
+
</p>
|
55 |
+
</div>
|
56 |
+
""",
|
57 |
+
unsafe_allow_html=True,
|
58 |
+
)
|
59 |
+
|
60 |
+
|
61 |
+
def get_gdf_from_file_url(file_url):
|
62 |
+
if isinstance(file_url, str):
|
63 |
+
if file_url.startswith("https://drive.google.com/file/d/"):
|
64 |
+
ID = file_url.replace("https://drive.google.com/file/d/", "").split("/")[0]
|
65 |
+
file_url = f"https://drive.google.com/uc?id={ID}"
|
66 |
+
elif file_url.startswith("https://drive.google.com/open?id="):
|
67 |
+
ID = file_url.replace("https://drive.google.com/open?id=", "")
|
68 |
+
file_url = f"https://drive.google.com/uc?id={ID}"
|
69 |
+
|
70 |
+
response = requests.get(file_url)
|
71 |
+
bytes_data = BytesIO(response.content)
|
72 |
+
string_data = response.text
|
73 |
+
else:
|
74 |
+
bytes_data = BytesIO(file_url.getvalue())
|
75 |
+
string_data = file_url.getvalue().decode("utf-8")
|
76 |
+
|
77 |
+
if string_data.startswith("<?xml"):
|
78 |
+
geojson = kml2geojson.convert(bytes_data)
|
79 |
+
features = geojson[0]["features"]
|
80 |
+
epsg = 4326
|
81 |
+
input_gdf = gpd.GeoDataFrame.from_features(features, crs=f"EPSG:{epsg}")
|
82 |
+
else:
|
83 |
+
input_gdf = gpd.read_file(bytes_data)
|
84 |
+
|
85 |
+
return input_gdf
|
86 |
+
|
87 |
+
|
88 |
+
# Function of find best suited statewise EPSG code
|
89 |
+
def find_best_epsg(geometry):
|
90 |
+
if geometry.geom_type == "Polygon":
|
91 |
+
centroid = geometry.centroid
|
92 |
+
else:
|
93 |
+
st.error("Geometry is not Polygon !!!")
|
94 |
+
st.stop()
|
95 |
+
common_epsg_codes = [
|
96 |
+
7756, # Andhra Pradesh
|
97 |
+
7757, # Arunachal Pradesh
|
98 |
+
7758, # Assam
|
99 |
+
7759, # Bihar
|
100 |
+
7760, # Delhi
|
101 |
+
7761, # Gujarat
|
102 |
+
7762, # Haryana
|
103 |
+
7763, # HimachalPradesh
|
104 |
+
7764, # JammuAndKashmir
|
105 |
+
7765, # Jharkhand
|
106 |
+
7766, # MadhyaPradesh
|
107 |
+
7767, # Maharastra
|
108 |
+
7768, # Manipur
|
109 |
+
7769, # Meghalaya
|
110 |
+
7770, # Nagaland
|
111 |
+
7772, # Orissa
|
112 |
+
7773, # Punjab
|
113 |
+
7774, # Rajasthan
|
114 |
+
7775, # UttarPradesh
|
115 |
+
7776, # Uttaranchal
|
116 |
+
7777, # A&N
|
117 |
+
7778, # Chattisgarh
|
118 |
+
7779, # Goa
|
119 |
+
7780, # Karnataka
|
120 |
+
7781, # Kerala
|
121 |
+
7782, # Lakshadweep
|
122 |
+
7783, # Mizoram
|
123 |
+
7784, # Sikkim
|
124 |
+
7785, # TamilNadu
|
125 |
+
7786, # Tripura
|
126 |
+
7787, # WestBengal
|
127 |
+
7771, # NE India
|
128 |
+
7755, # India
|
129 |
+
]
|
130 |
+
|
131 |
+
for epsg in common_epsg_codes:
|
132 |
+
crs = pyproj.CRS.from_epsg(epsg)
|
133 |
+
area_of_use = crs.area_of_use.bounds # Get the bounding box of the area of use
|
134 |
+
|
135 |
+
# check if centroid of polygon lies in teh bounds of the crs
|
136 |
+
if (area_of_use[0] <= centroid.x <= area_of_use[2]) and (area_of_use[1] <= centroid.y <= area_of_use[3]):
|
137 |
+
return epsg # Return the best suitable EPSG code
|
138 |
+
|
139 |
+
|
140 |
+
def daterange_str_to_dates(daterange_str):
|
141 |
+
start_date, end_date = daterange_str.split("-")
|
142 |
+
start_date = pd.to_datetime(start_date)
|
143 |
+
end_date = pd.to_datetime(end_date)
|
144 |
+
return start_date, end_date
|
145 |
+
|
146 |
+
|
147 |
+
def daterange_dates_to_str(start_date, end_date):
|
148 |
+
return f"{start_date.strftime('%Y/%m/%d')}-{end_date.strftime('%Y/%m/%d')}"
|
149 |
+
|
150 |
+
|
151 |
+
def daterange_str_to_year(daterange_str):
|
152 |
+
start_date, _ = daterange_str.split("-")
|
153 |
+
year = pd.to_datetime(start_date).year
|
154 |
+
return year
|
155 |
+
|
156 |
+
|
157 |
+
def shape_3d_to_2d(shape):
|
158 |
+
if shape.has_z:
|
159 |
+
return transform(lambda x, y, z: (x, y), shape)
|
160 |
+
else:
|
161 |
+
return shape
|
162 |
+
|
163 |
+
|
164 |
+
def preprocess_gdf(gdf):
|
165 |
+
gdf["geometry"] = gdf["geometry"].apply(shape_3d_to_2d)
|
166 |
+
gdf["geometry"] = gdf.buffer(0) # Fixes some invalid geometries
|
167 |
+
return gdf
|
168 |
+
|
169 |
+
|
170 |
+
def to_best_crs(gdf):
|
171 |
+
best_epsg_code = find_best_epsg(gdf["geometry"].iloc[0])
|
172 |
+
gdf = gdf.to_crs(epsg=best_epsg_code)
|
173 |
+
return gdf
|
174 |
+
|
175 |
+
|
176 |
+
def is_valid_polygon(geometry_gdf):
|
177 |
+
geometry = geometry_gdf.geometry.item()
|
178 |
+
return (geometry.type == "Polygon") and (not geometry.is_empty)
|
179 |
+
|
180 |
+
|
181 |
+
def add_geometry_to_maps(map_list, geometry_gdf, buffer_geometry_gdf, opacity=0.0):
|
182 |
+
for m in map_list:
|
183 |
+
m.add_gdf(
|
184 |
+
buffer_geometry_gdf,
|
185 |
+
layer_name="Geometry Buffer",
|
186 |
+
style_function=lambda x: {"color": "red", "fillOpacity": opacity, "fillColor": "red"},
|
187 |
+
)
|
188 |
+
m.add_gdf(
|
189 |
+
geometry_gdf,
|
190 |
+
layer_name="Geometry",
|
191 |
+
style_function=lambda x: {"color": "blue", "fillOpacity": opacity, "fillColor": "blue"},
|
192 |
+
)
|
193 |
+
|
194 |
+
|
195 |
+
def get_dem_slope_maps(ee_geometry, wayback_url, wayback_title):
|
196 |
+
# Create the map for DEM
|
197 |
+
dem_map = gee_folium.Map(controls={"scale": "bottomleft"})
|
198 |
+
dem_map.add_tile_layer(wayback_url, name=wayback_title, attribution="Esri")
|
199 |
+
|
200 |
+
dem_layer = ee.Image("USGS/SRTMGL1_003")
|
201 |
+
# Set the target resolution to 10 meters
|
202 |
+
target_resolution = 10
|
203 |
+
dem_layer = dem_layer.resample("bilinear").reproject(crs="EPSG:4326", scale=target_resolution).clip(ee_geometry)
|
204 |
+
|
205 |
+
# Generate contour lines using elevation thresholds
|
206 |
+
terrain = ee.Algorithms.Terrain(dem_layer)
|
207 |
+
contour_interval = 1
|
208 |
+
contours = (
|
209 |
+
terrain.select("elevation").subtract(terrain.select("elevation").mod(contour_interval)).rename("contours")
|
210 |
+
)
|
211 |
+
|
212 |
+
# Calculate the minimum and maximum values
|
213 |
+
stats = contours.reduceRegion(reducer=ee.Reducer.minMax(), scale=10, maxPixels=1e13)
|
214 |
+
max_value = stats.get("contours_max").getInfo()
|
215 |
+
min_value = stats.get("contours_min").getInfo()
|
216 |
+
vis_params = {"min": min_value, "max": max_value, "palette": ["blue", "green", "yellow", "red"]}
|
217 |
+
dem_map.addLayer(contours, vis_params, "Contours")
|
218 |
+
# Create a colormap
|
219 |
+
cmap = cm.LinearColormap(colors=vis_params["palette"], vmin=vis_params["min"], vmax=vis_params["max"])
|
220 |
+
tick_size = int((max_value - min_value) / 4)
|
221 |
+
dem_map.add_legend(
|
222 |
+
title="Elevation (m)",
|
223 |
+
legend_dict={
|
224 |
+
"{}-{} m".format(min_value, min_value + tick_size): "#0000FF",
|
225 |
+
"{}-{} m".format(min_value + tick_size, min_value + 2 * tick_size): "#00FF00",
|
226 |
+
"{}-{} m".format(min_value + 2 * tick_size, min_value + 3 * tick_size): "#FFFF00",
|
227 |
+
"{}-{} m".format(min_value + 3 * tick_size, max_value): "#FF0000",
|
228 |
+
},
|
229 |
+
position="bottomright",
|
230 |
+
draggable=False,
|
231 |
+
)
|
232 |
+
|
233 |
+
# Create the map for Slope
|
234 |
+
slope_map = gee_folium.Map(controls={"scale": "bottomleft"})
|
235 |
+
slope_map.add_tile_layer(wayback_url, name=wayback_title, attribution="Esri")
|
236 |
+
|
237 |
+
# Calculate slope from the DEM
|
238 |
+
slope_layer = (
|
239 |
+
ee.Terrain.slope(
|
240 |
+
ee.Image("USGS/SRTMGL1_003").resample("bilinear").reproject(crs="EPSG:4326", scale=target_resolution)
|
241 |
+
)
|
242 |
+
.clip(ee_geometry)
|
243 |
+
.rename("slope")
|
244 |
+
)
|
245 |
+
# Calculate the minimum and maximum values
|
246 |
+
stats = slope_layer.reduceRegion(reducer=ee.Reducer.minMax(), scale=10, maxPixels=1e13)
|
247 |
+
max_value = int(stats.get("slope_max").getInfo())
|
248 |
+
min_value = int(stats.get("slope_min").getInfo())
|
249 |
+
vis_params = {"min": min_value, "max": max_value, "palette": ["blue", "green", "yellow", "red"]}
|
250 |
+
slope_map.addLayer(slope_layer, vis_params, "Slope Layer")
|
251 |
+
# Create a colormap
|
252 |
+
colormap = cm.LinearColormap(colors=vis_params["palette"], vmin=vis_params["min"], vmax=vis_params["max"])
|
253 |
+
tick_size = int((max_value - min_value) / 4)
|
254 |
+
slope_map.add_legend(
|
255 |
+
title="Slope (degrees)",
|
256 |
+
legend_dict={
|
257 |
+
"{}-{} deg".format(min_value, min_value + tick_size): "#0000FF",
|
258 |
+
"{}-{} deg".format(min_value + tick_size, min_value + 2 * tick_size): "#00FF00",
|
259 |
+
"{}-{} deg".format(min_value + 2 * tick_size, min_value + 3 * tick_size): "#FFFF00",
|
260 |
+
"{}-{} deg".format(min_value + 3 * tick_size, max_value): "#FF0000",
|
261 |
+
},
|
262 |
+
position="bottomright",
|
263 |
+
draggable=False,
|
264 |
+
)
|
265 |
+
return dem_map, slope_map
|
266 |
+
|
267 |
+
|
268 |
+
def add_indices(image, nir_band, red_band, blue_band, evi_vars):
|
269 |
+
# Add negative cloud
|
270 |
+
neg_cloud = image.select("MSK_CLDPRB").multiply(-1).rename("Neg_MSK_CLDPRB")
|
271 |
+
nir = image.select(nir_band).divide(10000)
|
272 |
+
red = image.select(red_band).divide(10000)
|
273 |
+
blue = image.select(blue_band).divide(10000)
|
274 |
+
numerator = nir.subtract(red)
|
275 |
+
ndvi = (numerator).divide(nir.add(red)).rename("NDVI").clamp(-1, 1)
|
276 |
+
# EVI formula taken from: https://en.wikipedia.org/wiki/Enhanced_vegetation_index
|
277 |
+
|
278 |
+
denominator = nir.add(red.multiply(evi_vars["C1"])).subtract(blue.multiply(evi_vars["C2"])).add(evi_vars["L"])
|
279 |
+
evi = numerator.divide(denominator).multiply(evi_vars["G"]).rename("EVI").clamp(-1, 1)
|
280 |
+
evi2 = (
|
281 |
+
numerator.divide(nir.add(evi_vars["L"]).add(red.multiply(evi_vars["C"])))
|
282 |
+
.multiply(evi_vars["G"])
|
283 |
+
.rename("EVI2")
|
284 |
+
.clamp(-1, 1)
|
285 |
+
)
|
286 |
+
return image.addBands([neg_cloud, ndvi, evi, evi2])
|
287 |
+
|
288 |
+
|
289 |
+
def get_histogram(image, geometry, bins):
|
290 |
+
# Get image values as a list
|
291 |
+
values = image.reduceRegion(reducer=ee.Reducer.toList(), geometry=geometry, scale=10, maxPixels=1e13).get("NDVI")
|
292 |
+
|
293 |
+
# Convert values to a NumPy array
|
294 |
+
values_array = np.array(values.getInfo())
|
295 |
+
|
296 |
+
# Compute the histogram on bins
|
297 |
+
hist, bin_edges = np.histogram(values_array, bins=bins)
|
298 |
+
|
299 |
+
return hist, bin_edges
|
300 |
+
|
301 |
+
|
302 |
+
def process_date(
|
303 |
+
daterange,
|
304 |
+
satellite,
|
305 |
+
veg_indices,
|
306 |
+
satellites,
|
307 |
+
buffer_ee_geometry,
|
308 |
+
ee_feature_collection,
|
309 |
+
buffer_ee_feature_collection,
|
310 |
+
result_df,
|
311 |
+
):
|
312 |
+
start_date, end_date = daterange
|
313 |
+
daterange_str = daterange_dates_to_str(start_date, end_date)
|
314 |
+
prefix = f"Processing {satellite} - {daterange_str}"
|
315 |
+
try:
|
316 |
+
attrs = satellites[satellite]
|
317 |
+
collection = attrs["collection"]
|
318 |
+
collection = collection.filterBounds(buffer_ee_geometry)
|
319 |
+
collection = collection.filterDate(start_date, end_date)
|
320 |
+
|
321 |
+
bucket = {}
|
322 |
+
for veg_index in veg_indices:
|
323 |
+
mosaic_veg_index = collection.qualityMosaic(veg_index)
|
324 |
+
fc = geemap.zonal_stats(
|
325 |
+
mosaic_veg_index, ee_feature_collection, scale=attrs["scale"], return_fc=True
|
326 |
+
).getInfo()
|
327 |
+
mean_veg_index = fc["features"][0]["properties"][veg_index]
|
328 |
+
bucket[veg_index] = mean_veg_index
|
329 |
+
fc = geemap.zonal_stats(
|
330 |
+
mosaic_veg_index, buffer_ee_feature_collection, scale=attrs["scale"], return_fc=True
|
331 |
+
).getInfo()
|
332 |
+
buffer_mean_veg_index = fc["features"][0]["properties"][veg_index]
|
333 |
+
bucket[f"{veg_index}_buffer"] = buffer_mean_veg_index
|
334 |
+
bucket[f"{veg_index}_ratio"] = mean_veg_index / buffer_mean_veg_index
|
335 |
+
bucket[f"mosaic_{veg_index}"] = mosaic_veg_index
|
336 |
+
|
337 |
+
# Get median mosaic
|
338 |
+
bucket["mosaic_visual_max_ndvi"] = collection.qualityMosaic("NDVI")
|
339 |
+
bucket["mosaic_visual_median"] = collection.median()
|
340 |
+
bucket["image_visual_least_cloud"] = collection.sort("CLOUDY_PIXEL_PERCENTAGE").first()
|
341 |
+
|
342 |
+
if satellite == "COPERNICUS/S2_SR_HARMONIZED":
|
343 |
+
cloud_mask_probability = fc["features"][0]["properties"]["MSK_CLDPRB"] / 100
|
344 |
+
else:
|
345 |
+
cloud_mask_probability = None
|
346 |
+
bucket["Cloud (0 to 1)"] = cloud_mask_probability
|
347 |
+
result_df.loc[daterange_str, list(bucket.keys())] = list(bucket.values())
|
348 |
+
count = collection.size().getInfo()
|
349 |
+
suffix = f" - Processed {count} images"
|
350 |
+
write_info(f"{prefix}{suffix}")
|
351 |
+
except Exception as e:
|
352 |
+
print(e)
|
353 |
+
suffix = f" - Imagery not available"
|
354 |
+
write_info(f"{prefix}{suffix}")
|
355 |
+
|
356 |
+
|
357 |
+
def write_info(info):
|
358 |
+
st.write(f"<span style='color:#006400;'>{info}</span>", unsafe_allow_html=True)
|
wayback.csv
ADDED
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Title,Identifier,LowerCorner,UpperCorner,Format,TileMatrixSetLinks,ResourceURL_Template
|
2 |
+
World Imagery (Wayback 2024-10-10),WB_2024_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/56450/{TileMatrix}/{TileRow}/{TileCol}
|
3 |
+
World Imagery (Wayback 2024-09-19),WB_2024_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/20337/{TileMatrix}/{TileRow}/{TileCol}
|
4 |
+
World Imagery (Wayback 2024-08-15),WB_2024_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/32553/{TileMatrix}/{TileRow}/{TileCol}
|
5 |
+
World Imagery (Wayback 2024-06-27),WB_2024_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/39767/{TileMatrix}/{TileRow}/{TileCol}
|
6 |
+
World Imagery (Wayback 2024-06-06),WB_2024_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/12428/{TileMatrix}/{TileRow}/{TileCol}
|
7 |
+
World Imagery (Wayback 2024-05-09),WB_2024_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/52930/{TileMatrix}/{TileRow}/{TileCol}
|
8 |
+
World Imagery (Wayback 2024-03-28),WB_2024_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/13968/{TileMatrix}/{TileRow}/{TileCol}
|
9 |
+
World Imagery (Wayback 2024-03-07),WB_2024_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/60013/{TileMatrix}/{TileRow}/{TileCol}
|
10 |
+
World Imagery (Wayback 2024-02-08),WB_2024_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/37965/{TileMatrix}/{TileRow}/{TileCol}
|
11 |
+
World Imagery (Wayback 2024-01-18),WB_2024_R00,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/41468/{TileMatrix}/{TileRow}/{TileCol}
|
12 |
+
World Imagery (Wayback 2023-12-07),WB_2023_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/56102/{TileMatrix}/{TileRow}/{TileCol}
|
13 |
+
World Imagery (Wayback 2023-11-01),WB_2023_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/12457/{TileMatrix}/{TileRow}/{TileCol}
|
14 |
+
World Imagery (Wayback 2023-10-11),WB_2023_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/1034/{TileMatrix}/{TileRow}/{TileCol}
|
15 |
+
World Imagery (Wayback 2023-08-31),WB_2023_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/64776/{TileMatrix}/{TileRow}/{TileCol}
|
16 |
+
World Imagery (Wayback 2023-08-10),WB_2023_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/17632/{TileMatrix}/{TileRow}/{TileCol}
|
17 |
+
World Imagery (Wayback 2023-06-29),WB_2023_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/47963/{TileMatrix}/{TileRow}/{TileCol}
|
18 |
+
World Imagery (Wayback 2023-06-13),WB_2023_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/25982/{TileMatrix}/{TileRow}/{TileCol}
|
19 |
+
World Imagery (Wayback 2023-05-03),WB_2023_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/46399/{TileMatrix}/{TileRow}/{TileCol}
|
20 |
+
World Imagery (Wayback 2023-04-05),WB_2023_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/37890/{TileMatrix}/{TileRow}/{TileCol}
|
21 |
+
World Imagery (Wayback 2023-03-15),WB_2023_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/44873/{TileMatrix}/{TileRow}/{TileCol}
|
22 |
+
World Imagery (Wayback 2023-02-23),WB_2023_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/57965/{TileMatrix}/{TileRow}/{TileCol}
|
23 |
+
World Imagery (Wayback 2023-01-11),WB_2023_R00,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11475/{TileMatrix}/{TileRow}/{TileCol}
|
24 |
+
World Imagery (Wayback 2022-12-14),WB_2022_R15,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/45134/{TileMatrix}/{TileRow}/{TileCol}
|
25 |
+
World Imagery (Wayback 2022-11-02),WB_2022_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/7110/{TileMatrix}/{TileRow}/{TileCol}
|
26 |
+
World Imagery (Wayback 2022-10-12),WB_2022_R13,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/44988/{TileMatrix}/{TileRow}/{TileCol}
|
27 |
+
World Imagery (Wayback 2022-09-21),WB_2022_R12,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/47471/{TileMatrix}/{TileRow}/{TileCol}
|
28 |
+
World Imagery (Wayback 2022-08-31),WB_2022_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/45441/{TileMatrix}/{TileRow}/{TileCol}
|
29 |
+
World Imagery (Wayback 2022-08-10),WB_2022_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/17825/{TileMatrix}/{TileRow}/{TileCol}
|
30 |
+
World Imagery (Wayback 2022-07-20),WB_2022_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/13851/{TileMatrix}/{TileRow}/{TileCol}
|
31 |
+
World Imagery (Wayback 2022-06-29),WB_2022_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/4905/{TileMatrix}/{TileRow}/{TileCol}
|
32 |
+
World Imagery (Wayback 2022-06-08),WB_2022_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/44710/{TileMatrix}/{TileRow}/{TileCol}
|
33 |
+
World Imagery (Wayback 2022-05-18),WB_2022_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/5314/{TileMatrix}/{TileRow}/{TileCol}
|
34 |
+
World Imagery (Wayback 2022-04-27),WB_2022_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/16245/{TileMatrix}/{TileRow}/{TileCol}
|
35 |
+
World Imagery (Wayback 2022-04-06),WB_2022_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/48232/{TileMatrix}/{TileRow}/{TileCol}
|
36 |
+
World Imagery (Wayback 2022-03-16),WB_2022_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/10321/{TileMatrix}/{TileRow}/{TileCol}
|
37 |
+
World Imagery (Wayback 2022-02-24),WB_2022_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/10312/{TileMatrix}/{TileRow}/{TileCol}
|
38 |
+
World Imagery (Wayback 2022-02-02),WB_2022_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/26083/{TileMatrix}/{TileRow}/{TileCol}
|
39 |
+
World Imagery (Wayback 2022-01-12),WB_2022_R00,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/42663/{TileMatrix}/{TileRow}/{TileCol}
|
40 |
+
World Imagery (Wayback 2021-12-21),WB_2021_R17,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/26120/{TileMatrix}/{TileRow}/{TileCol}
|
41 |
+
World Imagery (Wayback 2021-11-30),WB_2021_R16,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/48624/{TileMatrix}/{TileRow}/{TileCol}
|
42 |
+
World Imagery (Wayback 2021-11-03),WB_2021_R15,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/42403/{TileMatrix}/{TileRow}/{TileCol}
|
43 |
+
World Imagery (Wayback 2021-10-13),WB_2021_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/16749/{TileMatrix}/{TileRow}/{TileCol}
|
44 |
+
World Imagery (Wayback 2021-09-22),WB_2021_R13,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/51313/{TileMatrix}/{TileRow}/{TileCol}
|
45 |
+
World Imagery (Wayback 2021-09-01),WB_2021_R12,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/47568/{TileMatrix}/{TileRow}/{TileCol}
|
46 |
+
World Imagery (Wayback 2021-08-11),WB_2021_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/51423/{TileMatrix}/{TileRow}/{TileCol}
|
47 |
+
World Imagery (Wayback 2021-07-21),WB_2021_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/8432/{TileMatrix}/{TileRow}/{TileCol}
|
48 |
+
World Imagery (Wayback 2021-06-30),WB_2021_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/13534/{TileMatrix}/{TileRow}/{TileCol}
|
49 |
+
World Imagery (Wayback 2021-06-09),WB_2021_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/48376/{TileMatrix}/{TileRow}/{TileCol}
|
50 |
+
World Imagery (Wayback 2021-05-19),WB_2021_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/15423/{TileMatrix}/{TileRow}/{TileCol}
|
51 |
+
World Imagery (Wayback 2021-04-28),WB_2021_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/27659/{TileMatrix}/{TileRow}/{TileCol}
|
52 |
+
World Imagery (Wayback 2021-04-08),WB_2021_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/6863/{TileMatrix}/{TileRow}/{TileCol}
|
53 |
+
World Imagery (Wayback 2021-03-17),WB_2021_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/5359/{TileMatrix}/{TileRow}/{TileCol}
|
54 |
+
World Imagery (Wayback 2021-02-24),WB_2021_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/9812/{TileMatrix}/{TileRow}/{TileCol}
|
55 |
+
World Imagery (Wayback 2021-01-13),WB_2021_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/1049/{TileMatrix}/{TileRow}/{TileCol}
|
56 |
+
World Imagery (Wayback 2020-12-16),WB_2020_R16,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/29260/{TileMatrix}/{TileRow}/{TileCol}
|
57 |
+
World Imagery (Wayback 2020-11-18),WB_2020_R15,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/20753/{TileMatrix}/{TileRow}/{TileCol}
|
58 |
+
World Imagery (Wayback 2020-10-14),WB_2020_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/119/{TileMatrix}/{TileRow}/{TileCol}
|
59 |
+
World Imagery (Wayback 2020-09-23),WB_2020_R13,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/19187/{TileMatrix}/{TileRow}/{TileCol}
|
60 |
+
World Imagery (Wayback 2020-09-02),WB_2020_R12,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/9181/{TileMatrix}/{TileRow}/{TileCol}
|
61 |
+
World Imagery (Wayback 2020-08-12),WB_2020_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/6049/{TileMatrix}/{TileRow}/{TileCol}
|
62 |
+
World Imagery (Wayback 2020-07-22),WB_2020_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/9549/{TileMatrix}/{TileRow}/{TileCol}
|
63 |
+
World Imagery (Wayback 2020-07-01),WB_2020_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/18289/{TileMatrix}/{TileRow}/{TileCol}
|
64 |
+
World Imagery (Wayback 2020-06-10),WB_2020_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11135/{TileMatrix}/{TileRow}/{TileCol}
|
65 |
+
World Imagery (Wayback 2020-05-20),WB_2020_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/32645/{TileMatrix}/{TileRow}/{TileCol}
|
66 |
+
World Imagery (Wayback 2020-04-29),WB_2020_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/15045/{TileMatrix}/{TileRow}/{TileCol}
|
67 |
+
World Imagery (Wayback 2020-04-08),WB_2020_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/26751/{TileMatrix}/{TileRow}/{TileCol}
|
68 |
+
World Imagery (Wayback 2020-03-23),WB_2020_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/16062/{TileMatrix}/{TileRow}/{TileCol}
|
69 |
+
World Imagery (Wayback 2020-02-20),WB_2020_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/8495/{TileMatrix}/{TileRow}/{TileCol}
|
70 |
+
World Imagery (Wayback 2020-01-30),WB_2020_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/21485/{TileMatrix}/{TileRow}/{TileCol}
|
71 |
+
World Imagery (Wayback 2020-01-08),WB_2020_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/23001/{TileMatrix}/{TileRow}/{TileCol}
|
72 |
+
World Imagery (Wayback 2019-12-12),WB_2019_R16,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/4756/{TileMatrix}/{TileRow}/{TileCol}
|
73 |
+
World Imagery (Wayback 2019-10-30),WB_2019_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11060/{TileMatrix}/{TileRow}/{TileCol}
|
74 |
+
World Imagery (Wayback 2019-10-09),WB_2019_R13,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11351/{TileMatrix}/{TileRow}/{TileCol}
|
75 |
+
World Imagery (Wayback 2019-09-18),WB_2019_R12,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/9892/{TileMatrix}/{TileRow}/{TileCol}
|
76 |
+
World Imagery (Wayback 2019-08-28),WB_2019_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/30442/{TileMatrix}/{TileRow}/{TileCol}
|
77 |
+
World Imagery (Wayback 2019-08-07),WB_2019_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/17216/{TileMatrix}/{TileRow}/{TileCol}
|
78 |
+
World Imagery (Wayback 2019-07-17),WB_2019_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/16681/{TileMatrix}/{TileRow}/{TileCol}
|
79 |
+
World Imagery (Wayback 2019-06-26),WB_2019_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/645/{TileMatrix}/{TileRow}/{TileCol}
|
80 |
+
World Imagery (Wayback 2019-06-05),WB_2019_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/12576/{TileMatrix}/{TileRow}/{TileCol}
|
81 |
+
World Imagery (Wayback 2019-05-15),WB_2019_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/9598/{TileMatrix}/{TileRow}/{TileCol}
|
82 |
+
World Imagery (Wayback 2019-04-24),WB_2019_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/18063/{TileMatrix}/{TileRow}/{TileCol}
|
83 |
+
World Imagery (Wayback 2019-04-03),WB_2019_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/18691/{TileMatrix}/{TileRow}/{TileCol}
|
84 |
+
World Imagery (Wayback 2019-03-13),WB_2019_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/4383/{TileMatrix}/{TileRow}/{TileCol}
|
85 |
+
World Imagery (Wayback 2019-02-21),WB_2019_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/17677/{TileMatrix}/{TileRow}/{TileCol}
|
86 |
+
World Imagery (Wayback 2019-01-31),WB_2019_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/25944/{TileMatrix}/{TileRow}/{TileCol}
|
87 |
+
World Imagery (Wayback 2019-01-09),WB_2019_R00,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/6036/{TileMatrix}/{TileRow}/{TileCol}
|
88 |
+
World Imagery (Wayback 2018-12-14),WB_2018_R17,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/23448/{TileMatrix}/{TileRow}/{TileCol}
|
89 |
+
World Imagery (Wayback 2018-11-29),WB_2018_R16,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/239/{TileMatrix}/{TileRow}/{TileCol}
|
90 |
+
World Imagery (Wayback 2018-11-07),WB_2018_R15,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/3201/{TileMatrix}/{TileRow}/{TileCol}
|
91 |
+
World Imagery (Wayback 2018-10-17),WB_2018_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/18820/{TileMatrix}/{TileRow}/{TileCol}
|
92 |
+
World Imagery (Wayback 2018-09-26),WB_2018_R13,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/14426/{TileMatrix}/{TileRow}/{TileCol}
|
93 |
+
World Imagery (Wayback 2018-09-06),WB_2018_R12,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/2168/{TileMatrix}/{TileRow}/{TileCol}
|
94 |
+
World Imagery (Wayback 2018-08-15),WB_2018_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/1858/{TileMatrix}/{TileRow}/{TileCol}
|
95 |
+
World Imagery (Wayback 2018-07-25),WB_2018_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/14829/{TileMatrix}/{TileRow}/{TileCol}
|
96 |
+
World Imagery (Wayback 2018-06-27),WB_2018_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11334/{TileMatrix}/{TileRow}/{TileCol}
|
97 |
+
World Imagery (Wayback 2018-06-06),WB_2018_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/8249/{TileMatrix}/{TileRow}/{TileCol}
|
98 |
+
World Imagery (Wayback 2018-05-16),WB_2018_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/32337/{TileMatrix}/{TileRow}/{TileCol}
|
99 |
+
World Imagery (Wayback 2018-04-25),WB_2018_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/1296/{TileMatrix}/{TileRow}/{TileCol}
|
100 |
+
World Imagery (Wayback 2018-04-11),WB_2018_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/20399/{TileMatrix}/{TileRow}/{TileCol}
|
101 |
+
World Imagery (Wayback 2018-03-28),WB_2018_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/7072/{TileMatrix}/{TileRow}/{TileCol}
|
102 |
+
World Imagery (Wayback 2018-03-14),WB_2018_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/8255/{TileMatrix}/{TileRow}/{TileCol}
|
103 |
+
World Imagery (Wayback 2018-02-23),WB_2018_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/13067/{TileMatrix}/{TileRow}/{TileCol}
|
104 |
+
World Imagery (Wayback 2018-01-31),WB_2018_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/10768/{TileMatrix}/{TileRow}/{TileCol}
|
105 |
+
World Imagery (Wayback 2018-01-18),WB_2018_R00,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/13045/{TileMatrix}/{TileRow}/{TileCol}
|
106 |
+
World Imagery (Wayback 2018-01-08),WB_2017_R21,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/13161/{TileMatrix}/{TileRow}/{TileCol}
|
107 |
+
World Imagery (Wayback 2017-11-16),WB_2017_R19,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/25521/{TileMatrix}/{TileRow}/{TileCol}
|
108 |
+
World Imagery (Wayback 2017-10-25),WB_2017_R18,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/23264/{TileMatrix}/{TileRow}/{TileCol}
|
109 |
+
World Imagery (Wayback 2017-10-04),WB_2017_R17,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/15212/{TileMatrix}/{TileRow}/{TileCol}
|
110 |
+
World Imagery (Wayback 2017-09-13),WB_2017_R16,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/18358/{TileMatrix}/{TileRow}/{TileCol}
|
111 |
+
World Imagery (Wayback 2017-08-30),WB_2017_R15,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/25379/{TileMatrix}/{TileRow}/{TileCol}
|
112 |
+
World Imagery (Wayback 2017-08-10),WB_2017_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/14035/{TileMatrix}/{TileRow}/{TileCol}
|
113 |
+
World Imagery (Wayback 2017-07-14),WB_2017_R13,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/3319/{TileMatrix}/{TileRow}/{TileCol}
|
114 |
+
World Imagery (Wayback 2017-06-27),WB_2017_R12,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/4073/{TileMatrix}/{TileRow}/{TileCol}
|
115 |
+
World Imagery (Wayback 2017-06-14),WB_2017_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/14765/{TileMatrix}/{TileRow}/{TileCol}
|
116 |
+
World Imagery (Wayback 2017-05-31),WB_2017_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/14342/{TileMatrix}/{TileRow}/{TileCol}
|
117 |
+
World Imagery (Wayback 2017-05-17),WB_2017_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/20365/{TileMatrix}/{TileRow}/{TileCol}
|
118 |
+
World Imagery (Wayback 2017-05-03),WB_2017_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/784/{TileMatrix}/{TileRow}/{TileCol}
|
119 |
+
World Imagery (Wayback 2017-04-19),WB_2017_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/1052/{TileMatrix}/{TileRow}/{TileCol}
|
120 |
+
World Imagery (Wayback 2017-03-29),WB_2017_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/5205/{TileMatrix}/{TileRow}/{TileCol}
|
121 |
+
World Imagery (Wayback 2017-03-15),WB_2017_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/29387/{TileMatrix}/{TileRow}/{TileCol}
|
122 |
+
World Imagery (Wayback 2017-02-27),WB_2017_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/31026/{TileMatrix}/{TileRow}/{TileCol}
|
123 |
+
World Imagery (Wayback 2017-02-08),WB_2017_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/27946/{TileMatrix}/{TileRow}/{TileCol}
|
124 |
+
World Imagery (Wayback 2017-01-25),WB_2017_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/9486/{TileMatrix}/{TileRow}/{TileCol}
|
125 |
+
World Imagery (Wayback 2017-01-11),WB_2017_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/577/{TileMatrix}/{TileRow}/{TileCol}
|
126 |
+
World Imagery (Wayback 2016-12-20),WB_2016_R22,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/18966/{TileMatrix}/{TileRow}/{TileCol}
|
127 |
+
World Imagery (Wayback 2016-12-07),WB_2016_R21,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/6678/{TileMatrix}/{TileRow}/{TileCol}
|
128 |
+
World Imagery (Wayback 2016-11-16),WB_2016_R20,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/21750/{TileMatrix}/{TileRow}/{TileCol}
|
129 |
+
World Imagery (Wayback 2016-10-25),WB_2016_R19,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/4222/{TileMatrix}/{TileRow}/{TileCol}
|
130 |
+
World Imagery (Wayback 2016-10-12),WB_2016_R18,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/13770/{TileMatrix}/{TileRow}/{TileCol}
|
131 |
+
World Imagery (Wayback 2016-09-14),WB_2016_R16,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/6984/{TileMatrix}/{TileRow}/{TileCol}
|
132 |
+
World Imagery (Wayback 2016-08-31),WB_2016_R15,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/9175/{TileMatrix}/{TileRow}/{TileCol}
|
133 |
+
World Imagery (Wayback 2016-08-11),WB_2016_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/23601/{TileMatrix}/{TileRow}/{TileCol}
|
134 |
+
World Imagery (Wayback 2016-07-20),WB_2016_R13,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/5097/{TileMatrix}/{TileRow}/{TileCol}
|
135 |
+
World Imagery (Wayback 2016-07-06),WB_2016_R12,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/13240/{TileMatrix}/{TileRow}/{TileCol}
|
136 |
+
World Imagery (Wayback 2016-06-13),WB_2016_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11509/{TileMatrix}/{TileRow}/{TileCol}
|
137 |
+
World Imagery (Wayback 2016-05-11),WB_2016_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/8551/{TileMatrix}/{TileRow}/{TileCol}
|
138 |
+
World Imagery (Wayback 2016-04-28),WB_2016_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/5769/{TileMatrix}/{TileRow}/{TileCol}
|
139 |
+
World Imagery (Wayback 2016-04-20),WB_2016_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/388/{TileMatrix}/{TileRow}/{TileCol}
|
140 |
+
World Imagery (Wayback 2016-03-16),WB_2016_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/19085/{TileMatrix}/{TileRow}/{TileCol}
|
141 |
+
World Imagery (Wayback 2016-03-02),WB_2016_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/20443/{TileMatrix}/{TileRow}/{TileCol}
|
142 |
+
World Imagery (Wayback 2016-02-17),WB_2016_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11262/{TileMatrix}/{TileRow}/{TileCol}
|
143 |
+
World Imagery (Wayback 2016-02-04),WB_2016_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/6354/{TileMatrix}/{TileRow}/{TileCol}
|
144 |
+
World Imagery (Wayback 2016-01-13),WB_2016_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/3515/{TileMatrix}/{TileRow}/{TileCol}
|
145 |
+
World Imagery (Wayback 2015-12-16),WB_2015_R23,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/28163/{TileMatrix}/{TileRow}/{TileCol}
|
146 |
+
World Imagery (Wayback 2015-11-18),WB_2015_R20,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/8781/{TileMatrix}/{TileRow}/{TileCol}
|
147 |
+
World Imagery (Wayback 2015-10-28),WB_2015_R18,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11092/{TileMatrix}/{TileRow}/{TileCol}
|
148 |
+
World Imagery (Wayback 2015-10-14),WB_2015_R17,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/10850/{TileMatrix}/{TileRow}/{TileCol}
|
149 |
+
World Imagery (Wayback 2015-09-30),WB_2015_R16,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/3630/{TileMatrix}/{TileRow}/{TileCol}
|
150 |
+
World Imagery (Wayback 2015-09-16),WB_2015_R15,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/1431/{TileMatrix}/{TileRow}/{TileCol}
|
151 |
+
World Imagery (Wayback 2015-09-02),WB_2015_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/30584/{TileMatrix}/{TileRow}/{TileCol}
|
152 |
+
World Imagery (Wayback 2015-08-19),WB_2015_R13,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/28219/{TileMatrix}/{TileRow}/{TileCol}
|
153 |
+
World Imagery (Wayback 2015-07-08),WB_2015_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/24007/{TileMatrix}/{TileRow}/{TileCol}
|
154 |
+
World Imagery (Wayback 2015-06-24),WB_2015_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11952/{TileMatrix}/{TileRow}/{TileCol}
|
155 |
+
World Imagery (Wayback 2015-05-13),WB_2015_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/19930/{TileMatrix}/{TileRow}/{TileCol}
|
156 |
+
World Imagery (Wayback 2015-04-30),WB_2015_R07,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/23880/{TileMatrix}/{TileRow}/{TileCol}
|
157 |
+
World Imagery (Wayback 2015-04-15),WB_2015_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/9203/{TileMatrix}/{TileRow}/{TileCol}
|
158 |
+
World Imagery (Wayback 2015-03-25),WB_2015_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/2730/{TileMatrix}/{TileRow}/{TileCol}
|
159 |
+
World Imagery (Wayback 2015-03-18),WB_2015_R04,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/15084/{TileMatrix}/{TileRow}/{TileCol}
|
160 |
+
World Imagery (Wayback 2015-02-18),WB_2015_R02,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/10443/{TileMatrix}/{TileRow}/{TileCol}
|
161 |
+
World Imagery (Wayback 2015-01-21),WB_2015_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/20222/{TileMatrix}/{TileRow}/{TileCol}
|
162 |
+
World Imagery (Wayback 2014-12-30),WB_2014_R21,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/5844/{TileMatrix}/{TileRow}/{TileCol}
|
163 |
+
World Imagery (Wayback 2014-12-18),WB_2014_R20,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/14720/{TileMatrix}/{TileRow}/{TileCol}
|
164 |
+
World Imagery (Wayback 2014-12-03),WB_2014_R19,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/23383/{TileMatrix}/{TileRow}/{TileCol}
|
165 |
+
World Imagery (Wayback 2014-11-12),WB_2014_R18,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/30195/{TileMatrix}/{TileRow}/{TileCol}
|
166 |
+
World Imagery (Wayback 2014-10-29),WB_2014_R17,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11019/{TileMatrix}/{TileRow}/{TileCol}
|
167 |
+
World Imagery (Wayback 2014-10-01),WB_2014_R15,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/22692/{TileMatrix}/{TileRow}/{TileCol}
|
168 |
+
World Imagery (Wayback 2014-09-17),WB_2014_R14,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/25586/{TileMatrix}/{TileRow}/{TileCol}
|
169 |
+
World Imagery (Wayback 2014-07-30),WB_2014_R11,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/5232/{TileMatrix}/{TileRow}/{TileCol}
|
170 |
+
World Imagery (Wayback 2014-07-02),WB_2014_R10,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/3026/{TileMatrix}/{TileRow}/{TileCol}
|
171 |
+
World Imagery (Wayback 2014-06-25),WB_2014_R09,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/11033/{TileMatrix}/{TileRow}/{TileCol}
|
172 |
+
World Imagery (Wayback 2014-06-11),WB_2014_R08,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/31144/{TileMatrix}/{TileRow}/{TileCol}
|
173 |
+
World Imagery (Wayback 2014-05-14),WB_2014_R06,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/16513/{TileMatrix}/{TileRow}/{TileCol}
|
174 |
+
World Imagery (Wayback 2014-04-30),WB_2014_R05,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/19819/{TileMatrix}/{TileRow}/{TileCol}
|
175 |
+
World Imagery (Wayback 2014-03-26),WB_2014_R03,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/4230/{TileMatrix}/{TileRow}/{TileCol}
|
176 |
+
World Imagery (Wayback 2014-02-20),WB_2014_R01,-2.003750722959434E7 -2.003750722959434E7,2.003750722959434E7 2.003750722959434E7,,"default028mm, GoogleMapsCompatible",https://wayback.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/WMTS/1.0.0/{TileMatrixSet}/MapServer/tile/10/{TileMatrix}/{TileRow}/{TileCol}
|
wayback.parquet
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:a240ea2d4bc920e20358948a42dbe0d204f4e2240a5584dbf94a4e07b70de34f
|
3 |
+
size 13682
|