Zeel commited on
Commit
cdab240
·
1 Parent(s): 9d41303

merge into single app

Browse files
Files changed (6) hide show
  1. .gitignore +1 -0
  2. Esri_XML_to_wayback_csv.ipynb +319 -0
  3. app.py +267 -496
  4. functions.py +358 -0
  5. wayback.csv +176 -0
  6. 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
- print(geemap.__version__)
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
- # Logo
 
 
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
- # make title in center
 
52
  st.markdown(
53
  f"""
54
- <h1 style="text-align: center;">Vrinda (वृन्दा): Interactive Vegetation Index Analyzer</h1>
55
  """,
56
  unsafe_allow_html=True,
57
  )
58
 
59
  ############################################
60
- # Hyperparameters
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", "shp"])
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
- "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."
81
  )
82
- show_credits()
83
- st.stop()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- # Functions
108
- ############################################
109
-
110
- # Function of find best suited statewise EPSG code
111
- def get_gdf_from_file_url(file_url):
112
- if isinstance(file_url, str):
113
- if file_url.startswith("https://drive.google.com/file/d/"):
114
- ID = file_url.replace("https://drive.google.com/file/d/", "").split("/")[0]
115
- file_url = f"https://drive.google.com/uc?id={ID}"
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
- # Calculate slope from the DEM
282
- slope_layer = (
283
- ee.Terrain.slope(
284
- ee.Image("USGS/SRTMGL1_003").resample("bilinear").reproject(crs="EPSG:4326", scale=target_resolution)
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
- m = leaf_folium.Map()
500
- keys = list(wayback_mapping.keys())
501
- latest_date = sorted(keys, key=lambda x: pd.to_datetime(x))[-1]
502
- m.add_tile_layer(
503
- wayback_mapping[latest_date], name=f"Esri Wayback - {latest_date.replace('-', '/')}", attribution="Esri"
 
 
 
 
504
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  # m.add_layer(buffer_ee_feature_collection)
506
- add_geometry_to_maps([m], opacity=0.3)
507
- write_info(
508
- f"""
509
- <div style="text-align: center;">
510
- Latest Esri Imagery - {latest_date.replace('-', '/')}
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
- }, index=[0]
 
 
523
  )
524
- st.write("<h3><div style='text-align: center;'>Geometry Metrics</div></h3>", unsafe_allow_html=True)
525
- # st.markdown(
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; width: 75%; text-align: center;">
536
  <tr>
537
- <th style="border: 1px solid black; padding: 8px;">Metric</th>
538
- <th style="border: 1px solid black; padding: 8px;">Value</th>
 
539
  </tr>
540
  <tr>
541
- <td style="border: 1px solid black; padding: 8px;">Area</td>
542
- <td style="border: 1px solid black; padding: 8px;">{stats_df['Area (m^2)'].item()/10000:.2f} ha</td>
 
543
  </tr>
544
  <tr>
545
- <td style="border: 1px solid black; padding: 8px;">Perimeter</td>
546
- <td style="border: 1px solid black; padding: 8px;">{stats_df['Perimeter (m)'].item():.2f} m</td>
 
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
- st.stop()
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(daterange, satellite, veg_indices)
 
 
 
 
 
 
 
 
 
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
- st.write(df_numeric)
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(wayback_mapping[latest_date], name=f"Esri Wayback - {latest_date.replace('-', '/')}", attribution="Esri")
 
 
 
 
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=='NDVI':
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(title="NDVI Class/Value",
679
- legend_dict={'<0:Waterbody ({}%)'.format(formatted_histogram[0]): '#0000FF',
680
- '0-0.1: Open ({}%)'.format(formatted_histogram[1]): '#FF0000',
681
- '0.1-0.2: Highly Degraded ({}%)'.format(formatted_histogram[2]):'#FFFF00',
682
- '0.2-0.3: Degraded ({}%)'.format(formatted_histogram[3]): '#FFA500',
683
- '0.3-0.4: Moderately Degraded ({}%)'.format(formatted_histogram[4]): '#00FE00',
684
- '0.4-0.5: Dense ({}%)'.format(formatted_histogram[5]): '#00A400',
685
- '>0.5: Very Dense ({}%)'.format(formatted_histogram[6]): '#006D00',
686
- },
687
- position='bottomright', draggable=False)
688
- ndvi_vis_params = {'min': -0.1,
689
- 'max': 0.6,
690
- 'palette': ['#0000FF', '#FF0000', '#FFFF00', '#FFA500', '#00FE00', '#00A400', '#006D00']}
 
 
 
 
 
 
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!='NDVI':
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(wayback_mapping.keys(), key=lambda x: abs(pd.to_datetime(x) - mid_date))
 
 
 
 
 
 
 
 
727
  with col:
728
  m = leaf_folium.Map()
729
- m.add_tile_layer(wayback_mapping[esri_date], name=f"Esri Wayback Imagery - {esri_date}", attribution="Esri")
730
- add_geometry_to_maps([m])
 
 
 
 
731
  write_info(
732
  f"""
733
  <div style="text-align: center;">
734
- Esri Imagery - {esri_date.replace('-', '/')}
735
  </div>
736
  """
737
  )
738
  m.to_streamlit()
739
 
740
- show_credits()
 
 
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