dea-tools 0.3.7.dev17__tar.gz → 0.3.7.dev19__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.
Files changed (37) hide show
  1. {dea_tools-0.3.7.dev17 → dea_tools-0.3.7.dev19}/PKG-INFO +12 -7
  2. {dea_tools-0.3.7.dev17 → dea_tools-0.3.7.dev19}/README_tools.md +3 -3
  3. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/__init__.py +1 -1
  4. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/app/animations.py +101 -176
  5. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/app/changefilmstrips.py +133 -161
  6. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/app/crophealth.py +51 -84
  7. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/app/deacoastlines.py +101 -127
  8. dea_tools-0.3.7.dev19/app/geomedian.py +246 -0
  9. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/app/imageexport.py +88 -162
  10. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/app/miningrehab.py +24 -35
  11. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/app/wetlandsinsighttool.py +85 -137
  12. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/app/widgetconstructors.py +104 -145
  13. dea_tools-0.3.7.dev19/bandindices.py +393 -0
  14. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/bom.py +74 -91
  15. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/classification.py +92 -224
  16. dea_tools-0.3.7.dev19/coastal.py +304 -0
  17. dea_tools-0.3.7.dev19/dask.py +143 -0
  18. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/datahandling.py +85 -136
  19. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/landcover.py +396 -524
  20. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/maps.py +101 -67
  21. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/plotting.py +329 -392
  22. {dea_tools-0.3.7.dev17 → dea_tools-0.3.7.dev19}/pyproject.toml +23 -27
  23. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/spatial.py +139 -359
  24. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/temporal.py +50 -83
  25. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/validation.py +8 -11
  26. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/waterbodies.py +24 -28
  27. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/wetlands.py +27 -35
  28. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/wit_app.py +55 -61
  29. dea_tools-0.3.7.dev17/dea_tools/app/geomedian.py +0 -126
  30. dea_tools-0.3.7.dev17/dea_tools/bandindices.py +0 -432
  31. dea_tools-0.3.7.dev17/dea_tools/coastal.py +0 -2381
  32. dea_tools-0.3.7.dev17/dea_tools/dask.py +0 -133
  33. dea_tools-0.3.7.dev17/dea_tools/pyfes_model.py +0 -70
  34. {dea_tools-0.3.7.dev17 → dea_tools-0.3.7.dev19}/.gitignore +0 -0
  35. {dea_tools-0.3.7.dev17 → dea_tools-0.3.7.dev19}/LICENSE +0 -0
  36. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/__main__.py +0 -0
  37. {dea_tools-0.3.7.dev17/dea_tools → dea_tools-0.3.7.dev19}/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.dev17
3
+ Version: 0.3.7.dev19
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
@@ -22,6 +22,7 @@ Requires-Python: <4.0,>=3.10
22
22
  Requires-Dist: aiohttp>=3.5.0
23
23
  Requires-Dist: dask-ml>=2023.3.24
24
24
  Requires-Dist: dask>=2023.1.0
25
+ Requires-Dist: eo-tides>=0.8.0
25
26
  Requires-Dist: fiona>=1.10.0
26
27
  Requires-Dist: folium>=0.16.0
27
28
  Requires-Dist: geopandas>=0.10.0
@@ -38,7 +39,7 @@ Requires-Dist: owslib>=0.26.0
38
39
  Requires-Dist: packaging>=22.0
39
40
  Requires-Dist: pandas>=2.2.0
40
41
  Requires-Dist: pyproj>=3.7.0
41
- Requires-Dist: pytmd==2.1.6
42
+ Requires-Dist: python-dateutil>=2.8.2
42
43
  Requires-Dist: pytz>=2022.1
43
44
  Requires-Dist: rasterio>=1.3.11
44
45
  Requires-Dist: rasterstats>=0.16.0
@@ -54,10 +55,11 @@ Requires-Dist: traitlets>=5.0.0
54
55
  Requires-Dist: xarray>=2022.3.0
55
56
  Provides-Extra: all
56
57
  Requires-Dist: affine>=2.3.1; extra == 'all'
57
- Requires-Dist: bs4>=0.0.1; extra == 'all'
58
+ Requires-Dist: beautifulsoup4>=4.12.0; extra == 'all'
58
59
  Requires-Dist: cmocean>=3.0.0; extra == 'all'
59
60
  Requires-Dist: contextily>=1.3.0; extra == 'all'
