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.
Files changed (35) hide show
  1. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/PKG-INFO +1 -1
  2. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/__init__.py +1 -1
  3. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/animations.py +92 -176
  4. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/changefilmstrips.py +136 -163
  5. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/crophealth.py +53 -85
  6. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/deacoastlines.py +98 -133
  7. dea_tools-0.3.7.dev14/dea_tools/app/geomedian.py +246 -0
  8. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/imageexport.py +81 -164
  9. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/miningrehab.py +26 -36
  10. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/wetlandsinsighttool.py +78 -137
  11. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/app/widgetconstructors.py +104 -145
  12. dea_tools-0.3.7.dev14/dea_tools/bandindices.py +393 -0
  13. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/bom.py +73 -90
  14. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/classification.py +92 -224
  15. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/coastal.py +133 -246
  16. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/dask.py +21 -22
  17. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/datahandling.py +43 -98
  18. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/landcover.py +396 -524
  19. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/maps.py +68 -64
  20. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/plotting.py +320 -377
  21. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/pyfes_model.py +6 -4
  22. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/spatial.py +74 -146
  23. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/temporal.py +41 -79
  24. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/validation.py +8 -11
  25. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/waterbodies.py +24 -28
  26. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/wetlands.py +27 -35
  27. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/wit_app.py +44 -57
  28. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/pyproject.toml +1 -1
  29. dea_tools-0.3.7.dev13/dea_tools/app/geomedian.py +0 -126
  30. dea_tools-0.3.7.dev13/dea_tools/bandindices.py +0 -432
  31. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/.gitignore +0 -0
  32. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/LICENSE +0 -0
  33. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/README_tools.md +0 -0
  34. {dea_tools-0.3.7.dev13 → dea_tools-0.3.7.dev14}/dea_tools/__main__.py +0 -0
  35. {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.dev13
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,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,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 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
- 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
- create_dea_wms_layer,
46
+ create_html,
47
+ create_map,
59
48
  )
60
- from ..dask import create_local_dask_cluster
61
- from ..spatial import reverse_geocode
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
- f"\nApplying rolling median ({self.rolling_median_window} timesteps window)"
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 ** self.power
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 = matplotlib.colors.Normalize(vmin=0, vmax=len(deacl_gdf.index))
321
- 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")
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
- else:
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(SearchControl(
513
- position="topleft",
514
- url='https://nominatim.openstreetmap.org/search?format=json&q={s}',
515
- zoom=13, # 'Village / Suburb' level zoom
516
- marker=Marker(draggable=False)
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
- self.basemap_list, self.basemap_list[0][1]
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
- HTML("<b>Start date:</b>"),
723
- date_picker_start,
724
- HTML("<b>End date:</b>"),
725
- date_picker_end,
726
- HTML("<b>Satellite imagery:</b>"),
727
- dropdown_dealayer,
728
- HTML("<b>Style:</b>"),
729
- dropdown_styles,
730
- HTML("<b>Colour percentile stretch:</b>"),
731
- slider_percentile,
732
- HTML("<b>Maximum cloud cover (%):</b>"),
733
- floatslider_max_cloud_cover,
734
- checkbox_rolling_median,
735
- text_rolling_median_window,
736
- HTML("</br><b>Output file format:</b>"),
737
- dropdown_output,
738
- HTML("</br>"),
739
- expand,
740
- ]
741
- )
742
- map_selection = VBox(
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".')