dea-tools 0.3.7.dev14__tar.gz → 0.3.7.dev15__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 (34) hide show
  1. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/PKG-INFO +2 -2
  2. dea_tools-0.3.7.dev15/dea_tools/coastal.py +304 -0
  3. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/pyproject.toml +2 -7
  4. dea_tools-0.3.7.dev14/dea_tools/coastal.py +0 -2268
  5. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/.gitignore +0 -0
  6. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/LICENSE +0 -0
  7. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/README_tools.md +0 -0
  8. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/__init__.py +0 -0
  9. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/__main__.py +0 -0
  10. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/__init__.py +0 -0
  11. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/animations.py +0 -0
  12. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/changefilmstrips.py +0 -0
  13. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/crophealth.py +0 -0
  14. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/deacoastlines.py +0 -0
  15. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/geomedian.py +0 -0
  16. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/imageexport.py +0 -0
  17. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/miningrehab.py +0 -0
  18. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/wetlandsinsighttool.py +0 -0
  19. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/app/widgetconstructors.py +0 -0
  20. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/bandindices.py +0 -0
  21. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/bom.py +0 -0
  22. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/classification.py +0 -0
  23. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/dask.py +0 -0
  24. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/datahandling.py +0 -0
  25. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/landcover.py +0 -0
  26. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/maps.py +0 -0
  27. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/plotting.py +0 -0
  28. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/pyfes_model.py +0 -0
  29. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/spatial.py +0 -0
  30. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/temporal.py +0 -0
  31. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/validation.py +0 -0
  32. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/waterbodies.py +0 -0
  33. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/wetlands.py +0 -0
  34. {dea_tools-0.3.7.dev14 → dea_tools-0.3.7.dev15}/dea_tools/wit_app.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dea-tools
3
- Version: 0.3.7.dev14
3
+ Version: 0.3.7.dev15
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,6 @@ 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
42
  Requires-Dist: pytz>=2022.1
43
43
  Requires-Dist: rasterio>=1.3.11
44
44
  Requires-Dist: rasterstats>=0.16.0