60
61
  Requires-Dist: dask-gateway>=2023.1.0; extra == 'all'
62
+ Requires-Dist: datacube-ows>=1.9.3; extra == 'all'
61
63
  Requires-Dist: datacube>=1.8.5; extra == 'all'
62
64
  Requires-Dist: gcsfs>=2022.1.0; extra == 'all'
63
65
  Requires-Dist: hdstats>=0.1.8.post1; extra == 'all'
@@ -73,6 +75,7 @@ Requires-Dist: statsmodels>=0.14.0; extra == 'all'
73
75
  Provides-Extra: dask-gateway
74
76
  Requires-Dist: dask-gateway>=2023.1.0; extra == 'dask-gateway'
75
77
  Provides-Extra: datacube
78
+ Requires-Dist: datacube-ows>=1.9.3; extra == 'datacube'
76
79
  Requires-Dist: datacube>=1.8.5; extra == 'datacube'
77
80
  Requires-Dist: odc-ui>=0.2.1; extra == 'datacube'
78
81
  Provides-Extra: hdstats
@@ -82,10 +85,12 @@ Requires-Dist: ipyleaflet>=0.17.0; extra == 'jupyter'
82
85
  Requires-Dist: jupyter>=1.0.0; extra == 'jupyter'
83
86
  Provides-Extra: notebooks
84
87
  Requires-Dist: affine>=2.3.1; extra == 'notebooks'
85
- Requires-Dist: bs4>=0.0.1; extra == 'notebooks'
88
+ Requires-Dist: beautifulsoup4>=4.12.0; extra == 'notebooks'
86
89
  Requires-Dist: cmocean>=3.0.0; extra == 'notebooks'
87
90
  Requires-Dist: contextily>=1.3.0; extra == 'notebooks'
88
91
  Requires-Dist: gcsfs>=2022.1.0; extra == 'notebooks'
92
+ Requires-Dist: ipyleaflet>=0.17.0; extra == 'notebooks'
93
+ Requires-Dist: jupyter>=1.0.0; extra == 'notebooks'
89
94
  Requires-Dist: opencv-python>=4.6.0.66; extra == 'notebooks'
90
95
  Requires-Dist: pydotplus>=2.0.0; extra == 'notebooks'
91
96
  Requires-Dist: statsmodels>=0.14.0; extra == 'notebooks'
@@ -95,9 +100,9 @@ Requires-Dist: planetary-computer>=1.0.0; extra == 'stac'
95
100
  Requires-Dist: pystac-client>=0.8.3; extra == 'stac'
96
101
  Description-Content-Type: text/markdown
97
102
 
98
- # dea-tools Python package
103
+ # DEA Tools Python package
99
104
 
100
- The `dea-tools` Python package provides a collection of functions and algorithms for geospatial analysis using Open Data Cube, Xarray, and Digital Earth Australia.
105
+ `dea_tools`` is an open-source Python package providing functions and algorithms for geospatial analysis using Open Data Cube, Xarray, and Digital Earth Australia.
101
106
  It includes utilities for loading data, plotting, spatial and temporal analysis, and applying machine learning to satellite data.
102
107
 
103
108
  The package is organised into the following modules:
@@ -110,7 +115,7 @@ The package is organised into the following modules:
110
115
  * `dea_tools.classification`: Machine learning utilities (e.g. training and applying models on satellite data)
111
116
  * `dea_tools.dask`: Utilities for parallel processing with Dask (e.g. creating scalable Dask clusters)
112
117
  * `dea_tools.landcover`: Tools for accessing and visualising DEA Land Cover data
113
- * `dea_tools.coastal`: Coastal and intertidal analysis tools (e.g. tidal tagging, coastal change time series)
118
+ * `dea_tools.coastal`: Coastal and intertidal analysis tools (e.g. coastal change time series, sunglint mapping)
114
119
  * `dea_tools.bom`: Accessing Bureau of Meteorology water data (e.g. gauge and discharge data)
115
120
  * `dea_tools.waterbodies`: Accessing and analysing DEA Waterbodies data (e.g. loading waterbody time series)
116
121
  * `dea_tools.maps`: Tools for interactive mapping (e.g. folium and ipyleaflet maps)
@@ -1,6 +1,6 @@
1
- # dea-tools Python package
1
+ # DEA Tools Python package
2
2
 
3
- The `dea-tools` Python package provides a collection of functions and algorithms for geospatial analysis using Open Data Cube, Xarray, and Digital Earth Australia.
3
+ `dea_tools`` is an open-source Python package providing functions and algorithms for geospatial analysis using Open Data Cube, Xarray, and Digital Earth Australia.
4
4
  It includes utilities for loading data, plotting, spatial and temporal analysis, and applying machine learning to satellite data.
