dea-tools 0.3.7.dev13__tar.gz → 0.3.7.dev14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/PKG-INFO +1 -1
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/__init__.py +1 -1
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/animations.py +92 -176
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/changefilmstrips.py +136 -163
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/crophealth.py +53 -85
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/deacoastlines.py +98 -133
- dea_tools-0.3.7.dev14/dea_tools/app/geomedian.py +246 -0
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/imageexport.py +81 -164
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/miningrehab.py +26 -36
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/wetlandsinsighttool.py +78 -137
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/widgetconstructors.py +104 -145
- dea_tools-0.3.7.dev14/dea_tools/bandindices.py +393 -0
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/bom.py +73 -90
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/classification.py +92 -224
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/coastal.py +133 -246
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/dask.py +21 -22
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/datahandling.py +43 -98
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/landcover.py +396 -524
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/maps.py +68 -64
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/plotting.py +320 -377
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/pyfes_model.py +6 -4
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/spatial.py +74 -146
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/temporal.py +41 -79
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/validation.py +8 -11
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/waterbodies.py +24 -28
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/wetlands.py +27 -35
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/wit_app.py +44 -57
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/pyproject.toml +1 -1
- dea_tools-0.3.7.dev13/dea_tools/app/geomedian.py +0 -126
- dea_tools-0.3.7.dev13/dea_tools/bandindices.py +0 -432
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/.gitignore +0 -0
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/LICENSE +0 -0
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/README_tools.md +0 -0
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/__main__.py +0 -0
- {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dea-tools
|
|
3
|
-
Version: 0.3.7.
|
|
3
|
+
Version: 0.3.7.dev14
|
|
4
4
|
Summary: Functions and algorithms for analysing Digital Earth Australia data.
|
|
5
5
|
Project-URL: Homepage, https://github.com/GeoscienceAustralia/dea-notebooks
|
|
6
6
|
Project-URL: Repository, https://github.com/GeoscienceAustralia/dea-notebooks
|
|
@@ -1,66 +1,55 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""
|
|
3
|
-
Satellite imagery animation widget, which can be used to interactively
|
|
3
|
+
Satellite imagery animation widget, which can be used to interactively
|
|
4
4
|
produce animations for multiple DEA products.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
# Import required packages
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
8
|
+
import datetime
|
|
9
|
+
import itertools
|
|
10
|
+
import json
|
|
11
11
|
import warnings
|
|
12
|
+
from io import BytesIO
|
|
13
|
+
|
|
14
|
+
import datacube
|
|
15
|
+
import geopandas as gpd
|
|
16
|
+
import ipywidgets as widgets
|
|
17
|
+
import matplotlib as mpl
|
|
12
18
|
import matplotlib.pyplot as plt
|
|
13
|
-
|
|
19
|
+
import numpy as np
|
|
20
|
+
import pandas as pd
|
|
21
|
+
from datacube.utils.geometry import Geometry
|
|
22
|
+
from datacube.utils.masking import mask_invalid_data
|
|
14
23
|
from ipyleaflet import (
|
|
15
|
-
WMSLayer,
|
|
16
|
-
basemaps,
|
|
17
|
-
basemap_to_tiles,
|
|
18
|
-
Map,
|
|
19
|
-
DrawControl,
|
|
20
|
-
WidgetControl,
|
|
21
|
-
SearchControl,
|
|
22
|
-
Marker,
|
|
23
24
|
LayerGroup,
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
Marker,
|
|
26
|
+
SearchControl,
|
|
27
|
+
basemap_to_tiles,
|
|
28
|
+
basemaps,
|
|
26
29
|
)
|
|
27
|
-
from traitlets import Unicode
|
|
28
30
|
from ipywidgets import (
|
|
29
|
-
|
|
31
|
+
HTML,
|
|
30
32
|
Button,
|
|
31
|
-
|
|
33
|
+
GridspecLayout,
|
|
32
34
|
HBox,
|
|
33
|
-
|
|
34
|
-
HTML,
|
|
35
|
+
Layout,
|
|
35
36
|
Output,
|
|
37
|
+
VBox,
|
|
36
38
|
)
|
|
37
|
-
import json
|
|
38
|
-
import itertools
|
|
39
|
-
import numpy as np
|
|
40
|
-
import geopandas as gpd
|
|
41
|
-
from io import BytesIO
|
|
42
|
-
import ipywidgets as widgets
|
|
43
|
-
import datetime
|
|
44
|
-
from skimage import exposure
|
|
45
39
|
from skimage.filters import unsharp_mask
|
|
46
40
|
|
|
47
|
-
from
|
|
48
|
-
from datacube.utils.geometry import Geometry
|
|
49
|
-
from datacube.utils.masking import mask_invalid_data
|
|
50
|
-
from .widgetconstructors import (
|
|
51
|
-
create_html,
|
|
52
|
-
create_drawcontrol,
|
|
53
|
-
create_map,
|
|
54
|
-
create_datepicker,
|
|
55
|
-
create_inputtext,
|
|
41
|
+
from dea_tools.app.widgetconstructors import (
|
|
56
42
|
create_checkbox,
|
|
43
|
+
create_datepicker,
|
|
44
|
+
create_drawcontrol,
|
|
57
45
|
create_dropdown,
|
|
58
|
-
|
|
46
|
+
create_html,
|
|
47
|
+
create_map,
|
|
59
48
|
)
|
|
60
|
-
from
|
|
61
|
-
from
|
|
49
|
+
from dea_tools.coastal import get_coastlines
|
|
50
|
+
from dea_tools.dask import create_local_dask_cluster
|
|
51
|
+
from dea_tools.spatial import reverse_geocode
|
|
62
52
|
|
|
63
|
-
import warnings
|
|
64
53
|
warnings.filterwarnings("ignore")
|
|
65
54
|
|
|
66
55
|
# WMS params and satellite style bands
|
|
@@ -146,14 +135,12 @@ def update_map_layers(self, update_basemap=False):
|
|
|
146
135
|
self.query_params = None
|
|
147
136
|
|
|
148
137
|
if update_basemap:
|
|
149
|
-
|
|
150
138
|
# Clear all layers and add basemap
|
|
151
139
|
self.map_layers.clear_layers()
|
|
152
140
|
self.map_layers.add_layer(self.basemap)
|
|
153
141
|
|
|
154
142
|
|
|
155
143
|
def extract_data(self):
|
|
156
|
-
|
|
157
144
|
# Connect to datacube database
|
|
158
145
|
dc = datacube.Datacube(app="Exporting satellite images")
|
|
159
146
|
|
|
@@ -175,15 +162,11 @@ def extract_data(self):
|
|
|
175
162
|
}
|
|
176
163
|
|
|
177
164
|
# Find matching datasets
|
|
178
|
-
dss = [
|
|
179
|
-
dc.find_datasets(product=i, **self.query_params)
|
|
180
|
-
for i in sat_params[self.dealayer]["products"]
|
|
181
|
-
]
|
|
165
|
+
dss = [dc.find_datasets(product=i, **self.query_params) for i in sat_params[self.dealayer]["products"]]
|
|
182
166
|
dss = list(itertools.chain.from_iterable(dss))
|
|
183
167
|
|
|
184
168
|
# If data is found
|
|
185
169
|
if len(dss) > 0:
|
|
186
|
-
|
|
187
170
|
# Get CRS
|
|
188
171
|
crs = str(dss[0].crs)
|
|
189
172
|
|
|
@@ -233,26 +216,21 @@ def extract_data(self):
|
|
|
233
216
|
|
|
234
217
|
|
|
235
218
|
def plot_data(self, fname):
|
|
236
|
-
|
|
237
219
|
# Data to plot
|
|
238
220
|
to_plot = self.timeseries_ds
|
|
239
221
|
|
|
240
222
|
# If rolling median specified
|
|
241
223
|
if self.rolling_median:
|
|
242
224
|
with self.status_info:
|
|
243
|
-
print(
|
|
244
|
-
|
|
245
|
-
)
|
|
246
|
-
to_plot = to_plot.rolling(
|
|
247
|
-
time=int(self.rolling_median_window), center=True, min_periods=1
|
|
248
|
-
).median()
|
|
225
|
+
print(f"\nApplying rolling median ({self.rolling_median_window} timesteps window)")
|
|
226
|
+
to_plot = to_plot.rolling(time=int(self.rolling_median_window), center=True, min_periods=1).median()
|
|
249
227
|
|
|
250
228
|
# Raise by power to dampen bright features and enhance dark.
|
|
251
229
|
# Raise vmin and vmax by same amount to ensure proper stretch
|
|
252
230
|
if self.power < 1.0:
|
|
253
231
|
with self.status_info:
|
|
254
232
|
print(f"\nApplying power transformation ({self.power})")
|
|
255
|
-
to_plot = to_plot
|
|
233
|
+
to_plot = to_plot**self.power
|
|
256
234
|
|
|
257
235
|
# Apply unsharp masking to enhance overall dynamic range,
|
|
258
236
|
# and improve fine scale detail
|
|
@@ -266,9 +244,7 @@ def plot_data(self, fname):
|
|
|
266
244
|
|
|
267
245
|
funcs_list = [
|
|
268
246
|
rescale_intensity,
|
|
269
|
-
lambda x: unsharp_mask(
|
|
270
|
-
x, radius=self.unsharp_mask_radius, amount=self.unsharp_mask_amount
|
|
271
|
-
),
|
|
247
|
+
lambda x: unsharp_mask(x, radius=self.unsharp_mask_radius, amount=self.unsharp_mask_amount),
|
|
272
248
|
]
|
|
273
249
|
else:
|
|
274
250
|
funcs_list = None
|
|
@@ -297,13 +273,6 @@ def plot_data(self, fname):
|
|
|
297
273
|
|
|
298
274
|
|
|
299
275
|
def deacoastlines_overlay(ds):
|
|
300
|
-
|
|
301
|
-
import geopandas as gpd
|
|
302
|
-
import pandas as pd
|
|
303
|
-
import matplotlib
|
|
304
|
-
from shapely.geometry import box, Point
|
|
305
|
-
from dea_tools.coastal import get_coastlines
|
|
306
|
-
|
|
307
276
|
# Get bounding box of data
|
|
308
277
|
xmin, ymin, xmax, ymax = ds.geobox.geographic_extent.boundingbox
|
|
309
278
|
bounds = [xmin, ymin, xmax, ymax]
|
|
@@ -317,8 +286,8 @@ def deacoastlines_overlay(ds):
|
|
|
317
286
|
deacl_gdf = deacl_gdf.dissolve("year") # values("year", ascending=True)
|
|
318
287
|
|
|
319
288
|
# Apply colours
|
|
320
|
-
norm =
|
|
321
|
-
cmap =
|
|
289
|
+
norm = mpl.colors.Normalize(vmin=0, vmax=len(deacl_gdf.index))
|
|
290
|
+
cmap = mpl.cm.get_cmap("inferno")
|
|
322
291
|
rgba = cmap(norm(deacl_gdf.reset_index().index))
|
|
323
292
|
deacl_gdf["color"] = list(rgba)
|
|
324
293
|
deacl_gdf["start_time"] = pd.to_datetime(deacl_gdf.index) + pd.DateOffset(months=0)
|
|
@@ -326,8 +295,7 @@ def deacoastlines_overlay(ds):
|
|
|
326
295
|
|
|
327
296
|
if len(deacl_gdf.index) > 0:
|
|
328
297
|
return deacl_gdf
|
|
329
|
-
|
|
330
|
-
return None
|
|
298
|
+
return None
|
|
331
299
|
|
|
332
300
|
|
|
333
301
|
class animation_app(HBox):
|
|
@@ -347,15 +315,13 @@ class animation_app(HBox):
|
|
|
347
315
|
|
|
348
316
|
# Satellite data
|
|
349
317
|
end_date = datetime.datetime.today()
|
|
350
|
-
start_date = datetime.datetime(
|
|
351
|
-
year=end_date.year - 3, month=end_date.month, day=end_date.day
|
|
352
|
-
)
|
|
318
|
+
start_date = datetime.datetime(year=end_date.year - 3, month=end_date.month, day=end_date.day)
|
|
353
319
|
self.start_date = start_date.strftime("%Y-%m-%d")
|
|
354
320
|
self.end_date = end_date.strftime("%Y-%m-%d")
|
|
355
321
|
self.dealayer_list = [
|
|
356
322
|
("Landsat", "Landsat"),
|
|
357
323
|
("Sentinel-2", "Sentinel-2"),
|
|
358
|
-
("Sentinel-2 and Landsat", "Sentinel-2 and Landsat")
|
|
324
|
+
("Sentinel-2 and Landsat", "Sentinel-2 and Landsat"),
|
|
359
325
|
]
|
|
360
326
|
self.dealayer = self.dealayer_list[0][1]
|
|
361
327
|
|
|
@@ -404,9 +370,7 @@ class animation_app(HBox):
|
|
|
404
370
|
##################
|
|
405
371
|
|
|
406
372
|
# Create the Header widget
|
|
407
|
-
header_title_text =
|
|
408
|
-
"<h3>Digital Earth Australia satellite imagery animations</h3>"
|
|
409
|
-
)
|
|
373
|
+
header_title_text = "<h3>Digital Earth Australia satellite imagery animations</h3>"
|
|
410
374
|
instruction_text = (
|
|
411
375
|
"<p>Select the desired satellite data, imagery date range "
|
|
412
376
|
"and image style, then zoom in and draw a rectangle to "
|
|
@@ -422,7 +386,6 @@ class animation_app(HBox):
|
|
|
422
386
|
|
|
423
387
|
# Define the action to take once something is drawn on the map
|
|
424
388
|
def update_geojson(target, action, geo_json):
|
|
425
|
-
|
|
426
389
|
# Get data from action
|
|
427
390
|
self.action = action
|
|
428
391
|
|
|
@@ -452,12 +415,7 @@ class animation_app(HBox):
|
|
|
452
415
|
'<span style="color: #33cc33"> '
|
|
453
416
|
"<b>(Overriding maximum size limit; use with caution as may lead to memory issues)</b></span>"
|
|
454
417
|
)
|
|
455
|
-
self.header.value =
|
|
456
|
-
header_title_text
|
|
457
|
-
+ instruction_text
|
|
458
|
-
+ polyarea_text
|
|
459
|
-
+ confirmation_text
|
|
460
|
-
)
|
|
418
|
+
self.header.value = header_title_text + instruction_text + polyarea_text + confirmation_text
|
|
461
419
|
self.gdf_drawn = gdf
|
|
462
420
|
elif area <= 50000:
|
|
463
421
|
confirmation_text = (
|
|
@@ -465,12 +423,7 @@ class animation_app(HBox):
|
|
|
465
423
|
"<b>(Area to extract falls within "
|
|
466
424
|
"recommended 50000 ha limit)</b></span>"
|
|
467
425
|
)
|
|
468
|
-
self.header.value =
|
|
469
|
-
header_title_text
|
|
470
|
-
+ instruction_text
|
|
471
|
-
+ polyarea_text
|
|
472
|
-
+ confirmation_text
|
|
473
|
-
)
|
|
426
|
+
self.header.value = header_title_text + instruction_text + polyarea_text + confirmation_text
|
|
474
427
|
self.gdf_drawn = gdf
|
|
475
428
|
else:
|
|
476
429
|
warning_text = (
|
|
@@ -479,9 +432,7 @@ class animation_app(HBox):
|
|
|
479
432
|
"please select an area less than 50000 "
|
|
480
433
|
"ha)</b></span>"
|
|
481
434
|
)
|
|
482
|
-
self.header.value =
|
|
483
|
-
header_title_text + instruction_text + polyarea_text + warning_text
|
|
484
|
-
)
|
|
435
|
+
self.header.value = header_title_text + instruction_text + polyarea_text + warning_text
|
|
485
436
|
self.gdf_drawn = None
|
|
486
437
|
|
|
487
438
|
###########################
|
|
@@ -509,12 +460,14 @@ class animation_app(HBox):
|
|
|
509
460
|
|
|
510
461
|
# Add tools to map widget
|
|
511
462
|
self.m.add_control(draw_control)
|
|
512
|
-
self.m.add_control(
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
463
|
+
self.m.add_control(
|
|
464
|
+
SearchControl(
|
|
465
|
+
position="topleft",
|
|
466
|
+
url="https://nominatim.openstreetmap.org/search?format=json&q={s}",
|
|
467
|
+
zoom=13, # 'Village / Suburb' level zoom
|
|
468
|
+
marker=Marker(draggable=False),
|
|
469
|
+
)
|
|
470
|
+
)
|
|
518
471
|
self.m.add_layer(self.map_layers)
|
|
519
472
|
|
|
520
473
|
# Update all maps to starting defaults
|
|
@@ -525,24 +478,16 @@ class animation_app(HBox):
|
|
|
525
478
|
############################
|
|
526
479
|
|
|
527
480
|
# Create parameter widgets
|
|
528
|
-
dropdown_basemap = create_dropdown(
|
|
529
|
-
|
|
530
|
-
)
|
|
531
|
-
dropdown_dealayer = create_dropdown(
|
|
532
|
-
self.dealayer_list, self.dealayer_list[0][1]
|
|
533
|
-
)
|
|
534
|
-
dropdown_output = create_dropdown(
|
|
535
|
-
self.output_list, self.output_list[0][1]
|
|
536
|
-
)
|
|
481
|
+
dropdown_basemap = create_dropdown(self.basemap_list, self.basemap_list[0][1])
|
|
482
|
+
dropdown_dealayer = create_dropdown(self.dealayer_list, self.dealayer_list[0][1])
|
|
483
|
+
dropdown_output = create_dropdown(self.output_list, self.output_list[0][1])
|
|
537
484
|
date_picker_start = create_datepicker(
|
|
538
485
|
value=start_date,
|
|
539
486
|
)
|
|
540
487
|
date_picker_end = create_datepicker(
|
|
541
488
|
value=end_date,
|
|
542
489
|
)
|
|
543
|
-
dropdown_styles = create_dropdown(
|
|
544
|
-
self.styles_list, self.styles_list[0]
|
|
545
|
-
)
|
|
490
|
+
dropdown_styles = create_dropdown(self.styles_list, self.styles_list[0])
|
|
546
491
|
slider_percentile = widgets.FloatRangeSlider(
|
|
547
492
|
value=[0.01, 0.99],
|
|
548
493
|
min=0,
|
|
@@ -580,26 +525,20 @@ class animation_app(HBox):
|
|
|
580
525
|
)
|
|
581
526
|
|
|
582
527
|
# Expandable advanced section
|
|
583
|
-
text_interval = widgets.IntText(
|
|
584
|
-
value=100, description="", step=50, layout={"width": "95%"}
|
|
585
|
-
)
|
|
528
|
+
text_interval = widgets.IntText(value=100, description="", step=50, layout={"width": "95%"})
|
|
586
529
|
text_resolution = widgets.FloatText(
|
|
587
530
|
value=30,
|
|
588
531
|
description="",
|
|
589
532
|
layout={"width": "95%", "margin": "0px", "padding": "0px"},
|
|
590
533
|
)
|
|
591
|
-
text_width = widgets.IntText(
|
|
592
|
-
value=900, description="", step=50, layout={"width": "95%"}
|
|
593
|
-
)
|
|
534
|
+
text_width = widgets.IntText(value=900, description="", step=50, layout={"width": "95%"})
|
|
594
535
|
dropdown_resampling = create_dropdown(
|
|
595
536
|
self.resample_list,
|
|
596
537
|
self.resample_freq,
|
|
597
538
|
description="",
|
|
598
539
|
layout={"width": "95%"},
|
|
599
540
|
)
|
|
600
|
-
checkbox_cloud_mask = create_checkbox(
|
|
601
|
-
self.cloud_mask, "Mask out cloudy pixels", layout={"width": "95%"}
|
|
602
|
-
)
|
|
541
|
+
checkbox_cloud_mask = create_checkbox(self.cloud_mask, "Mask out cloudy pixels", layout={"width": "95%"})
|
|
603
542
|
slider_power = widgets.FloatSlider(
|
|
604
543
|
value=1.0,
|
|
605
544
|
min=0.01,
|
|
@@ -608,9 +547,7 @@ class animation_app(HBox):
|
|
|
608
547
|
description="",
|
|
609
548
|
layout={"width": "95%"},
|
|
610
549
|
)
|
|
611
|
-
checkbox_unsharp_mask = create_checkbox(
|
|
612
|
-
self.unsharp_mask, "Enable", layout={"width": "95%"}
|
|
613
|
-
)
|
|
550
|
+
checkbox_unsharp_mask = create_checkbox(self.unsharp_mask, "Enable", layout={"width": "95%"})
|
|
614
551
|
text_unsharp_mask_radius = widgets.FloatText(
|
|
615
552
|
value=20,
|
|
616
553
|
step=1,
|
|
@@ -636,9 +573,7 @@ class animation_app(HBox):
|
|
|
636
573
|
checkbox_deacoastlines = create_checkbox(
|
|
637
574
|
self.deacoastlines, "Add DEA Coastlines overlay", layout={"width": "95%"}
|
|
638
575
|
)
|
|
639
|
-
checkbox_max_size = create_checkbox(
|
|
640
|
-
self.max_size, "Enable", layout={"width": "95%"}
|
|
641
|
-
)
|
|
576
|
+
checkbox_max_size = create_checkbox(self.max_size, "Enable", layout={"width": "95%"})
|
|
642
577
|
expand_box = widgets.VBox(
|
|
643
578
|
[
|
|
644
579
|
HTML("Frame interval (milliseconds):"),
|
|
@@ -658,9 +593,7 @@ class animation_app(HBox):
|
|
|
658
593
|
checkbox_unsharp_mask,
|
|
659
594
|
text_unsharp_mask_radius,
|
|
660
595
|
text_unsharp_mask_amount,
|
|
661
|
-
HTML(
|
|
662
|
-
"</br>Override maximum size limit: (use with caution; may cause memory issues/crashes)"
|
|
663
|
-
),
|
|
596
|
+
HTML("</br>Override maximum size limit: (use with caution; may cause memory issues/crashes)"),
|
|
664
597
|
checkbox_max_size,
|
|
665
598
|
],
|
|
666
599
|
)
|
|
@@ -689,13 +622,9 @@ class animation_app(HBox):
|
|
|
689
622
|
dropdown_styles.observe(self.update_styles, "value")
|
|
690
623
|
|
|
691
624
|
slider_percentile.observe(self.update_slider_percentile, "value")
|
|
692
|
-
floatslider_max_cloud_cover.observe(
|
|
693
|
-
self.update_floatslider_max_cloud_cover, "value"
|
|
694
|
-
)
|
|
625
|
+
floatslider_max_cloud_cover.observe(self.update_floatslider_max_cloud_cover, "value")
|
|
695
626
|
checkbox_rolling_median.observe(self.update_checkbox_rolling_median, "value")
|
|
696
|
-
text_rolling_median_window.observe(
|
|
697
|
-
self.update_text_rolling_median_window, "value"
|
|
698
|
-
)
|
|
627
|
+
text_rolling_median_window.observe(self.update_text_rolling_median_window, "value")
|
|
699
628
|
dropdown_output.observe(self.update_output, "value")
|
|
700
629
|
run_button.on_click(self.run_app)
|
|
701
630
|
draw_control.on_draw(update_geojson)
|
|
@@ -717,34 +646,30 @@ class animation_app(HBox):
|
|
|
717
646
|
# COLLECTION OF ALL APP CONTROLS #
|
|
718
647
|
##################################
|
|
719
648
|
|
|
720
|
-
parameter_selection = VBox(
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
HTML("</br><b>Map overlay:</b>"),
|
|
745
|
-
dropdown_basemap,
|
|
746
|
-
]
|
|
747
|
-
)
|
|
649
|
+
parameter_selection = VBox([
|
|
650
|
+
HTML("<b>Start date:</b>"),
|
|
651
|
+
date_picker_start,
|
|
652
|
+
HTML("<b>End date:</b>"),
|
|
653
|
+
date_picker_end,
|
|
654
|
+
HTML("<b>Satellite imagery:</b>"),
|
|
655
|
+
dropdown_dealayer,
|
|
656
|
+
HTML("<b>Style:</b>"),
|
|
657
|
+
dropdown_styles,
|
|
658
|
+
HTML("<b>Colour percentile stretch:</b>"),
|
|
659
|
+
slider_percentile,
|
|
660
|
+
HTML("<b>Maximum cloud cover (%):</b>"),
|
|
661
|
+
floatslider_max_cloud_cover,
|
|
662
|
+
checkbox_rolling_median,
|
|
663
|
+
text_rolling_median_window,
|
|
664
|
+
HTML("</br><b>Output file format:</b>"),
|
|
665
|
+
dropdown_output,
|
|
666
|
+
HTML("</br>"),
|
|
667
|
+
expand,
|
|
668
|
+
])
|
|
669
|
+
map_selection = VBox([
|
|
670
|
+
HTML("</br><b>Map overlay:</b>"),
|
|
671
|
+
dropdown_basemap,
|
|
672
|
+
])
|
|
748
673
|
parameter_selection.layout = make_box_layout()
|
|
749
674
|
map_selection.layout = make_box_layout()
|
|
750
675
|
|
|
@@ -819,10 +744,10 @@ class animation_app(HBox):
|
|
|
819
744
|
|
|
820
745
|
elif change.new == "Sentinel-2":
|
|
821
746
|
self.text_resolution.value = 10
|
|
822
|
-
|
|
747
|
+
|
|
823
748
|
elif change.new == "Sentinel-2 and Landsat":
|
|
824
749
|
self.text_resolution.value = 30
|
|
825
|
-
|
|
750
|
+
|
|
826
751
|
# Clear data load params to trigger data re-load
|
|
827
752
|
update_map_layers(self)
|
|
828
753
|
|
|
@@ -924,16 +849,13 @@ class animation_app(HBox):
|
|
|
924
849
|
update_map_layers(self)
|
|
925
850
|
|
|
926
851
|
def run_app(self, change):
|
|
927
|
-
|
|
928
852
|
# Clear progress bar and output areas before running
|
|
929
853
|
self.status_info.clear_output()
|
|
930
854
|
self.output_plot.clear_output()
|
|
931
855
|
|
|
932
856
|
# Verify that polygon was drawn
|
|
933
857
|
if self.gdf_drawn is not None:
|
|
934
|
-
|
|
935
858
|
with self.status_info:
|
|
936
|
-
|
|
937
859
|
# Load data and add to attribute
|
|
938
860
|
if self.timeseries_ds is None:
|
|
939
861
|
self.timeseries_ds = extract_data(self)
|
|
@@ -942,9 +864,7 @@ class animation_app(HBox):
|
|
|
942
864
|
print("Using previously loaded data")
|
|
943
865
|
|
|
944
866
|
if self.timeseries_ds is not None:
|
|
945
|
-
|
|
946
867
|
with self.status_info:
|
|
947
|
-
|
|
948
868
|
# Create unique file name
|
|
949
869
|
centre_coords = self.gdf_drawn.geometry[0].centroid.coords[0][::-1]
|
|
950
870
|
site = reverse_geocode(coords=centre_coords)
|
|
@@ -956,9 +876,7 @@ class animation_app(HBox):
|
|
|
956
876
|
.lower()
|
|
957
877
|
)
|
|
958
878
|
|
|
959
|
-
print(
|
|
960
|
-
f"\nExporting animation for {site}.\nThis may take several minutes..."
|
|
961
|
-
)
|
|
879
|
+
print(f"\nExporting animation for {site}.\nThis may take several minutes...")
|
|
962
880
|
|
|
963
881
|
############
|
|
964
882
|
# Plotting #
|
|
@@ -977,6 +895,4 @@ class animation_app(HBox):
|
|
|
977
895
|
|
|
978
896
|
else:
|
|
979
897
|
with self.status_info:
|
|
980
|
-
print(
|
|
981
|
-
'Please draw a valid rectangle on the map, then press "Generate animation".'
|
|
982
|
-
)
|
|
898
|
+
print('Please draw a valid rectangle on the map, then press "Generate animation".')
|