eo-tides 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl

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.
eo_tides/stats.py CHANGED
@@ -13,10 +13,13 @@ from scipy import stats
13
13
 
14
14
  # Only import if running type checking
15
15
  if TYPE_CHECKING:
16
+ import datetime
17
+
16
18
  import xarray as xr
19
+ from odc.geo.geobox import GeoBox
17
20
 
18
- from .eo import pixel_tides, tag_tides
19
- from .model import model_tides
21
+ from .eo import _standardise_inputs, pixel_tides, tag_tides
22
+ from .model import DatetimeLike, model_tides
20
23
 
21
24
 
22
25
  def _plot_biases(
@@ -136,7 +139,8 @@ def _plot_biases(
136
139
 
137
140
 
138
141
  def tide_stats(
139
- ds: xr.Dataset,
142
+ data: xr.Dataset | xr.DataArray | GeoBox,
143
+ time: DatetimeLike | None = None,
140
144
  model: str = "EOT20",
141
145
  directory: str | os.PathLike | None = None,
142
146
  tidepost_lat: float | None = None,
@@ -167,15 +171,23 @@ def tide_stats(
167
171
 
168
172
  Parameters
169
173
  ----------
170
- ds : xarray.Dataset
171
- A multi-dimensional dataset (e.g. "x", "y", "time") used
172
- to calculate tide statistics. This dataset must contain
173
- a "time" dimension.
174
- model : string, optional
174
+ data : xarray.Dataset or xarray.DataArray or odc.geo.geobox.GeoBox
175
+ A multi-dimensional dataset or GeoBox pixel grid that will
176
+ be used to calculate tide statistics. If `data` is an
177
+ xarray object, it should include a "time" dimension.
178
+ If no "time" dimension exists or if `data` is a GeoBox,
179
+ then times must be passed using the `time` parameter.
180
+ time : DatetimeLike, optional
181
+ By default, tides will be modelled using times from the
182
+ "time" dimension of `data`. Alternatively, this param can
183
+ be used to provide a custom set of times. Accepts any format
184
+ that can be converted by `pandas.to_datetime()`. For example:
185
+ `time=pd.date_range(start="2000", end="2001", freq="5h")`
186
+ model : str, optional
175
187
  The tide model to use to model tides. Defaults to "EOT20";
176
188
  for a full list of available/supported models, run
177
189
  `eo_tides.model.list_models`.
178
- directory : string, optional
190
+ directory : str, optional
179
191
  The directory containing tide model data files. If no path is
180
192
  provided, this will default to the environment variable
181
193
  `EO_TIDES_TIDE_MODELS` if set, or raise an error if not.
@@ -201,7 +213,7 @@ def tide_stats(
201
213
  An optional string giving the frequency at which to model tides
202
214
  when computing the full modelled tidal range. Defaults to '3h',
203
215
  which computes a tide height for every three hours across the
204
- temporal extent of `ds`.
216
+ temporal extent of `data`.
205
217
  linear_reg: bool, optional
206
218
  Whether to return linear regression statistics that assess
207
219
  whether satellite-observed tides show any decreasing or
@@ -247,6 +259,9 @@ def tide_stats(
247
259
  - `observed_slope`: slope of any relationship between observed tide heights and time
248
260
  - `observed_pval`: significance/p-value of any relationship between observed tide heights and time
249
261
  """
262
+ # Standardise data inputs, time and models
263
+ gbox, time_coords = _standardise_inputs(data, time)
264
+
250
265
  # Verify that only one tide model is provided
251
266
  if isinstance(model, list):
252
267
  raise Exception("Only single tide models are supported by `tide_stats`.")
@@ -254,11 +269,13 @@ def tide_stats(
254
269
  # If custom tide modelling locations are not provided, use the
255
270
  # dataset centroid
256
271
  if not tidepost_lat or not tidepost_lon:
257
- tidepost_lon, tidepost_lat = ds.odc.geobox.geographic_extent.centroid.coords[0]
272
+ tidepost_lon, tidepost_lat = gbox.geographic_extent.centroid.coords[0]
258
273
 
259
274
  # Model tides for each observation in the supplied xarray object
275
+ assert time_coords is not None
260
276
  obs_tides_da = tag_tides(
261
- ds,
277
+ gbox,
278
+ time=time_coords,
262
279
  model=model,
263
280
  directory=directory,
264
281
  tidepost_lat=tidepost_lat, # type: ignore
@@ -266,12 +283,13 @@ def tide_stats(
266
283
  return_tideposts=True,
267
284
  **model_tides_kwargs,
268
285
  )
269
- obs_tides_da = obs_tides_da.sortby("time")
286
+ if isinstance(data, (xr.Dataset, xr.DataArray)):
287
+ obs_tides_da = obs_tides_da.reindex_like(data)
270
288
 
271
289
  # Generate range of times covering entire period of satellite record
272
290
  all_timerange = pd.date_range(
273
- start=obs_tides_da.time.min().item(),
274
- end=obs_tides_da.time.max().item(),
291
+ start=time_coords.min().item(),
292
+ end=time_coords.max().item(),
275
293
  freq=modelled_freq,
276
294
  )
277
295
 
@@ -355,7 +373,7 @@ def tide_stats(
355
373
  offset_low=low_tide_offset,
356
374
  offset_high=high_tide_offset,
357
375
  spread=spread,
358
- plot_col=ds[plot_col] if plot_col else None,
376
+ plot_col=data[plot_col] if plot_col else None,
359
377
  obs_linreg=obs_linreg if linear_reg else None,
360
378
  obs_x=obs_x,
361
379
  all_timerange=all_timerange,
@@ -390,12 +408,13 @@ def tide_stats(
390
408
 
391
409
 
392
410
  def pixel_stats(
393
- ds: xr.Dataset | xr.DataArray,
411
+ data: xr.Dataset | xr.DataArray | GeoBox,
412
+ time: DatetimeLike | None = None,
394
413
  model: str | list[str] = "EOT20",
395
414
  directory: str | os.PathLike | None = None,
396
415
  resample: bool = False,
397
- modelled_freq="3h",
398
- min_max_q=(0.0, 1.0),
416
+ modelled_freq: str = "3h",
417
+ min_max_q: tuple[float, float] = (0.0, 1.0),
399
418
  extrapolate: bool = True,
400
419
  cutoff: float = 10,
401
420
  **pixel_tides_kwargs,
@@ -420,13 +439,21 @@ def pixel_stats(
420
439
 
421
440
  Parameters
422
441
  ----------
423
- ds : xarray.Dataset or xarray.DataArray
424
- A multi-dimensional dataset (e.g. "x", "y", "time") used
425
- to calculate 2D tide statistics. This dataset must contain
426
- a "time" dimension.
442
+ data : xarray.Dataset or xarray.DataArray or odc.geo.geobox.GeoBox
443
+ A multi-dimensional dataset or GeoBox pixel grid that will
444
+ be used to calculate 2D tide statistics. If `data`
445
+ is an xarray object, it should include a "time" dimension.
446
+ If no "time" dimension exists or if `data` is a GeoBox,
447
+ then times must be passed using the `time` parameter.
448
+ time : DatetimeLike, optional
449
+ By default, tides will be modelled using times from the
450
+ "time" dimension of `data`. Alternatively, this param can
451
+ be used to provide a custom set of times. Accepts any format
452
+ that can be converted by `pandas.to_datetime()`. For example:
453
+ `time=pd.date_range(start="2000", end="2001", freq="5h")`
427
454
  model : str or list of str, optional
428
455
  The tide model (or models) to use to model tides. If a list is
429
- provided, a new "tide_model" dimension will be added to `ds`.
456
+ provided, a new "tide_model" dimension will be added to `data`.
430
457
  Defaults to "EOT20"; for a full list of available/supported
431
458
  models, run `eo_tides.model.list_models`.
432
459
  directory : str, optional
@@ -437,7 +464,7 @@ def pixel_stats(
437
464
  model that match the structure required by `pyTMD`
438
465
  (<https://geoscienceaustralia.github.io/eo-tides/setup/>).
439
466
  resample : bool, optional
440
- Whether to resample tide statistics back into `ds`'s original
467
+ Whether to resample tide statistics back into `data`'s original
441
468
  higher resolution grid. Defaults to False, which will return
442
469
  lower-resolution statistics that are typically sufficient for
443
470
  most purposes.
@@ -445,7 +472,7 @@ def pixel_stats(
445
472
  An optional string giving the frequency at which to model tides
446
473
  when computing the full modelled tidal range. Defaults to '3h',
447
474
  which computes a tide height for every three hours across the
448
- temporal extent of `ds`.
475
+ temporal extent of `data`.
449
476
  min_max_q : tuple, optional
450
477
  Quantiles used to calculate max and min observed and modelled
451
478
  astronomical tides. By default `(0.0, 1.0)` which is equivalent
@@ -478,9 +505,15 @@ def pixel_stats(
478
505
  - `offset_high`: proportion of the highest tides never observed by the satellite
479
506
 
480
507
  """
508
+ # Standardise data inputs, time and models
509
+ gbox, time_coords = _standardise_inputs(data, time)
510
+ model = [model] if isinstance(model, str) else model
511
+
481
512
  # Model observed tides
513
+ assert time_coords is not None
482
514
  obs_tides = pixel_tides(
483
- ds,
515
+ gbox,
516
+ time=time_coords,
484
517
  resample=False,
485
518
  model=model,
486
519
  directory=directory,
@@ -492,15 +525,15 @@ def pixel_stats(
492
525
 
493
526
  # Generate times covering entire period of satellite record
494
527
  all_timerange = pd.date_range(
495
- start=ds.time.min().item(),
496
- end=ds.time.max().item(),
528
+ start=time_coords.min().item(),
529
+ end=time_coords.max().item(),
497
530
  freq=modelled_freq,
498
531
  )
499
532
 
500
533
  # Model all tides
501
534
  all_tides = pixel_tides(
502
- ds,
503
- times=all_timerange,
535
+ gbox,
536
+ time=all_timerange,
504
537
  model=model,
505
538
  directory=directory,
506
539
  calculate_quantiles=min_max_q,
@@ -510,6 +543,11 @@ def pixel_stats(
510
543
  **pixel_tides_kwargs,
511
544
  )
512
545
 
546
+ # # Calculate means
547
+ # TODO: Find way to make this work with `calculate_quantiles`
548
+ # mot = obs_tides.mean(dim="time")
549
+ # mat = all_tides.mean(dim="time")
550
+
513
551
  # Calculate min and max tides
514
552
  lot = obs_tides.isel(quantile=0)
515
553
  hot = obs_tides.isel(quantile=-1)
@@ -531,10 +569,12 @@ def pixel_stats(
531
569
  stats_ds = (
532
570
  xr.merge(
533
571
  [
534
- hat.rename("hat"),
572
+ # mot.rename("mot"),
573
+ # mat.rename("mat"),
535
574
  hot.rename("hot"),
536
- lat.rename("lat"),
575
+ hat.rename("hat"),
537
576
  lot.rename("lot"),
577
+ lat.rename("lat"),
538
578
  otr.rename("otr"),
539
579
  tr.rename("tr"),
540
580
  spread.rename("spread"),
@@ -544,11 +584,11 @@ def pixel_stats(
544
584
  compat="override",
545
585
  )
546
586
  .drop_vars("quantile")
547
- .odc.assign_crs(crs=ds.odc.crs)
587
+ .odc.assign_crs(crs=gbox.crs)
548
588
  )
549
589
 
550
- # Optionally resample into the original pixel grid of `ds`
590
+ # Optionally resample into the original pixel grid of `data`
551
591
  if resample:
552
- stats_ds = stats_ds.odc.reproject(how=ds.odc.geobox, resample_method="bilinear")
592
+ stats_ds = stats_ds.odc.reproject(how=gbox, resample_method="bilinear")
553
593
 
554
594
  return stats_ds
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eo-tides
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Tide modelling tools for large-scale satellite earth observation analysis
5
5
  Author-email: Robbi Bishop-Taylor <Robbi.BishopTaylor@ga.gov.au>
6
6
  Project-URL: Homepage, https://GeoscienceAustralia.github.io/eo-tides/
@@ -29,7 +29,7 @@ Requires-Dist: numpy >=1.26.0
29
29
  Requires-Dist: odc-geo >=0.4.7
30
30
  Requires-Dist: pandas >=2.2.0
31
31
  Requires-Dist: pyproj >=3.6.1
32
- Requires-Dist: pyTMD ==2.1.6
32
+ Requires-Dist: pyTMD ==2.1.7
33
33
  Requires-Dist: scikit-learn >=1.4.0
34
34
  Requires-Dist: scipy >=1.11.2
35
35
  Requires-Dist: shapely >=2.0.6
@@ -68,9 +68,9 @@ These tools can be applied to petabytes of freely available satellite data (e.g.
68
68
 
69
69
  ## Highlights
70
70
 
71
- - 🌊 Model tides from multiple global ocean tide models in parallel, and return tide heights in standardised `pandas.DataFrame` format for further analysis
71
+ - 🌊 Model tide heights and phases (e.g. high, low, ebb, flow) from multiple global ocean tide models in parallel, and return a `pandas.DataFrame` for further analysis
72
72
  - 🛰️ "Tag" satellite data with tide height and stage based on the exact moment of image acquisition
73
- - 🌐 Model tides for every individual satellite pixel, producing three-dimensional "tide height" `xarray`-format datacubes that can be integrated with satellite data
73
+ - 🌐 Model tides for every individual satellite pixel through time, producing three-dimensional "tide height" `xarray`-format datacubes that can be integrated with satellite data
74
74
  - 📈 Calculate statistics describing local tide dynamics, as well as biases caused by interactions between tidal processes and satellite orbits
75
75
  - 🛠️ Validate modelled tides using measured sea levels from coastal tide gauges (e.g. [GESLA Global Extreme Sea Level Analysis](https://gesla.org/))
76
76
  <!-- - 🎯 Combine multiple tide models into a single locally-optimised "ensemble" model informed by satellite altimetry and satellite-observed patterns of tidal inundation -->
@@ -103,6 +103,12 @@ To cite `eo-tides` in your work, please use the following citation:
103
103
  Bishop-Taylor, R., Sagar, S., Phillips, C., & Newey, V. (2024). eo-tides: Tide modelling tools for large-scale satellite earth observation analysis. https://github.com/GeoscienceAustralia/eo-tides
104
104
  ```
105
105
 
106
+ In addition, please consider also citing the underlying [`pyTMD` Python package](https://pytmd.readthedocs.io/en/latest/) which powers the tide modelling functionality behind `eo-tides`:
107
+
108
+ ```
109
+ Sutterley, T. C., Alley, K., Brunt, K., Howard, S., Padman, L., Siegfried, M. (2017) pyTMD: Python-based tidal prediction software. 10.5281/zenodo.5555395
110
+ ```
111
+
106
112
  ## Acknowledgements
107
113
 
108
114
  For a full list of acknowledgements, refer to [Citations and Credits](https://geoscienceaustralia.github.io/eo-tides/credits/).
@@ -0,0 +1,11 @@
1
+ eo_tides/__init__.py,sha256=MKL_HjRECVHHQVnMVg-TSz3J-vjxPZgbnyWu0RAXZ0U,1623
2
+ eo_tides/eo.py,sha256=98llXpF2lSDfsVQBao-dpr8Z4zH5q0C2Rfu4X-qmPiE,22400
3
+ eo_tides/model.py,sha256=kaYXU_jmv91ONam_CpoVN137aJsmqHvKHEPWe-DRJnI,38280
4
+ eo_tides/stats.py,sha256=sOwXEh8RPb8muh2o9-z1c0GDnV5FJa_TgsiGb4rMkiU,22689
5
+ eo_tides/utils.py,sha256=l9VXJawQzaRBYaFMsP8VBeaN5VA3rFDdzcvF7Rk04Vc,5620
6
+ eo_tides/validation.py,sha256=JjTUqDfbR189m_6W1bpaSolQIHNTLicTHN7z9O_nr3s,11828
7
+ eo_tides-0.2.0.dist-info/LICENSE,sha256=owxWsXViCL2J6Ks3XYhot7t4Y93nstmXAT95Zf030Cc,11350
8
+ eo_tides-0.2.0.dist-info/METADATA,sha256=msiUYdlCm5pTix7LXA7RzM8Hg-9r4JHpWTSUyxdPpg4,7637
9
+ eo_tides-0.2.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10
+ eo_tides-0.2.0.dist-info/top_level.txt,sha256=lXZDUUM1DlLdKWHRn8zdmtW8Rx-eQOIWVvt0b8VGiyQ,9
11
+ eo_tides-0.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,11 +0,0 @@
1
- eo_tides/__init__.py,sha256=TWmQNplePCcNAlua5WI_H7SShkWNk-Gd3X70EDEknSo,1557
2
- eo_tides/eo.py,sha256=OTFjchQWpSfgi2Q62mFBj6ckmy_1B_ExCAmex4UT4js,21616
3
- eo_tides/model.py,sha256=Bwc2VVhDDBJB0wuKUAdSKYfBPZG4XDfldb_BO5Wcy6Y,34517
4
- eo_tides/stats.py,sha256=9nfa7_obkS4tiHrQ1WTutuy2jlHtFg-cmOqP3l_Q7b8,20644
5
- eo_tides/utils.py,sha256=l9VXJawQzaRBYaFMsP8VBeaN5VA3rFDdzcvF7Rk04Vc,5620
6
- eo_tides/validation.py,sha256=JjTUqDfbR189m_6W1bpaSolQIHNTLicTHN7z9O_nr3s,11828
7
- eo_tides-0.1.0.dist-info/LICENSE,sha256=owxWsXViCL2J6Ks3XYhot7t4Y93nstmXAT95Zf030Cc,11350
8
- eo_tides-0.1.0.dist-info/METADATA,sha256=S8nHZcj3TWi2w_RpYilZFeBM_Hjw38hXE16eFJhNPQc,7260
9
- eo_tides-0.1.0.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
10
- eo_tides-0.1.0.dist-info/top_level.txt,sha256=lXZDUUM1DlLdKWHRn8zdmtW8Rx-eQOIWVvt0b8VGiyQ,9
11
- eo_tides-0.1.0.dist-info/RECORD,,