5
5
 
6
6
  The package is organised into the following modules:
@@ -13,7 +13,7 @@ The package is organised into the following modules:
13
13
  * `dea_tools.classification`: Machine learning utilities (e.g. training and applying models on satellite data)
14
14
  * `dea_tools.dask`: Utilities for parallel processing with Dask (e.g. creating scalable Dask clusters)
15
15
  * `dea_tools.landcover`: Tools for accessing and visualising DEA Land Cover data
16
- * `dea_tools.coastal`: Coastal and intertidal analysis tools (e.g. tidal tagging, coastal change time series)
16
+ * `dea_tools.coastal`: Coastal and intertidal analysis tools (e.g. coastal change time series, sunglint mapping)
17
17
  * `dea_tools.bom`: Accessing Bureau of Meteorology water data (e.g. gauge and discharge data)
18
18
  * `dea_tools.waterbodies`: Accessing and analysing DEA Waterbodies data (e.g. loading waterbody time series)
19
19
  * `dea_tools.maps`: Tools for interactive mapping (e.g. folium and ipyleaflet maps)
@@ -1,4 +1,4 @@
1
1
  try:
2
2
  from .__version__ import version as __version__
3
3
  except ImportError:
4
- __version__ = None
4
+ __version__ = None
@@ -1,57 +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 fiona
9
- import sys
10
- import datacube
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
- from datacube.utils.geometry import CRS
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
- LayersControl,
25
- GeoData,
25
+ Marker,
26
+ SearchControl,
27
+ basemap_to_tiles,
28
+ basemaps,
26
29
  )
27
- from traitlets import Unicode
28
30
  from ipywidgets import (
29
- GridspecLayout,
31
+ HTML,
30
32
  Button,
31
- Layout,
33
+ GridspecLayout,
32
34
  HBox,
33
- VBox,
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 datacube.utils import masking
48
- from datacube.utils.geometry import Geometry
49
- from datacube.utils.masking import mask_invalid_data
50
- import dea_tools.app.widgetconstructors as deawidgets
41
+ from dea_tools.app.widgetconstructors import (
42
+ create_checkbox,
43
+ create_datepicker,
44
+ create_drawcontrol,
45
+ create_dropdown,
46
+ create_html,
47
+ create_map,
48
+ )
49
+ from dea_tools.coastal import get_coastlines
51
50
  from dea_tools.dask import create_local_dask_cluster
52
51
  from dea_tools.spatial import reverse_geocode
53
52
 
54
- import warnings
55
53
  warnings.filterwarnings("ignore")
56
54
 
57
55
  # WMS params and satellite style bands
@@ -137,14 +135,12 @@ def update_map_layers(self, update_basemap=False):
137
135
  self.query_params = None
138
136
 
139
137
  if update_basemap:
140
-
141
138
  # Clear all layers and add basemap
142
139
  self.map_layers.clear_layers()
143
140
  self.map_layers.add_layer(self.basemap)
144
141
 
145
142
 
146
143
  def extract_data(self):
147
-
148
144
  # Connect to datacube database
149
145
  dc = datacube.Datacube(app="Exporting satellite images")
150
146
 
@@ -166,15 +162,11 @@ def extract_data(self):
166
162
  }
167
163
 
168
164
  # Find matching datasets
169
- dss = [
170
- dc.find_datasets(product=i, **self.query_params)
171
- for i in sat_params[self.dealayer]["products"]
172
- ]
165
+ dss = [dc.find_datasets(product=i, **self.query_params) for i in sat_params[self.dealayer]["products"]]
173
166
  dss = list(itertools.chain.from_iterable(dss))
174
167
 
175
168
  # If data is found
176
169
  if len(dss) > 0:
177
-
178
170
  # Get CRS
179
171
  crs = str(dss[0].crs)
180
172
 
@@ -224,26 +216,21 @@ def extract_data(self):
224
216
 
225
217
 
226
218
  def plot_data(self, fname):
227
-
228
219
  # Data to plot
229
220
  to_plot = self.timeseries_ds
230
221
 