@@ -0,0 +1,304 @@
1
+ ## dea_coastaltools.py
2
+ """
3
+ Coastal analysis tools.
4
+
5
+ License: The code in this notebook is licensed under the Apache License,
6
+ Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0). Digital Earth
7
+ Australia data is licensed under the Creative Commons by Attribution 4.0
8
+ license (https://creativecommons.org/licenses/by/4.0/).
9
+
10
+ Contact: If you need assistance, post a question on the Open Data Cube
11
+ Discord chat (https://discord.com/invite/4hhBQVas5U) or the GIS Stack Exchange
12
+ (https://gis.stackexchange.com/questions/ask?tags=open-data-cube) using
13
+ the `open-data-cube` tag (you can view previously asked questions here:
14
+ https://gis.stackexchange.com/questions/tagged/open-data-cube).
15
+
16
+ If you would like to report an issue with this script, you can file one
17
+ on GitHub (https://github.com/GeoscienceAustralia/dea-notebooks/issues/new).
18
+
19
+ Last modified: July 2024
20
+
21
+ """
22
+
23
+ # Import required packages
24
+ import warnings
25
+
26
+ import geopandas as gpd
27
+ import numpy as np
28
+ import pandas as pd
29
+ from owslib.wfs import WebFeatureService
30
+ from pandas.plotting import register_matplotlib_converters
31
+ from shapely.geometry import box
32
+
33
+ register_matplotlib_converters()
34
+
35
+
36
+ WFS_ADDRESS = "https://geoserver.dea.ga.gov.au/geoserver/wfs"
37
+
38
+
39
+ def transect_distances(transects_gdf, lines_gdf, mode="distance"):
40
+ """
41
+ Take a set of transects (e.g. shore-normal beach survey lines), and
42
+ determine the distance along the transect to each object in a set of
43
+ lines (e.g. shorelines). Distances are measured in the CRS of the
44
+ input datasets.
45
+
46
+ For coastal applications, transects should be drawn from land to
47
+ water (with the first point being on land so that it can be used
48
+ as a consistent location from which to measure distances.
49
+
50
+ The distance calculation can be performed using two modes:
51
+ - 'distance': Distances are measured from the start of the
52
+ transect to where it intersects with each line. Any transect
53
+ that intersects a line more than once is ignored. This mode is
54
+ useful for measuring e.g. the distance to the shoreline over
55
+ time from a consistent starting location.
56
+ - 'width' Distances are measured between the first and last
57
+ intersection between a transect and each line. Any transect
58
+ that intersects a line only once is ignored. This is useful
59
+ for e.g. measuring the width of a narrow area of coastline over
60
+ time, e.g. the neck of a spit or tombolo.
61
+
62
+ Parameters
63
+ ----------
64
+ transects_gdf : geopandas.GeoDataFrame
65
+ A GeoDataFrame containing one or multiple vector profile lines.
66
+ The GeoDataFrame's index column will be used to name the rows in
67
+ the output distance table.
68
+ lines_gdf : geopandas.GeoDataFrame
69
+ A GeoDataFrame containing one or multiple vector line features
70
+ that intersect the profile lines supplied to `transects_gdf`.
71
+ The GeoDataFrame's index column will be used to name the columns
72
+ in the output distance table.
73
+ mode : string, optional
74
+ Whether to use 'distance' (for measuring distances from the
75
+ start of a profile) or 'width' mode (for measuring the width
76
+ between two profile intersections). See docstring above for more
77
+ info; defaults to 'distance'.
78
+
79
+ Returns
80
+ -------
81
+ distance_df : pandas.DataFrame
82
+ A DataFrame containing distance measurements for each profile
83
+ line (rows) and line feature (columns).
84
+ """
85
+
86
+ from shapely.errors import ShapelyDeprecationWarning
87
+ from shapely.geometry import Point
88
+
89
+ def _intersect_dist(transect_gdf, lines_gdf, mode=mode):
90
+ """
91
+ Take an individual transect, and determine the distance along
92
+ the transect to each object in a set of lines (e.g. shorelines).
93
+ """
94
+
95
+ # Identify intersections between transects and lines
96
+ intersect_points = lines_gdf.apply(lambda x: x.geometry.intersection(transect_gdf.geometry), axis=1)
97
+
98
+ # In distance mode, identify transects with one intersection only,
99
+ # and use this as the end point and the start of the transect as the
100
+ # start point when measuring distances
101
+ if mode == "distance":
102
+ start_point = Point(transect_gdf.geometry.coords[0])
103
+ point_df = intersect_points.apply(
104
+ lambda x: (
105
+ pd.Series({"start": start_point, "end": x})
106
+ if x.type == "Point"
107
+ else pd.Series({"start": None, "end": None})
108
+ )
109
+ )
110
+
111
+ # In width mode, identify transects with multiple intersections, and
112
+ # use the first intersection as the start point and the second
113
+ # intersection for the end point when measuring distances
114
+ if mode == "width":
115
+ point_df = intersect_points.apply(
116
+ lambda x: (
117
+ pd.Series({"start": x.geoms[0], "end": x.geoms[-1]})
118
+ if x.type == "MultiPoint"
119
+ else pd.Series({"start": None, "end": None})
120
+ )
121
+ )
122
+
123
+ # Calculate distances between valid start and end points
124
+ return point_df.apply(lambda x: x.start.distance(x.end) if x.start else None, axis=1)
125
+
126
+ # Run code after ignoring Shapely pre-v2.0 warnings
127
+ with warnings.catch_warnings():
128
+ warnings.filterwarnings("ignore", category=ShapelyDeprecationWarning)
129
+
130
+ # Assert that both datasets use the same CRS
131
+ assert transects_gdf.crs == lines_gdf.crs, "Please ensure both input datasets use the same CRS."
132
+
133
+ # Run distance calculations
134
+ distance_df = transects_gdf.apply(lambda x: _intersect_dist(x, lines_gdf), axis=1)
135
+
136
+ return pd.DataFrame(distance_df)
137
+
138
+
139
+ def get_coastlines(bbox: tuple, crs="EPSG:4326", layer="shorelines_annual", drop_wms=True) -> gpd.GeoDataFrame:
140
+ """
141
+ Load DEA Coastlines annual shorelines or rates of change points data
142
+ for a provided bounding box using WFS.
143
+
144
+ For a full description of the DEA Coastlines dataset, refer to the
145
+ official Geoscience Australia product description:
146
+ /data/product/dea-coastlines
147
+
148
+ Parameters
149
+ ----------
150
+ bbox : (xmin, ymin, xmax, ymax), or geopandas object
151
+ Bounding box expressed as a tutple. Alternatively, a bounding
152
+ box can be automatically extracted by suppling a
153
+ geopandas.GeoDataFrame or geopandas.GeoSeries.
154
+ crs : str, optional
155
+ Optional CRS for the bounding box. This is ignored if `bbox`
156
+ is provided as a geopandas object.
157
+ layer : str, optional
158
+ Which DEA Coastlines layer to load. Options include the annual
159
+ shoreline vectors ("shorelines_annual") and the rates of change
160
+ points ("rates_of_change"). Defaults to "shorelines_annual".
161
+ drop_wms : bool, optional
162
+ Whether to drop WMS-specific attribute columns from the data.
163
+ These columns are used for visualising the dataset on DEA Maps,
164
+ and are unlikely to be useful for scientific analysis. Defaults
165
+ to True.
166
+
167
+ Returns
168
+ -------
169
+ gpd.GeoDataFrame
170
+ A GeoDataFrame containing shoreline or point features and
171
+ associated metadata.
172
+ """
173
+
174
+ # If bbox is a geopandas object, convert to bbox
175
+ try:
176
+ crs = str(bbox.crs)
177
+ bbox = bbox.total_bounds
178
+ except:
179
+ pass
180
+
181
+ # Query WFS
182
+ wfs = WebFeatureService(url=WFS_ADDRESS, version="1.1.0")
183
+ layer_name = f"dea:{layer}"
184
+ response = wfs.getfeature(
185
+ typename=layer_name,
186
+ bbox=tuple(bbox) + (crs,),
187
+ outputFormat="json",
188
+ )
189
+
190
+ # Load data as a geopandas.GeoDataFrame
191
+ coastlines_gdf = gpd.read_file(response)
192
+
193
+ # Clip to extent of bounding box
194
+ extent = gpd.GeoSeries(box(*bbox), crs=crs).to_crs(coastlines_gdf.crs)
195
+ coastlines_gdf = coastlines_gdf.clip(extent)
196
+
197
+ # Optionally drop WMS-specific columns
198
+ if drop_wms:
199
+ coastlines_gdf = coastlines_gdf.loc[:, ~coastlines_gdf.columns.str.contains("wms_")]
200
+
201
+ return coastlines_gdf
202
+
203
+
204
+ def glint_angle(solar_azimuth, solar_zenith, view_azimuth, view_zenith):
205
+ """
206
+ Calculates glint angles for each pixel in a satellite image based
207
+ on the relationship between the solar and sensor zenith and azimuth
208
+ viewing angles at the moment the image was acquired.
209
+
210
+ Glint angle is considered a predictor of sunglint over water; small
211
+ glint angles (e.g. < 20 degrees) are associated with a high
212
+ probability of sunglint due to the viewing angle of the sensor
213
+ being aligned with specular reflectance of the sun from the water's
214
+ surface.
215
+
216
+ Based on code from https://towardsdatascience.com/how-to-implement-
217
+ sunglint-detection-for-sentinel-2-images-in-python-using-metadata-
218
+ info-155e683d50
219
+
220
+ Parameters
221
+ ----------
222
+ solar_azimuth : array-like
223
+ Array of solar azimuth angles in degrees. In DEA Collection 3,
224
+ this is contained in the "oa_solar_azimuth" band.
225
+ solar_zenith : array-like
226
+ Array of solar zenith angles in degrees. In DEA Collection 3,
227
+ this is contained in the "oa_solar_zenith" band.
228
+ view_azimuth : array-like
229
+ Array of sensor/viewing azimuth angles in degrees. In DEA
230
+ Collection 3, this is contained in the "oa_satellite_azimuth"
231
+ band.
232
+ view_zenith : array-like
233
+ Array of sensor/viewing zenith angles in degrees. In DEA
234
+ Collection 3, this is contained in the "oa_satellite_view" band.
235
+
236
+ Returns
237
+ -------
238
+ glint_array : numpy.ndarray
239
+ Array of glint angles in degrees. Small values indicate higher
240
+ probabilities of sunglint.
241
+ """
242
+
243
+ # Convert angle arrays to radians
244
+ solar_zenith_rad = np.deg2rad(solar_zenith)
245
+ solar_azimuth_rad = np.deg2rad(solar_azimuth)
246
+ view_zenith_rad = np.deg2rad(view_zenith)
247
+ view_azimuth_rad = np.deg2rad(view_azimuth)
248
+
249
+ # Calculate sunglint angle
250
+ phi = solar_azimuth_rad - view_azimuth_rad
251
+ glint_angle = np.cos(view_zenith_rad) * np.cos(solar_zenith_rad) - np.sin(view_zenith_rad) * np.sin(
252
+ solar_zenith_rad
253
+ ) * np.cos(phi)
254
+
255
+ # Convert to degrees
256
+ return np.degrees(np.arccos(glint_angle))
257
+
258
+
259
+ def model_tides(*args, **kwargs):
260
+ raise ImportError(
261
+ "The `model_tides` function has been removed and is no longer available in this package.\n"
262
+ "Please install and use the `eo-tides` package instead:\n"
263
+ "https://geoscienceaustralia.github.io/eo-tides/migration/"
264
+ )
265
+
266
+
267
+ def pixel_tides(*args, **kwargs):
268
+ raise ImportError(
269
+ "The `pixel_tides` function has been removed and is no longer available in this package.\n"
270
+ "Please install and use the `eo-tides` package instead:\n"
271
+ "https://geoscienceaustralia.github.io/eo-tides/migration/"
272
+ )
273
+
274
+
275
+ def tidal_tag(*args, **kwargs):
276
+ raise ImportError(
277
+ "The `tidal_tag` function has been removed and is no longer available in this package.\n"
278
+ "Please install and use the `eo-tides` package instead:\n"
279
+ "https://geoscienceaustralia.github.io/eo-tides/migration/"
280
+ )
281
+
282
+
283
+ def tidal_stats(*args, **kwargs):
284
+ raise ImportError(
285
+ "The `tidal_stats` function has been removed and is no longer available in this package.\n"
286
+ "Please install and use the `eo-tides` package instead:\n"
287
+ "https://geoscienceaustralia.github.io/eo-tides/migration/"
288
+ )
289
+
290
+
291
+ def tidal_tag_otps(*args, **kwargs):
292
+ raise ImportError(
293
+ "The `tidal_tag_otps` function has been removed and is no longer available in this package.\n"
294
+ "Please install and use the `eo-tides` package instead:\n"
295
+ "https://geoscienceaustralia.github.io/eo-tides/migration/"
296
+ )
297
+
298
+
299
+ def tidal_stats_otps(*args, **kwargs):
300
+ raise ImportError(
301
+ "The `tidal_stats_otps` function has been removed and is no longer available in this package.\n"
302
+ "Please install and use the `eo-tides` package instead:\n"
303
+ "https://geoscienceaustralia.github.io/eo-tides/migration/"
304
+ )
@@ -33,7 +33,7 @@ dependencies = [
33
33
  # "ciso8601>=2.2.0", # blocks Python 3.13 installation on Windows
34
34
  "dask>=2023.1.0",
35
35
  "dask-ml>=2023.3.24",
36
- # "eo-tides>=0.7.4", # requires notebook updates
36
+ "eo-tides>=0.8.0",
37
37
  "fiona>=1.10.0",
38
38
  "folium>=0.16.0",
39
39
  "geopandas>=0.10.0",
@@ -50,7 +50,6 @@ dependencies = [
50
50
  "packaging>=22.0",
51
51
  "pandas>=2.2.0",
52
52
  "pyproj>=3.7.0",
53
- "pyTMD==2.1.6",
54
53
  "pytz>=2022.1",
55
54
  "rasterio>=1.3.11",
56
55
  "rasterstats>=0.16.0",
@@ -203,9 +202,7 @@ opencv-python = "cv2"
203
202
  # Project should not contain missing dependencies
204
203
  DEP001 = [
205
204
  "ciso8601", # currently hard to install, candidate for removal
206
- "datacube_ows", # currently hard to install, candidate for removal
207
- "otps", # to fix with eo-tides refactor
208
- "pyfes", # to fix with eo-tides refactor
205
+ "datacube_ows", # temporarily removed until dependency issue fixed at source
209
206
  "intertidal", # to fix with Sandbox upgrade
210
207
  "osgeo", # ignore due to confusion with gdal package
211
208
  "ipywidgets", # covered by jupyter metapackage
@@ -218,13 +215,11 @@ DEP002 = [
218
215
  "pystac-client", # included for local STAC support
219
216
  "odc-stac", # included for local STAC support
220
217
  "planetary_computer", # included for STAC support
221
- "eo-tides", # to fix with eo-tides refactor
222
218
  "odc-ui", # ignore `odc.ui` not being recognised as `odc-ui`
223
219
  "numba", # required to enforce minimum version of llvmlite
224
220
  ]
225
221
  # Project should not use transitive dependencies
226
222
  DEP003 = [
227
- "pyTMD", # to fix with eo-tides refactor
228
223
  "ipywidgets", # covered by jupyter metapackage
229
224
  "IPython", # covered by jupyter metapackage
230
225
  ]