Skip to content

Commit d436ede

Browse files
committed
Add an example about loopers colocate with eddies
1 parent e56905c commit d436ede

File tree

5 files changed

+142
-25
lines changed

5 files changed

+142
-25
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"""
2+
[draft] Loopers vs eddies from altimetry
3+
========================================
4+
5+
All loopers datas used in this example are a subset from the dataset describe in this article
6+
[Lumpkin, R. : Global characteristics of coherent vortices from surface drifter trajectories](https://doi.org/10.1002/2015JC011435)
7+
8+
9+
"""
10+
11+
import re
12+
13+
import numpy as np
14+
import py_eddy_tracker_sample
15+
from IPython.display import HTML
16+
from matplotlib import pyplot as plt
17+
from matplotlib.animation import FuncAnimation
18+
19+
from py_eddy_tracker import data
20+
from py_eddy_tracker.appli.gui import Anim
21+
from py_eddy_tracker.observations.tracking import TrackEddiesObservations
22+
23+
24+
# %%
25+
class VideoAnimation(FuncAnimation):
26+
def _repr_html_(self, *args, **kwargs):
27+
"""To get video in html and have a player"""
28+
content = self.to_html5_video()
29+
return re.sub(
30+
r'width="[0-9]*"\sheight="[0-9]*"', 'width="100%" height="100%"', content
31+
)
32+
33+
def save(self, *args, **kwargs):
34+
if args[0].endswith("gif"):
35+
# In this case gif is use to create thumbnail which are not use but consume same time than video
36+
# So we create an empty file, to save time
37+
with open(args[0], "w") as _:
38+
pass
39+
return
40+
return super().save(*args, **kwargs)
41+
42+
43+
def start_axes(title):
44+
fig = plt.figure(figsize=(13, 5))
45+
ax = fig.add_axes([0.03, 0.03, 0.90, 0.94], aspect="equal")
46+
ax.set_xlim(-6, 36.5), ax.set_ylim(30, 46)
47+
ax.set_title(title, weight="bold")
48+
return ax
49+
50+
51+
def update_axes(ax, mappable=None):
52+
ax.grid()
53+
if mappable:
54+
plt.colorbar(mappable, cax=ax.figure.add_axes([0.94, 0.05, 0.01, 0.9]))
55+
56+
57+
# %%
58+
# Load eddies dataset
59+
cyclonic_eddies = TrackEddiesObservations.load_file(
60+
py_eddy_tracker_sample.get_demo_path("eddies_med_adt_allsat_dt2018/Cyclonic.zarr")
61+
)
62+
anticyclonic_eddies = TrackEddiesObservations.load_file(
63+
py_eddy_tracker_sample.get_demo_path(
64+
"eddies_med_adt_allsat_dt2018/Anticyclonic.zarr"
65+
)
66+
)
67+
68+
# %%
69+
# Load loopers dataset
70+
loopers_med = TrackEddiesObservations.load_file(
71+
data.get_demo_path("loopers_lumpkin_med.nc")
72+
)
73+
74+
# %%
75+
#
76+
ax = start_axes("All drifter available in med from Lumpkin dataset")
77+
loopers_med.plot(ax, lw=0.5, color="r", ref=-10)
78+
update_axes(ax)
79+
80+
# %%
81+
# Only long period drifter
82+
long_drifter = loopers_med.extract_with_length((400, -1))
83+
ax = start_axes("Long period drifter")
84+
long_drifter.plot(ax, lw=0.5, color="r", ref=-10)
85+
update_axes(ax)
86+
print(np.unique(long_drifter.tracks))
87+
88+
# %%
89+
drifter_1 = long_drifter.extract_ids((3588,))
90+
fig = plt.figure(figsize=(8, 4))
91+
ax = fig.add_subplot(111, aspect="equal")
92+
ax.grid()
93+
drifter_1.plot(ax, lw=0.5)
94+
# %%
95+
drifter_1.close_tracks(
96+
anticyclonic_eddies, method="close_center", delta=0.5, nb_obs_min=25
97+
).tracks
98+
99+
# %%
100+
# Animation which show drifter with colocated eddies
101+
ed = anticyclonic_eddies.extract_ids((4738, 4836, 4910,))
102+
x, y, t = drifter_1.lon, drifter_1.lat, drifter_1.time
103+
104+
105+
def update(frame):
106+
# We display last 5 days of loopers trajectory
107+
m = (t < frame) * (t > (frame - 5))
108+
a.func_animation(frame)
109+
line.set_data(x[m], y[m])
110+
111+
112+
a = Anim(ed, intern=True, figsize=(8, 8), cmap="magma_r", nb_step=10, dpi=60)
113+
line = a.ax.plot([], [], "r", lw=4, zorder=100)[0]
114+
kwargs = dict(frames=np.arange(*a.period, 1), interval=100)
115+
a.fig.suptitle("")
116+
_ = VideoAnimation(a.fig, update, **kwargs)
117+
118+
# %%
119+
fig = plt.figure(figsize=(12, 6))
120+
ax = fig.add_subplot(111)
121+
ax.plot(drifter_1.time, drifter_1.radius_s / 1e3, label="loopers")
122+
drifter_1.median_filter(7, "time", "radius_s", inplace=True)
123+
drifter_1.loess_filter(15, "time", "radius_s", inplace=True)
124+
ax.plot(
125+
drifter_1.time,
126+
drifter_1.radius_s / 1e3,
127+
label="loopers (filtered half window 15 days)",
128+
)
129+
ax.plot(ed.time, ed.radius_s / 1e3, label="altimetry")
130+
ed.median_filter(7, "time", "radius_s", inplace=True)
131+
ed.loess_filter(15, "time", "radius_s", inplace=True)
132+
ax.plot(ed.time, ed.radius_s / 1e3, label="altimetry (filtered half window 15 days)")
133+
ax.set_ylabel("radius(km)"), ax.set_ylim(0, 100)
134+
ax.legend()
135+
ax.grid()
136+
_ = ax.set_title("Radius from loopers and altimeter")
238 KB
Binary file not shown.