231
222
  # If rolling median specified
232
223
  if self.rolling_median:
233
224
  with self.status_info:
234
- print(
235
- f"\nApplying rolling median ({self.rolling_median_window} timesteps window)"
236
- )
237
- to_plot = to_plot.rolling(
238
- time=int(self.rolling_median_window), center=True, min_periods=1
239
- ).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()
240
227
 
241
228
  # Raise by power to dampen bright features and enhance dark.
242
229
  # Raise vmin and vmax by same amount to ensure proper stretch
243
230
  if self.power < 1.0:
244
231
  with self.status_info:
245
232
  print(f"\nApplying power transformation ({self.power})")
246
- to_plot = to_plot ** self.power
233
+ to_plot = to_plot**self.power
247
234
 
248
235
  # Apply unsharp masking to enhance overall dynamic range,
249
236
  # and improve fine scale detail
@@ -257,9 +244,7 @@ def plot_data(self, fname):
257
244
 
258
245
  funcs_list = [
259
246
  rescale_intensity,
260
- lambda x: unsharp_mask(
261
- x, radius=self.unsharp_mask_radius, amount=self.unsharp_mask_amount
262
- ),
247
+ lambda x: unsharp_mask(x, radius=self.unsharp_mask_radius, amount=self.unsharp_mask_amount),
263
248
  ]
264
249
  else:
265
250
  funcs_list = None
@@ -288,13 +273,6 @@ def plot_data(self, fname):
288
273
 
289
274
 
290
275
  def deacoastlines_overlay(ds):
291
-
292
- import geopandas as gpd
293
- import pandas as pd
294
- import matplotlib
295
- from shapely.geometry import box, Point
296
- from dea_tools.coastal import get_coastlines
297
-
298
276
  # Get bounding box of data
299
277
  xmin, ymin, xmax, ymax = ds.geobox.geographic_extent.boundingbox
300
278
  bounds = [xmin, ymin, xmax, ymax]
@@ -308,8 +286,8 @@ def deacoastlines_overlay(ds):
308
286
  deacl_gdf = deacl_gdf.dissolve("year") # values("year", ascending=True)
309
287
 
310
288
  # Apply colours
311
- norm = matplotlib.colors.Normalize(vmin=0, vmax=len(deacl_gdf.index))
312
- cmap = matplotlib.cm.get_cmap("inferno")
289
+ norm = mpl.colors.Normalize(vmin=0, vmax=len(deacl_gdf.index))
290
+ cmap = mpl.cm.get_cmap("inferno")
313
291
  rgba = cmap(norm(deacl_gdf.reset_index().index))
314
292
  deacl_gdf["color"] = list(rgba)
315
293
  deacl_gdf["start_time"] = pd.to_datetime(deacl_gdf.index) + pd.DateOffset(months=0)
@@ -317,8 +295,7 @@ def deacoastlines_overlay(ds):
317
295
 
318
296
  if len(deacl_gdf.index) > 0:
319
297
  return deacl_gdf
320
- else:
321
- return None
298
+ return None
322
299
 
323
300
 
324
301
  class animation_app(HBox):
@@ -338,15 +315,13 @@ class animation_app(HBox):
338
315
 
339
316
  # Satellite data
340
317
  end_date = datetime.datetime.today()
341
- start_date = datetime.datetime(
342
- year=end_date.year - 3, month=end_date.month, day=end_date.day
343
- )
318
+ start_date = datetime.datetime(year=end_date.year - 3, month=end_date.month, day=end_date.day)
344
319
  self.start_date = start_date.strftime("%Y-%m-%d")
345
320
  self.end_date = end_date.strftime("%Y-%m-%d")
346
321
  self.dealayer_list = [
347
322
  ("Landsat", "Landsat"),
348
323
  ("Sentinel-2", "Sentinel-2"),
349
- ("Sentinel-2 and Landsat", "Sentinel-2 and Landsat")
324
+ ("Sentinel-2 and Landsat", "Sentinel-2 and Landsat"),
350
325
  ]
351
326
  self.dealayer = self.dealayer_list[0][1]
352
327
 
@@ -395,16 +370,14 @@ class animation_app(HBox):
395
370
  ##################
396
371
 
397
372
  # Create the Header widget
