Skip to content

Commit 141e941

Browse files
committed
add indexer
1 parent 229543f commit 141e941

File tree

5 files changed

+128
-28
lines changed

5 files changed

+128
-28
lines changed

src/py_eddy_tracker/dataset/grid.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@ def clean(self):
326326
self.contours = None
327327
self.vars = dict()
328328

329+
def parse_varname(self, name):
330+
return self.grid(name) if isinstance(name, str) else name
331+
329332
@property
330333
def is_centered(self):
331334
"""Give True if pixel is described with its center's position or
@@ -526,6 +529,8 @@ def grid(self, varname, indexs=None):
526529
527530
.. minigallery:: py_eddy_tracker.GridDataset.grid
528531
"""
532+
# Ensure to have acces to coordinates
533+
self.populate()
529534
if indexs is None:
530535
indexs = dict()
531536
if varname not in self.vars:
@@ -1914,6 +1919,18 @@ def init_speed_coef(self, uname="u", vname="v"):
19141919
u, v = self.grid(uname), self.grid(vname)
19151920
self._speed_ev = sqrt(u * u + v * v)
19161921

1922+
def text(self, ax, name, label="{v:.2f}", **kwargs):
1923+
"""
1924+
:param matplotlib.axes.Axes ax: matplotlib axes used to draw
1925+
:param str,array name: variable to display, could be an array
1926+
:param str label: string to format value
1927+
:param dict kwargs: look at :py:meth:`matplotlib.axes.Axes.pcolormesh`
1928+
"""
1929+
data = self.parse_varname(name)
1930+
for ix, x in enumerate(self.x_c):
1931+
for iy, y in enumerate(self.y_c):
1932+
ax.text(x, y, label.format(v=data[ix,iy]), **kwargs)
1933+
19171934
def display(self, ax, name, factor=1, ref=None, **kwargs):
19181935
"""
19191936
:param matplotlib.axes.Axes ax: matplotlib axes used to draw
@@ -1926,7 +1943,7 @@ def display(self, ax, name, factor=1, ref=None, **kwargs):
19261943
"""
19271944
if "cmap" not in kwargs:
19281945
kwargs["cmap"] = "coolwarm"
1929-
data = self.grid(name) if isinstance(name, str) else name
1946+
data = self.parse_varname(name)
19301947
if ref is None:
19311948
x = self.x_bounds
19321949
else:
@@ -1946,7 +1963,7 @@ def contour(self, ax, name, factor=1, ref=None, **kwargs):
19461963
19471964
.. minigallery:: py_eddy_tracker.RegularGridDataset.contour
19481965
"""
1949-
data = self.grid(name) if isinstance(name, str) else name
1966+
data = self.parse_varname(name)
19501967
if ref is None:
19511968
x = self.x_c
19521969
else:
@@ -2020,8 +2037,8 @@ def uv_for_advection(
20202037
self.add_uv(h_name)
20212038
self.vars.pop(h_name, None)
20222039

2023-
u = (self.grid(u_name) if isinstance(u_name, str) else u_name).copy()
2024-
v = (self.grid(v_name) if isinstance(v_name, str) else v_name).copy()
2040+
u = self.parse_varname(u_name).copy()
2041+
v = self.parse_varname(v_name).copy()
20252042
# N seconds / 1 degrees in m
20262043
coef = time_step * 180 / pi / self.EARTH_RADIUS * factor
20272044
u *= coef / cos(radians(self.y_c))

src/py_eddy_tracker/observations/groups.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,12 @@ def get_matrix(i_start, i_end, translate_start, translate_end, i_target, pct):
268268

269269

270270
class GroupEddiesObservations(EddiesObservations, ABC):
271+
__slots__ = ('indexers',)
272+
273+
def __init__(self, *args, **kwargs):
274+
super().__init__(*args, **kwargs)
275+
self.indexers = dict()
276+
271277
@abstractmethod
272278
def fix_next_previous_obs(self):
273279
pass
@@ -474,3 +480,16 @@ def merge_particle_result(
474480
i_local_targets[m] = i_end[i_local_targets[m]]
475481
i_targets[i_origin] = i_local_targets
476482
percents[i_origin] = local_percents
483+
484+
def daily_time_indexer(self, t, dt=.5):
485+
"""Get all index cover by time window
486+
487+
:param float t: time centered of window
488+
:param float dt: delta +/- around t
489+
"""
490+
if 'time' not in self.indexers:
491+
x0, x1 = self.period
492+
self.indexers['time'] = x0, *window_index(self.time, np.arange(x0, x1), 0.5)
493+
x0, i_ordered, first_index, last_index = self.indexers['time']
494+
j0, j1 = max(0, int(np.ceil(t - x0 - dt))), min(int(np.trunc(t - x0 + dt)), last_index.size - 1)
495+
return i_ordered[first_index[j0]:last_index[j1]]

src/py_eddy_tracker/poly.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -717,12 +717,8 @@ def get_pixel_in_regular(vertices, x_c, y_c, x_start, x_stop, y_start, y_stop):
717717
:param int y_stop: north index of contour
718718
"""
719719
if x_stop < x_start:
720-
x_ref = vertices[0, 0]
721-
x_array = (
722-
(concatenate((x_c[x_start:], x_c[:x_stop])) - x_ref + 180) % 360
723-
+ x_ref
724-
- 180
725-
)
720+
x_ref = vertices[0, 0] - 180
721+
x_array = (concatenate((x_c[x_start:], x_c[:x_stop])) - x_ref) % 360 + x_ref
726722
return winding_number_grid_in_poly(
727723
x_array,
728724
y_c[y_start:y_stop],

tests/test_generic.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,39 @@
1-
from numpy import arange, array, nan, ones, zeros
1+
import numpy as np
22

3-
from py_eddy_tracker.generic import cumsum_by_track, simplify, wrap_longitude
3+
from py_eddy_tracker.generic import cumsum_by_track, simplify, wrap_longitude, bbox_indice_regular
44

55

66
def test_simplify():
7-
x = arange(10, dtype="f4")
8-
y = zeros(10, dtype="f4")
7+
x = np.arange(10, dtype="f4")
8+
y = np.zeros(10, dtype="f4")
99
# Will jump one value on two
1010
x_, y_ = simplify(x, y, precision=1)
1111
assert x_.shape[0] == 5
1212
x_, y_ = simplify(x, y, precision=0.99)
1313
assert x_.shape[0] == 10
1414
# check nan management
15-
x[4] = nan
15+
x[4] = np.nan
1616
x_, y_ = simplify(x, y, precision=1)
1717
assert x_.shape[0] == 6
18-
x[3] = nan
18+
x[3] = np.nan
1919
x_, y_ = simplify(x, y, precision=1)
2020
assert x_.shape[0] == 6
21-
x[:4] = nan
21+
x[:4] = np.nan
2222
x_, y_ = simplify(x, y, precision=1)
2323
assert x_.shape[0] == 3
24-
x[:] = nan
24+
x[:] = np.nan
2525
x_, y_ = simplify(x, y, precision=1)
2626
assert x_.shape[0] == 0
2727

2828

2929
def test_cumsum_by_track():
30-
a = ones(10, dtype="i4") * 2
31-
track = array([1, 1, 2, 2, 2, 2, 44, 44, 44, 48])
30+
a = np.ones(10, dtype="i4") * 2
31+
track = np.array([1, 1, 2, 2, 2, 2, 44, 44, 44, 48])
3232
assert (cumsum_by_track(a, track) == [2, 4, 2, 4, 6, 8, 2, 4, 6, 2]).all()
3333

3434

3535
def test_wrapping():
36-
y = x = arange(-5, 5, dtype="f4")
36+
y = x = np.arange(-5, 5, dtype="f4")
3737
x_, _ = wrap_longitude(x, y, ref=-10)
3838
assert (x_ == x).all()
3939
x_, _ = wrap_longitude(x, y, ref=1)
@@ -49,3 +49,29 @@ def test_wrapping():
4949
# x %= 360
5050
# x_, _ = wrap_longitude(x, y, ref=-10, cut=True)
5151
# assert x.size == x_.size
52+
53+
54+
def test_bbox_fit_contour():
55+
v= np.array([
56+
[200.6, 10.5],
57+
[203.4, 10.4],
58+
[204.4, 9.6],
59+
[198.4, 9.3],
60+
[200.6, 10.5],
61+
])
62+
xc0, yc0 = v.min(axis=0)
63+
xc1, yc1 = v.max(axis=0)
64+
for step in [1, .5, .2, .133333, .125,.1,.07, .025]:
65+
x_c = np.arange(0, 360, step)
66+
y_c = np.arange(-80, 80, step)
67+
xstep, ystep = x_c[1] - x_c[0], y_c[1] - y_c[0]
68+
x0, y0 = x_c - xstep / 2.0, y_c - ystep / 2.0
69+
nb_x = x_c.shape[0]
70+
(x_start, x_stop), (y_start, y_stop) = bbox_indice_regular(v, x0, y0, xstep, ystep, 0, True, nb_x)
71+
i_x = np.where((x_c >= xc0) * (x_c <= xc1))[0]
72+
i_y = np.where((y_c >= yc0) * (y_c <= yc1))[0]
73+
(x_start_raw, x_stop_raw), (y_start_raw, y_stop_raw) = (i_x.min(), i_x.max()), (i_y.min(), i_y.max())
74+
assert x_start == x_start_raw
75+
assert x_stop == x_stop_raw + 1
76+
assert y_start == y_start_raw
77+
assert y_stop == y_stop_raw + 1

tests/test_poly.py

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from numpy import array, pi, roll
1+
import numpy as np
22
from pytest import approx
33

44
from py_eddy_tracker.poly import (
@@ -7,11 +7,13 @@
77
get_convex_hull,
88
poly_area_vertice,
99
visvalingam,
10+
get_pixel_in_regular,
1011
)
12+
from py_eddy_tracker.generic import bbox_indice_regular
1113

1214
# Vertices for next test
13-
V = array(((2, 2, 3, 3, 2), (-10, -9, -9, -10, -10)))
14-
V_concave = array(((2, 2, 2.5, 3, 3, 2), (-10, -9, -9.5, -9, -10, -10)))
15+
V = np.array(((2, 2, 3, 3, 2), (-10, -9, -9, -10, -10)))
16+
V_concave = np.array(((2, 2, 2.5, 3, 3, 2), (-10, -9, -9.5, -9, -10, -10)))
1517

1618

1719
def test_poly_area():
@@ -23,7 +25,7 @@ def test_fit_circle():
2325
assert x0 == approx(2.5, rel=1e-10)
2426
assert y0 == approx(-9.5, rel=1e-10)
2527
assert r == approx(2**0.5 / 2, rel=1e-10)
26-
assert err == approx((1 - 2 / pi) * 100, rel=1e-10)
28+
assert err == approx((1 - 2 / np.pi) * 100, rel=1e-10)
2729

2830

2931
def test_convex():
@@ -38,8 +40,8 @@ def test_convex_hull():
3840

3941

4042
def test_visvalingam():
41-
x = array([1, 2, 3, 4, 5, 6.75, 6, 1])
42-
y = array([-0.5, -1.5, -1, -1.75, -1, -1, -0.5, -0.5])
43+
x = np.array([1, 2, 3, 4, 5, 6.75, 6, 1])
44+
y = np.array([-0.5, -1.5, -1, -1.75, -1, -1, -0.5, -0.5])
4345
x_target = [1, 2, 3, 4, 6, 1]
4446
y_target = [-0.5, -1.5, -1, -1.75, -0.5, -0.5]
4547
x_, y_ = visvalingam(x, y, 6)
@@ -48,6 +50,46 @@ def test_visvalingam():
4850
x_, y_ = visvalingam(x[:-1], y[:-1], 6)
4951
assert (x_target == x_).all()
5052
assert (y_target == y_).all()
51-
x_, y_ = visvalingam(roll(x, 2), roll(y, 2), 6)
53+
x_, y_ = visvalingam(np.roll(x, 2), np.roll(y, 2), 6)
5254
assert (x_target[:-1] == x_[1:]).all()
5355
assert (y_target[:-1] == y_[1:]).all()
56+
57+
58+
def test_pixel_in_contour():
59+
xmin, xmax, ymin, ymax = -1, 31, -2, 11
60+
v = np.array([
61+
[xmin, ymax],
62+
[xmax, ymax],
63+
[xmax, ymin],
64+
[xmin, ymin],
65+
[xmin, ymax],
66+
])
67+
xstep = ystep = 7.5
68+
# Global grid
69+
for x0_ in [-10, 0]:
70+
x0, y0 = (x0_, x0_ + 360), (-10, 20)
71+
x_c, y_c = np.arange(*x0, xstep), np.arange(*y0, ystep)
72+
(x_start, x_stop), (y_start, y_stop) = bbox_indice_regular(v, x0, y0, xstep, ystep, 1, True, int(360/5))
73+
i, j = get_pixel_in_regular(v, x_c, y_c, x_start, x_stop, y_start, y_stop)
74+
assert (x_c[i] < xmax).all(), f"{x0=}"
75+
assert (x_c[i] > xmin).all(), f"{x0=}"
76+
77+
# Regional grid
78+
# contour over two bounds
79+
x0, y0 = (20, 370), (-10, 20)
80+
x_c, y_c = np.arange(*x0, xstep), np.arange(*y0, ystep)
81+
(x_start, x_stop), (y_start, y_stop) = bbox_indice_regular(v, x0, y0, xstep, ystep, 1, False, int(360/5))
82+
i, j = get_pixel_in_regular(v, x_c, y_c, x_start, x_stop, y_start, y_stop)
83+
assert (x_c[i] < xmax).all(), f"{x0=}"
84+
assert (x_c[i] > xmin).all(), f"{x0=}"
85+
86+
# first case grid fully cover contour, and not in second case
87+
for x0_ in [-2, -.5]:
88+
x0, y0 = (x0_, 100), (-10, 20)
89+
x_c, y_c = np.arange(*x0, xstep), np.arange(*y0, ystep)
90+
(x_start, x_stop), (y_start, y_stop) = bbox_indice_regular(v, x0, y0, xstep, ystep, 1, False, int(360/5))
91+
i, j = get_pixel_in_regular(v, x_c, y_c, x_start, x_stop, y_start, y_stop)
92+
assert (x_c[i] < xmax).all(), f"{x0=}"
93+
assert (x_c[i] > xmin).all(), f"{x0=}"
94+
assert (y_c[j] < ymax).all(), f"{y0=}"
95+
assert (y_c[j] > ymin).all(), f"{y0=}"

0 commit comments

Comments
 (0)