eo-tides 0.0.21__py3-none-any.whl → 0.0.22__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/model.py +5 -1
- eo_tides/stats.py +75 -21
- {eo_tides-0.0.21.dist-info → eo_tides-0.0.22.dist-info}/METADATA +16 -15
- eo_tides-0.0.22.dist-info/RECORD +11 -0
- eo_tides-0.0.21.dist-info/RECORD +0 -11
- {eo_tides-0.0.21.dist-info → eo_tides-0.0.22.dist-info}/LICENSE +0 -0
- {eo_tides-0.0.21.dist-info → eo_tides-0.0.22.dist-info}/WHEEL +0 -0
- {eo_tides-0.0.21.dist-info → eo_tides-0.0.22.dist-info}/top_level.txt +0 -0
eo_tides/model.py
CHANGED
@@ -243,7 +243,7 @@ def _model_tides(
|
|
243
243
|
lon,
|
244
244
|
lat,
|
245
245
|
pytmd_model.model_file,
|
246
|
-
grid=pytmd_model.
|
246
|
+
grid=pytmd_model.file_format,
|
247
247
|
crop=crop,
|
248
248
|
bounds=bounds,
|
249
249
|
method=method,
|
@@ -277,6 +277,10 @@ def _model_tides(
|
|
277
277
|
|
278
278
|
# Delta time (TT - UT1)
|
279
279
|
deltat = timescale.tt_ut1
|
280
|
+
else:
|
281
|
+
raise Exception(
|
282
|
+
f"Unsupported model format ({pytmd_model.format}). This may be due to an incompatible version of `pyTMD`."
|
283
|
+
)
|
280
284
|
|
281
285
|
# Calculate complex phase in radians for Euler's
|
282
286
|
cph = -1j * ph * np.pi / 180.0
|
eo_tides/stats.py
CHANGED
@@ -26,8 +26,10 @@ def tide_stats(
|
|
26
26
|
tidepost_lon: float | None = None,
|
27
27
|
plain_english: bool = True,
|
28
28
|
plot: bool = True,
|
29
|
+
plot_col: str | None = None,
|
29
30
|
modelled_freq: str = "2h",
|
30
31
|
linear_reg: bool = False,
|
32
|
+
min_max_q: tuple = (0.0, 1.0),
|
31
33
|
round_stats: int = 3,
|
32
34
|
**model_tides_kwargs,
|
33
35
|
) -> pd.Series:
|
@@ -73,6 +75,10 @@ def tide_stats(
|
|
73
75
|
An optional boolean indicating whether to plot how satellite-
|
74
76
|
observed tide heights compare against the full tidal range.
|
75
77
|
Defaults to True.
|
78
|
+
plot_col : str, optional
|
79
|
+
Optional name of a coordinate, dimension or variable in the array
|
80
|
+
that will be used to plot observations with unique symbols.
|
81
|
+
Defaults to None, which will plot all observations as circles.
|
76
82
|
modelled_freq : str, optional
|
77
83
|
An optional string giving the frequency at which to model tides
|
78
84
|
when computing the full modelled tidal range. Defaults to '2h',
|
@@ -84,6 +90,11 @@ def tide_stats(
|
|
84
90
|
increasing trends over time. This may indicate whether your
|
85
91
|
satellite data may produce misleading trends based on uneven
|
86
92
|
sampling of the local tide regime.
|
93
|
+
min_max_q : tuple, optional
|
94
|
+
Quantiles used to calculate max and min observed and modelled
|
95
|
+
astronomical tides. By default `(0.0, 1.0)` which is equivalent
|
96
|
+
to minimum and maximum; to use a softer threshold that is more
|
97
|
+
robust to outliers, use e.g. `(0.1, 0.9)`.
|
87
98
|
round_stats : int, optional
|
88
99
|
The number of decimal places used to round the output statistics.
|
89
100
|
Defaults to 3.
|
@@ -135,6 +146,7 @@ def tide_stats(
|
|
135
146
|
return_tideposts=True,
|
136
147
|
**model_tides_kwargs,
|
137
148
|
)
|
149
|
+
ds_tides = ds_tides.sortby("time")
|
138
150
|
|
139
151
|
# Drop spatial ref for nicer plotting
|
140
152
|
ds_tides = ds_tides.drop_vars("spatial_ref")
|
@@ -160,8 +172,8 @@ def tide_stats(
|
|
160
172
|
# Get coarse statistics on all and observed tidal ranges
|
161
173
|
obs_mean = ds_tides.tide_height.mean().item()
|
162
174
|
all_mean = all_tides_df.tide_height.mean()
|
163
|
-
obs_min, obs_max = ds_tides.tide_height.quantile(
|
164
|
-
all_min, all_max = all_tides_df.tide_height.quantile(
|
175
|
+
obs_min, obs_max = ds_tides.tide_height.quantile(min_max_q).values
|
176
|
+
all_min, all_max = all_tides_df.tide_height.quantile(min_max_q).values
|
165
177
|
|
166
178
|
# Calculate tidal range
|
167
179
|
obs_range = obs_max - obs_min
|
@@ -169,47 +181,89 @@ def tide_stats(
|
|
169
181
|
|
170
182
|
# Calculate Bishop-Taylor et al. 2018 tidal metrics
|
171
183
|
spread = obs_range / all_range
|
172
|
-
|
173
|
-
|
184
|
+
low_tide_offset_m = abs(all_min - obs_min)
|
185
|
+
high_tide_offset_m = abs(all_max - obs_max)
|
186
|
+
low_tide_offset = low_tide_offset_m / all_range
|
187
|
+
high_tide_offset = high_tide_offset_m / all_range
|
188
|
+
|
189
|
+
# Plain text descriptors
|
190
|
+
mean_diff = "higher" if obs_mean > all_mean else "lower"
|
191
|
+
mean_diff_icon = "⬆️" if obs_mean > all_mean else "⬇️"
|
192
|
+
spread_icon = "🟢" if spread >= 0.9 else "🟡" if 0.7 < spread <= 0.9 else "🔴"
|
193
|
+
low_tide_icon = "🟢" if low_tide_offset <= 0.1 else "🟡" if 0.1 <= low_tide_offset < 0.2 else "🔴"
|
194
|
+
high_tide_icon = "🟢" if high_tide_offset <= 0.1 else "🟡" if 0.1 <= high_tide_offset < 0.2 else "🔴"
|
174
195
|
|
175
196
|
# Extract x (time in decimal years) and y (distance) values
|
176
197
|
all_times = all_tides_df.index.get_level_values("time")
|
177
|
-
all_x = all_times.year + ((all_times.dayofyear - 1) / 365) + ((all_times.hour
|
198
|
+
all_x = all_times.year + ((all_times.dayofyear - 1) / 365) + ((all_times.hour) / 24)
|
178
199
|
time_period = all_x.max() - all_x.min()
|
179
200
|
|
180
201
|
# Extract x (time in decimal years) and y (distance) values
|
181
|
-
obs_x = ds_tides.time.dt.year + ((ds_tides.time.dt.dayofyear - 1) / 365) + ((ds_tides.time.dt.hour
|
202
|
+
obs_x = ds_tides.time.dt.year + ((ds_tides.time.dt.dayofyear - 1) / 365) + ((ds_tides.time.dt.hour) / 24)
|
182
203
|
obs_y = ds_tides.tide_height.values.astype(np.float32)
|
183
204
|
|
184
205
|
# Compute linear regression
|
185
206
|
obs_linreg = stats.linregress(x=obs_x, y=obs_y)
|
186
207
|
|
208
|
+
# return obs_linreg
|
209
|
+
|
187
210
|
if plain_english:
|
211
|
+
print(f"\n\n🌊 Modelled astronomical tide range: {all_range:.2f} metres.")
|
212
|
+
print(f"🛰️ Observed tide range: {obs_range:.2f} metres.\n")
|
213
|
+
print(f" {spread_icon} {spread:.0%} of the modelled astronomical tide range was observed at this location.")
|
214
|
+
print(
|
215
|
+
f" {high_tide_icon} The highest {high_tide_offset:.0%} ({high_tide_offset_m:.2f} metres) of the tide range was never observed."
|
216
|
+
)
|
188
217
|
print(
|
189
|
-
f"
|
190
|
-
|
191
|
-
|
192
|
-
|
218
|
+
f" {low_tide_icon} The lowest {low_tide_offset:.0%} ({low_tide_offset_m:.2f} metres) of the tide range was never observed.\n"
|
219
|
+
)
|
220
|
+
print(f"🌊 Mean modelled astronomical tide height: {all_mean:.2f} metres.")
|
221
|
+
print(f"🛰️ Mean observed tide height: {obs_mean:.2f} metres.\n")
|
222
|
+
print(
|
223
|
+
f" {mean_diff_icon} The mean observed tide height was {obs_mean - all_mean:.2f} metres {mean_diff} than the mean modelled astronomical tide height."
|
193
224
|
)
|
194
225
|
|
195
226
|
if linear_reg:
|
196
|
-
if obs_linreg.pvalue > 0.
|
197
|
-
print(
|
227
|
+
if obs_linreg.pvalue > 0.01:
|
228
|
+
print(" ➖ Observed tides showed no significant trends over time.")
|
198
229
|
else:
|
199
|
-
obs_slope_desc = "
|
230
|
+
obs_slope_desc = "decreasing" if obs_linreg.slope < 0 else "increasing"
|
200
231
|
print(
|
201
|
-
f"Observed tides {obs_slope_desc}
|
202
|
-
f"(p={obs_linreg.pvalue:.3f}) over time by "
|
203
|
-
f"{obs_linreg.slope:.03f} m per year (i.e. a "
|
204
|
-
f"~{time_period * obs_linreg.slope:.2f} m "
|
205
|
-
f"{obs_slope_desc} over the ~{time_period:.0f} year period)."
|
232
|
+
f" ⚠️ Observed tides showed a significant {obs_slope_desc} trend over time (p={obs_linreg.pvalue:.3f}, {obs_linreg.slope:.2f} metres per year)"
|
206
233
|
)
|
207
234
|
|
208
235
|
if plot:
|
209
236
|
# Create plot and add all time and observed tide data
|
210
|
-
fig, ax = plt.subplots(figsize=(10,
|
211
|
-
all_tides_df.reset_index(["x", "y"]).tide_height.plot(ax=ax, alpha=0.4)
|
212
|
-
|
237
|
+
fig, ax = plt.subplots(figsize=(10, 6))
|
238
|
+
all_tides_df.reset_index(["x", "y"]).tide_height.plot(ax=ax, alpha=0.4, label="Modelled tides")
|
239
|
+
|
240
|
+
# Look through custom column values if provided
|
241
|
+
if plot_col is not None:
|
242
|
+
# Create a list of marker styles
|
243
|
+
markers = ["o", "^", "s", "D", "v", "<", ">", "p", "*", "h", "H", "+", "x", "d", "|", "_"]
|
244
|
+
for i, value in enumerate(np.unique(ds_tides[plot_col])):
|
245
|
+
ds_tides.where(ds_tides[plot_col] == value, drop=True).tide_height.plot.line(
|
246
|
+
ax=ax,
|
247
|
+
linewidth=0.0,
|
248
|
+
color="black",
|
249
|
+
marker=markers[i % len(markers)],
|
250
|
+
markersize=4,
|
251
|
+
label=value,
|
252
|
+
)
|
253
|
+
# Otherwise, plot all data at once
|
254
|
+
else:
|
255
|
+
ds_tides.tide_height.plot.line(
|
256
|
+
ax=ax, marker="o", linewidth=0.0, color="black", markersize=3.5, label="Satellite observations"
|
257
|
+
)
|
258
|
+
|
259
|
+
ax.legend(loc="upper center", bbox_to_anchor=(0.5, 1.04), ncol=20, borderaxespad=0, frameon=False)
|
260
|
+
|
261
|
+
ax.plot(
|
262
|
+
ds_tides.time.isel(time=[0, -1]),
|
263
|
+
obs_linreg.intercept + obs_linreg.slope * obs_x[[0, -1]],
|
264
|
+
"r",
|
265
|
+
label="fitted line",
|
266
|
+
)
|
213
267
|
|
214
268
|
# Add horizontal lines for spread/offsets
|
215
269
|
ax.axhline(obs_min, color="black", linestyle=":", linewidth=1)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: eo-tides
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.22
|
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/
|
@@ -22,23 +22,24 @@ Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Requires-Python: <4.0,>=3.9
|
23
23
|
Description-Content-Type: text/markdown
|
24
24
|
License-File: LICENSE
|
25
|
-
Requires-Dist: colorama
|
26
|
-
Requires-Dist: geopandas >=
|
27
|
-
Requires-Dist:
|
28
|
-
Requires-Dist:
|
29
|
-
Requires-Dist:
|
30
|
-
Requires-Dist:
|
25
|
+
Requires-Dist: colorama >=0.4.3
|
26
|
+
Requires-Dist: geopandas >=0.10.0
|
27
|
+
Requires-Dist: matplotlib >=3.8.0
|
28
|
+
Requires-Dist: numpy >=1.26.0
|
29
|
+
Requires-Dist: odc-geo >=0.4.7
|
30
|
+
Requires-Dist: pandas >=2.2.0
|
31
|
+
Requires-Dist: pyproj >=3.6.1
|
31
32
|
Requires-Dist: pyTMD ==2.1.6
|
32
|
-
Requires-Dist: scikit-learn
|
33
|
-
Requires-Dist: scipy
|
34
|
-
Requires-Dist: shapely
|
35
|
-
Requires-Dist: tqdm
|
36
|
-
Requires-Dist: xarray
|
33
|
+
Requires-Dist: scikit-learn >=1.4.0
|
34
|
+
Requires-Dist: scipy >=1.11.2
|
35
|
+
Requires-Dist: shapely >=2.0.6
|
36
|
+
Requires-Dist: tqdm >=4.55.0
|
37
|
+
Requires-Dist: xarray >=2022.3.0
|
37
38
|
Provides-Extra: notebooks
|
38
39
|
Requires-Dist: odc-stac >=0.3.10 ; extra == 'notebooks'
|
39
|
-
Requires-Dist: pystac-client ; extra == 'notebooks'
|
40
|
-
Requires-Dist: folium ; extra == 'notebooks'
|
41
|
-
Requires-Dist:
|
40
|
+
Requires-Dist: pystac-client >=0.8.3 ; extra == 'notebooks'
|
41
|
+
Requires-Dist: folium >=0.16.0 ; extra == 'notebooks'
|
42
|
+
Requires-Dist: planetary-computer >=1.0.0 ; extra == 'notebooks'
|
42
43
|
|
43
44
|
# `eo-tides`: Tide modelling tools for large-scale satellite earth observation analysis
|
44
45
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
eo_tides/__init__.py,sha256=TWmQNplePCcNAlua5WI_H7SShkWNk-Gd3X70EDEknSo,1557
|
2
|
+
eo_tides/eo.py,sha256=K2Ubxvp5yYxVwAOaUZDHCIV_AppRuqMiQRtArhe7YOM,22480
|
3
|
+
eo_tides/model.py,sha256=l7RmzRqr_-yrNMVwW0bisCSnxR9NFHrwWda6WvQHZKU,33129
|
4
|
+
eo_tides/stats.py,sha256=-piIpX3SmZL8DJntSLORRozyAJ1-od49GU-p56Cs_lc,13663
|
5
|
+
eo_tides/utils.py,sha256=l9VXJawQzaRBYaFMsP8VBeaN5VA3rFDdzcvF7Rk04Vc,5620
|
6
|
+
eo_tides/validation.py,sha256=yFuIjAxS9qf097_n4DHWG4AOa6n4nt1HGibUkOkJW6o,11437
|
7
|
+
eo_tides-0.0.22.dist-info/LICENSE,sha256=owxWsXViCL2J6Ks3XYhot7t4Y93nstmXAT95Zf030Cc,11350
|
8
|
+
eo_tides-0.0.22.dist-info/METADATA,sha256=Ae6NT_B98l4eZauFon-YBdb04z02JKRhzI6cxfvMBxc,6452
|
9
|
+
eo_tides-0.0.22.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
10
|
+
eo_tides-0.0.22.dist-info/top_level.txt,sha256=lXZDUUM1DlLdKWHRn8zdmtW8Rx-eQOIWVvt0b8VGiyQ,9
|
11
|
+
eo_tides-0.0.22.dist-info/RECORD,,
|
eo_tides-0.0.21.dist-info/RECORD
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
eo_tides/__init__.py,sha256=TWmQNplePCcNAlua5WI_H7SShkWNk-Gd3X70EDEknSo,1557
|
2
|
-
eo_tides/eo.py,sha256=K2Ubxvp5yYxVwAOaUZDHCIV_AppRuqMiQRtArhe7YOM,22480
|
3
|
-
eo_tides/model.py,sha256=WC-3gBH-ToREl1RS6CxYJLfXlpy03vtwZKd_464QYcU,32958
|
4
|
-
eo_tides/stats.py,sha256=gpkewfgM7ixOr_XXepkMHpezmvjlt5-Qo2xbUmzyKhs,10898
|
5
|
-
eo_tides/utils.py,sha256=l9VXJawQzaRBYaFMsP8VBeaN5VA3rFDdzcvF7Rk04Vc,5620
|
6
|
-
eo_tides/validation.py,sha256=yFuIjAxS9qf097_n4DHWG4AOa6n4nt1HGibUkOkJW6o,11437
|
7
|
-
eo_tides-0.0.21.dist-info/LICENSE,sha256=owxWsXViCL2J6Ks3XYhot7t4Y93nstmXAT95Zf030Cc,11350
|
8
|
-
eo_tides-0.0.21.dist-info/METADATA,sha256=t60AoRbSg9K6GEXlk3TCd9nrEQbaFrHp7rgAmwAda_g,6298
|
9
|
-
eo_tides-0.0.21.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
10
|
-
eo_tides-0.0.21.dist-info/top_level.txt,sha256=lXZDUUM1DlLdKWHRn8zdmtW8Rx-eQOIWVvt0b8VGiyQ,9
|
11
|
-
eo_tides-0.0.21.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|