398
- header_title_text = (
399
- "<h3>Digital Earth Australia satellite imagery animations</h3>"
400
- )
373
+ header_title_text = "<h3>Digital Earth Australia satellite imagery animations</h3>"
401
374
  instruction_text = (
402
375
  "<p>Select the desired satellite data, imagery date range "
403
376
  "and image style, then zoom in and draw a rectangle to "
404
377
  "select an area export as a satellite imagery time-series "
405
378
  "animation.</p>"
406
379
  )
407
- self.header = deawidgets.create_html(f"{header_title_text}{instruction_text}")
380
+ self.header = create_html(f"{header_title_text}{instruction_text}")
408
381
  self.header.layout = make_box_layout()
409
382
 
410
383
  #####################################
@@ -413,7 +386,6 @@ class animation_app(HBox):
413
386
 
414
387
  # Define the action to take once something is drawn on the map
415
388
  def update_geojson(target, action, geo_json):
416
-
417
389
  # Get data from action
418
390
  self.action = action
419
391
 
@@ -443,12 +415,7 @@ class animation_app(HBox):
443
415
  '<span style="color: #33cc33"> '
444
416
  "<b>(Overriding maximum size limit; use with caution as may lead to memory issues)</b></span>"
445
417
  )
446
- self.header.value = (
447
- header_title_text
448
- + instruction_text
449
- + polyarea_text
450
- + confirmation_text
451
- )
418
+ self.header.value = header_title_text + instruction_text + polyarea_text + confirmation_text
452
419
  self.gdf_drawn = gdf
453
420
  elif area <= 50000:
454
421
  confirmation_text = (
@@ -456,12 +423,7 @@ class animation_app(HBox):
456
423
  "<b>(Area to extract falls within "
457
424
  "recommended 50000 ha limit)</b></span>"
458
425
  )
459
- self.header.value = (
460
- header_title_text
461
- + instruction_text
462
- + polyarea_text
463
- + confirmation_text
464
- )
426
+ self.header.value = header_title_text + instruction_text + polyarea_text + confirmation_text
465
427
  self.gdf_drawn = gdf
466
428
  else:
467
429
  warning_text = (
@@ -470,9 +432,7 @@ class animation_app(HBox):
470
432
  "please select an area less than 50000 "
471
433
  "ha)</b></span>"
472
434
  )
473
- self.header.value = (
474
- header_title_text + instruction_text + polyarea_text + warning_text
475
- )
435
+ self.header.value = header_title_text + instruction_text + polyarea_text + warning_text
476
436
  self.gdf_drawn = None
477
437
 
478
438
  ###########################
@@ -488,24 +448,26 @@ class animation_app(HBox):
488
448
 
489
449
  # Create drawing tools
490
450
  desired_drawtools = ["rectangle"]
491
- draw_control = deawidgets.create_drawcontrol(desired_drawtools)
451
+ draw_control = create_drawcontrol(desired_drawtools)
492
452
 
493
453
  # Begin by displaying an empty layer group, and update the group with desired WMS on interaction.
494
454
  self.map_layers = LayerGroup(layers=())
495
455
  self.map_layers.name = "Map Overlays"
496
456
 
497
457
  # Create map widget
498
- self.m = deawidgets.create_map(map_center=(-33.96, 151.20), zoom_level=13)
458
+ self.m = create_map(map_center=(-33.96, 151.20), zoom_level=13)
499
459
  self.m.layout = make_box_layout()
500
460
 
501
461
  # Add tools to map widget
502
462
  self.m.add_control(draw_control)
503
- self.m.add_control(SearchControl(
504
- position="topleft",
505
- url='https://nominatim.openstreetmap.org/search?format=json&q={s}',
506
- zoom=13, # 'Village / Suburb' level zoom
507
- marker=Marker(draggable=False)
508
- ))
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
+ )
509
471
  self.m.add_layer(self.map_layers)
510
472
 
511
473
  # Update all maps to starting defaults
@@ -516,24 +478,16 @@ class animation_app(HBox):
516
478
  ############################
517
479
 
518
480
  # Create parameter widgets
519
- dropdown_basemap = deawidgets.create_dropdown(
520
- self.basemap_list, self.basemap_list[0][1]
521
- )
522
- dropdown_dealayer = deawidgets.create_dropdown(
523
- self.dealayer_list, self.dealayer_list[0][1]
524
- )
525
- dropdown_output = deawidgets.create_dropdown(
526
- self.output_list, self.output_list[0][1]
527
- )
528
- date_picker_start = deawidgets.create_datepicker(
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])
484
+ date_picker_start = create_datepicker(
529
485
  value=start_date,
530
486
  )