src/py_eddy_tracker/observations/observation.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,7 +1987,7 @@ def display(self, ax, ref=None, extern_only=False, intern_only=False, **kwargs):
19871987
"""Plot the speed and effective (dashed) contour of the eddies
19881988
19891989
:param matplotlib.axes.Axes ax: matplotlib axe used to draw
1990-
:param float,None ref: western longitude reference used
1990+
:param float,None ref: if defined, all coordinates are wrapped with ref as western boundary
19911991
:param bool extern_only: if True, draw only the effective contour
19921992
:param bool intern_only: if True, draw only the speed contour
19931993
:param dict kwargs: look at :py:meth:`matplotlib.axes.Axes.plot`
@@ -2082,7 +2082,6 @@ def inside(self, x, y, intern=False):
20822082
:rtype: array[bool]
20832083
"""
20842084
xname, yname = self.intern(intern)
2085-
# FIXME: wrapping
20862085
return insidepoly(x, y, self[xname], self[yname])
20872086

20882087
def grid_count(self, bins, intern=False, center=False, filter=slice(None)):

src/py_eddy_tracker/observations/tracking.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ def loess_filter(self, half_window, xfield, yfield, inplace=True):
445445
if inplace:
446446
self.obs[yfield] = result
447447
return self
448+
return result
448449

449450
def median_filter(self, half_window, xfield, yfield, inplace=True):
450451
result = track_median_filter(
@@ -568,7 +569,7 @@ def close_tracks(self, other, nb_obs_min=10, **kwargs):
568569
"""
569570
p0, p1 = self.period
570571
indexs = list()
571-
for i_self, i_other, t0, t1 in self.align_on(other, bins=range(p0, p1 + 2)):
572+
for i_self, i_other, t0, t1 in self.align_on(other, bins=arange(p0, p1 + 2)):
572573
i, j, s = self.match(other, i_self=i_self, i_other=i_other, **kwargs)
573574
indexs.append(other.re_reference_index(j, i_other))
574575
indexs = concatenate(indexs)
@@ -578,10 +579,7 @@ def close_tracks(self, other, nb_obs_min=10, **kwargs):
578579
def format_label(self, label):
579580
t0, t1 = self.period
580581
return label.format(
581-
t0=t0,
582-
t1=t1,
583-
nb_obs=len(self),
584-
nb_tracks=(self.nb_obs_by_track != 0).sum(),
582+
t0=t0, t1=t1, nb_obs=len(self), nb_tracks=(self.nb_obs_by_track != 0).sum(),
585583
)
586584

587585
def plot(self, ax, ref=None, **kwargs):

src/py_eddy_tracker/poly.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ def poly_indexs(x_p, y_p, x_c, y_c):
865865
nb_p = x_p.shape[0]
866866
nb_c = x_c.shape[0]
867867
indexs = -ones(nb_p, dtype=numba_types.int32)
868-
# Adress table to get particle bloc
868+
# Adress table to get test bloc
869869
start_index, end_index, i_first = build_index(i[i_order])
870870
nb_bloc = end_index.size
871871
for i_contour in range(nb_c):
@@ -918,20 +918,4 @@ def insidepoly(x_p, y_p, x_c, y_c):
918918
:param array x_c: longitude of contours
919919
:param array y_c: latitude of contours
920920
"""
921-
# TODO must be optimize like poly_index
922-
nb_p = x_p.shape[0]
923-
nb_c = x_c.shape[0]
924-
flag = zeros(nb_p, dtype=numba_types.bool_)
925-
for i in range(nb_c):
926-
x_, y_ = reduce_size(x_c[i], y_c[i])
927-
x_c_min, y_c_min = x_.min(), y_.min()
928-
x_c_max, y_c_max = x_.max(), y_.max()
929-
v = create_vertice(x_, y_)
930-
for j in range(nb_p):
931-
if flag[j]:
932-
continue
933-
x, y = x_p[j], y_p[j]
934-
if x > x_c_min and x < x_c_max and y > y_c_min and y < y_c_max:
935-
if winding_number_poly(x, y, v) != 0:
936-
flag[j] = True
937-
return flag
921+
return poly_indexs(x_p, y_p, x_c, y_c) != -1

0 commit comments

Comments
 (0)