531
- date_picker_end = deawidgets.create_datepicker(
487
+ date_picker_end = create_datepicker(
532
488
  value=end_date,
533
489
  )
534
- dropdown_styles = deawidgets.create_dropdown(
535
- self.styles_list, self.styles_list[0]
536
- )
490
+ dropdown_styles = create_dropdown(self.styles_list, self.styles_list[0])
537
491
  slider_percentile = widgets.FloatRangeSlider(
538
492
  value=[0.01, 0.99],
539
493
  min=0,
@@ -553,7 +507,7 @@ class animation_app(HBox):
553
507
  layout={"width": "85%"},
554
508
  )
555
509
 
556
- checkbox_rolling_median = deawidgets.create_checkbox(
510
+ checkbox_rolling_median = create_checkbox(
557
511
  self.rolling_median,
558
512
  "Apply rolling median to produce smooth, cloud-free animations",
559
513
  layout={"width": "85%"},
@@ -571,26 +525,20 @@ class animation_app(HBox):
571
525
  )
572
526
 
573
527
  # Expandable advanced section
574
- text_interval = widgets.IntText(
575
- value=100, description="", step=50, layout={"width": "95%"}
576
- )
528
+ text_interval = widgets.IntText(value=100, description="", step=50, layout={"width": "95%"})
577
529
  text_resolution = widgets.FloatText(
578
530
  value=30,
579
531
  description="",
580
532
  layout={"width": "95%", "margin": "0px", "padding": "0px"},
581
533
  )
582
- text_width = widgets.IntText(
583
- value=900, description="", step=50, layout={"width": "95%"}
584
- )
585
- dropdown_resampling = deawidgets.create_dropdown(
534
+ text_width = widgets.IntText(value=900, description="", step=50, layout={"width": "95%"})
535
+ dropdown_resampling = create_dropdown(
586
536
  self.resample_list,
587
537
  self.resample_freq,
588
538
  description="",
589
539
  layout={"width": "95%"},
590
540
  )
591
- checkbox_cloud_mask = deawidgets.create_checkbox(
592
- self.cloud_mask, "Mask out cloudy pixels", layout={"width": "95%"}
593
- )
541
+ checkbox_cloud_mask = create_checkbox(self.cloud_mask, "Mask out cloudy pixels", layout={"width": "95%"})
594
542
  slider_power = widgets.FloatSlider(
595
543
  value=1.0,
596
544
  min=0.01,
@@ -599,9 +547,7 @@ class animation_app(HBox):
599
547
  description="",
600
548
  layout={"width": "95%"},
601
549
  )
602
- checkbox_unsharp_mask = deawidgets.create_checkbox(
603
- self.unsharp_mask, "Enable", layout={"width": "95%"}
604
- )
550
+ checkbox_unsharp_mask = create_checkbox(self.unsharp_mask, "Enable", layout={"width": "95%"})
605
551
  text_unsharp_mask_radius = widgets.FloatText(
606
552
  value=20,
607
553
  step=1,
@@ -624,12 +570,10 @@ class animation_app(HBox):
624
570
  "display": "none",
625
571
  },
626
572
  )
627
- checkbox_deacoastlines = deawidgets.create_checkbox(
573
+ checkbox_deacoastlines = create_checkbox(
628
574
  self.deacoastlines, "Add DEA Coastlines overlay", layout={"width": "95%"}
629
575
  )
630
- checkbox_max_size = deawidgets.create_checkbox(
631
- self.max_size, "Enable", layout={"width": "95%"}
632
- )
576
+ checkbox_max_size = create_checkbox(self.max_size, "Enable", layout={"width": "95%"})
633
577
  expand_box = widgets.VBox(
634
578
  [
635
579
  HTML("Frame interval (milliseconds):"),
@@ -649,9 +593,7 @@ class animation_app(HBox):
649
593
  checkbox_unsharp_mask,
650
594
  text_unsharp_mask_radius,
651
595
  text_unsharp_mask_amount,
652
- HTML(
653
- "</br>Override maximum size limit: (use with caution; may cause memory issues/crashes)"
654
- ),
596
+ HTML("</br>Override maximum size limit: (use with caution; may cause memory issues/crashes)"),
655
597
  checkbox_max_size,
656
598
  ],
657
599
  )
@@ -680,13 +622,9 @@ class animation_app(HBox):
680
622
  dropdown_styles.observe(self.update_styles, "value")
681
623
 
682
624
  slider_percentile.observe(self.update_slider_percentile, "value")
683
- floatslider_max_cloud_cover.observe(
684
- self.update_floatslider_max_cloud_cover, "value"
685
- )
625
+ floatslider_max_cloud_cover.observe(self.update_floatslider_max_cloud_cover, "value")
686
626
  checkbox_rolling_median.observe(self.update_checkbox_rolling_median, "value")
687
- text_rolling_median_window.observe(
688
- self.update_text_rolling_median_window, "value"
689
- )
627
+ text_rolling_median_window.observe(self.update_text_rolling_median_window, "value")
690
628
  dropdown_output.observe(self.update_output, "value")
691
629
  run_button.on_click(self.run_app)
692
630
  draw_control.on_draw(update_geojson)
@@ -708,34 +646,30 @@ class animation_app(HBox):
708
646
  # COLLECTION OF ALL APP CONTROLS #
709
647
  ##################################
710
648
 
711
- parameter_selection = VBox(
712
- [
713
- HTML("<b>Start date:</b>"),
714
- date_picker_start,
715
- HTML("<b>End date:</b>"),
716
- date_picker_end,
717
- HTML("<b>Satellite imagery:</b>"),
718
- dropdown_dealayer,
719
- HTML("<b>Style:</b>"),
720
- dropdown_styles,
721
- HTML("<b>Colour percentile stretch:</b>"),
722
- slider_percentile,
723
- HTML("<b>Maximum cloud cover (%):</b>"),
724
- floatslider_max_cloud_cover,
725
- checkbox_rolling_median,
726
- text_rolling_median_window,
727
- HTML("</br><b>Output file format:</b>"),
728
- dropdown_output,
729
- HTML("</br>"),
730
- expand,
731
- ]
732
- )
733
- map_selection = VBox(
734
- [
735
- HTML("</br><b>Map overlay:</b>"),
736
- dropdown_basemap,
737
- ]
738
- )
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
+ ])
739
673
  parameter_selection.layout = make_box_layout()
740
674
  map_selection.layout = make_box_layout()
741
675
 
@@ -810,10 +744,10 @@ class animation_app(HBox):
810
744
 
811
745
  elif change.new == "Sentinel-2":
812
746
  self.text_resolution.value = 10
813
-
747
+
814
748
  elif change.new == "Sentinel-2 and Landsat":
815
749
  self.text_resolution.value = 30
816
-
750
+
817
751
  # Clear data load params to trigger data re-load
818
752
  update_map_layers(self)
819
753
 
@@ -915,16 +849,13 @@ class animation_app(HBox):
915
849
  update_map_layers(self)
916
850
 
917
851
  def run_app(self, change):
918
-
919
852
  # Clear progress bar and output areas before running
920
853
  self.status_info.clear_output()
921
854
  self.output_plot.clear_output()
922
855
 
923
856
  # Verify that polygon was drawn
924
857
  if self.gdf_drawn is not None:
925
-
926
858
  with self.status_info:
927
-
928
859
  # Load data and add to attribute
929
860
  if self.timeseries_ds is None:
930
861
  self.timeseries_ds = extract_data(self)
@@ -933,9 +864,7 @@ class animation_app(HBox):
933
864
  print("Using previously loaded data")
934
865
 
935
866
  if self.timeseries_ds is not None:
936
-
937
867
  with self.status_info:
938
-
939
868
  # Create unique file name
940
869
  centre_coords = self.gdf_drawn.geometry[0].centroid.coords[0][::-1]
941
870
  site = reverse_geocode(coords=centre_coords)
@@ -947,9 +876,7 @@ class animation_app(HBox):
947
876
  .lower()
948
877
  )
949
878
 
950
- print(
951
- f"\nExporting animation for {site}.\nThis may take several minutes..."
952
- )
879
+ print(f"\nExporting animation for {site}.\nThis may take several minutes...")
953
880
 
954
881
  ############
955
882
  # Plotting #
@@ -968,6 +895,4 @@ class animation_app(HBox):
968
895
 
969
896
  else:
970
897
  with self.status_info:
971
- print(
972
- 'Please draw a valid rectangle on the map, then press "Generate animation".'
973
- )
898
+ print('Please draw a valid rectangle on the map, then press "Generate animation".')