Skip to content

Commit ac9c142

Browse files
committed
Start basic tools for network manipulation
1 parent d5b460d commit ac9c142

File tree

6 files changed

+182
-10
lines changed

6 files changed

+182
-10
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""
2+
Network basic manipulation
3+
==========================
4+
"""
5+
6+
from matplotlib import pyplot as plt
7+
8+
import py_eddy_tracker.gui
9+
from py_eddy_tracker import data
10+
from py_eddy_tracker.observations.network import NetworkObservations
11+
from py_eddy_tracker.observations.tracking import TrackEddiesObservations
12+
13+
# %%
14+
# Load data
15+
# ---------
16+
# Load data where observations are put in same network but no segmentation
17+
e = TrackEddiesObservations.load_file(data.get_path("c568803.nc"))
18+
n = NetworkObservations.from_split_network(e, e.split_network(intern=False, window=5))
19+
20+
# %%
21+
# Timeline
22+
# --------
23+
24+
# %%
25+
# Display timeline
26+
fig = plt.figure(figsize=(15, 8))
27+
ax = fig.add_axes([0.04, 0.04, 0.92, 0.92])
28+
n.display_timeline(ax)
29+
30+
# %%
31+
# Display timeline with event
32+
fig = plt.figure(figsize=(15, 8))
33+
ax = fig.add_axes([0.04, 0.04, 0.92, 0.92])
34+
n.display_timeline(ax, event=True)
35+
plt.show()
36+
37+
# %%
38+
# Keep close relative
39+
# -------------------
40+
# First choose an observation in the network

src/py_eddy_tracker/__init__.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,15 +374,35 @@ def parse_args(self, *args, **kwargs):
374374
long_name="Trajectory number", comment="Trajectory identification number"
375375
),
376376
),
377-
sub_track=dict(
377+
segment=dict(
378378
attr_name=None,
379-
nc_name="sub_track",
379+
nc_name="segment",
380380
nc_type="uint32",
381381
nc_dims=("obs",),
382382
nc_attr=dict(
383383
long_name="Segment Number", comment="Segment number inside a group"
384384
),
385385
),
386+
previous_obs=dict(
387+
attr_name=None,
388+
nc_name="previous_obs",
389+
nc_type="int32",
390+
nc_dims=("obs",),
391+
nc_attr=dict(
392+
long_name="Previous obs index",
393+
comment="Index of previous obs, if there are a spliting",
394+
),
395+
),
396+
next_obs=dict(
397+
attr_name=None,
398+
nc_name="next_obs",
399+
nc_type="int32",
400+
nc_dims=("obs",),
401+
nc_attr=dict(
402+
long_name="Next obs index",
403+
comment="Index of next obs, if there are a merging",
404+
),
405+
),
386406
n=dict(
387407
attr_name=None,
388408
nc_name="observation_number",

src/py_eddy_tracker/appli/network.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,6 @@ def divide_network():
5151
include_vars=("time", "track", "latitude", "longitude", *contour_name),
5252
)
5353
ids = e.split_network(intern=args.intern, window=args.window, minimal_area=False)
54-
e = e.add_fields(("sub_track",))
55-
e.sub_track[:] = ids["track"]
54+
e = e.add_fields(("segment",))
55+
e.segment[:] = ids["track"]
5656
e.write_file(filename=args.out)

src/py_eddy_tracker/observations/network.py

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from glob import glob
77

88
from numba import njit
9-
from numpy import arange, array, bincount, empty, uint32, unique
9+
from numpy import arange, array, bincount, empty, ones, uint32, unique
1010

1111
from ..poly import bbox_intersection, vertice_overlap
1212
from .observation import EddiesObservations
@@ -58,6 +58,97 @@ def load_contour(self, filename):
5858
return self.DATA[filename]
5959

6060

61+
class NetworkObservations(EddiesObservations):
62+
63+
__slots__ = tuple()
64+
65+
NOGROUP = 0
66+
67+
@property
68+
def elements(self):
69+
elements = super().elements
70+
elements.extend(["track", "segment", "next_obs", "previous_obs"])
71+
return list(set(elements))
72+
73+
@classmethod
74+
def from_split_network(cls, group_dataset, indexs, **kwargs):
75+
"""
76+
Build a NetworkObservations object with Group dataset and indexs
77+
78+
:param TrackEddiesObservations group_dataset: Group dataset
79+
:param indexs: result from split_network
80+
return NetworkObservations
81+
"""
82+
index_order = indexs.argsort(order=("group", "track", "time"))
83+
network = cls.new_like(group_dataset, len(group_dataset), **kwargs)
84+
network.sign_type = group_dataset.sign_type
85+
for field in group_dataset.elements:
86+
if field not in network.elements:
87+
continue
88+
network[field][:] = group_dataset[field][index_order]
89+
network.segment[:] = indexs["track"][index_order]
90+
# n & p must be re-index
91+
n, p = indexs["next_obs"][index_order], indexs["previous_obs"][index_order]
92+
translate = empty(index_order.max() + 1, dtype="i4")
93+
translate[index_order] = arange(index_order.shape[0])
94+
m = n != -1
95+
n[m] = translate[n[m]]
96+
m = p != -1
97+
p[m] = translate[p[m]]
98+
network.next_obs[:] = n
99+
network.previous_obs[:] = p
100+
return network
101+
102+
def relative(self, i_obs, order=2, direct=True, only_past=False, only_future=False):
103+
pass
104+
105+
def only_one_network(self):
106+
"""
107+
Raise a warning or error?
108+
if there are more than one network
109+
"""
110+
# TODO
111+
pass
112+
113+
def display_timeline(self, ax, event=False):
114+
"""
115+
Must be call on only one network
116+
"""
117+
self.only_one_network()
118+
j = 0
119+
line_kw = dict(
120+
ls="-",
121+
marker=".",
122+
markersize=6,
123+
zorder=1,
124+
lw=3,
125+
)
126+
for i, b0, b1 in self.iter_on("segment"):
127+
x = self.time[i]
128+
if x.shape[0] == 0:
129+
continue
130+
y = b0 * ones(x.shape)
131+
line = ax.plot(x, y, **line_kw, color=self.COLORS[j % self.NB_COLORS])[0]
132+
if event:
133+
event_kw = dict(color=line.get_color(), ls="-", zorder=1)
134+
i_n, i_p = (
135+
self.next_obs[i.stop - 1],
136+
self.previous_obs[i.start],
137+
)
138+
if i_n != -1:
139+
ax.plot(
140+
(x[-1], self.time[i_n]), (b0, self.segment[i_n]), **event_kw
141+
)
142+
ax.plot(x[-1], b0, color="k", marker=">", markersize=10, zorder=-1)
143+
if i_p != -1:
144+
ax.plot((x[0], self.time[i_p]), (b0, self.segment[i_p]), **event_kw)
145+
ax.plot(x[0], b0, color="k", marker="*", markersize=12, zorder=-1)
146+
j += 1
147+
148+
def insert_virtual(self):
149+
pass
150+
151+
61152
class Network:
62153
__slots__ = (
63154
"window",

src/py_eddy_tracker/observations/observation.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,27 @@ class EddiesObservations(object):
144144
"height_inner_contour",
145145
]
146146

147+
COLORS = [
148+
"sienna",
149+
"red",
150+
"darkorange",
151+
"gold",
152+
"palegreen",
153+
"limegreen",
154+
"forestgreen",
155+
"mediumblue",
156+
"dodgerblue",
157+
"lightskyblue",
158+
"violet",
159+
"blueviolet",
160+
"darkmagenta",
161+
"darkgrey",
162+
"dimgrey",
163+
"steelblue",
164+
]
165+
166+
NB_COLORS = len(COLORS)
167+
147168
def __init__(
148169
self,
149170
size=0,
@@ -553,9 +574,9 @@ def __copy__(self):
553574
def copy(self):
554575
return self.__copy__()
555576

556-
@staticmethod
557-
def new_like(eddies, new_size: int):
558-
return eddies.__class__(
577+
@classmethod
578+
def new_like(cls, eddies, new_size: int):
579+
return cls(
559580
new_size,
560581
track_extra_variables=eddies.track_extra_variables,
561582
track_array_variables=eddies.track_array_variables,

src/py_eddy_tracker/observations/tracking.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,9 +620,9 @@ def split_network(self, intern=True, **kwargs):
620620
sl = slice(i_s, i_e)
621621
local_ids = ids[sl]
622622
self.set_tracks(self[xname][sl], self[yname][sl], local_ids, **kwargs)
623-
m = local_ids["previous_obs"] == -1
623+
m = local_ids["previous_obs"] != -1
624624
local_ids["previous_obs"][m] += i_s
625-
m = local_ids["next_obs"] == -1
625+
m = local_ids["next_obs"] != -1
626626
local_ids["next_obs"][m] += i_s
627627
return ids
628628

0 commit comments

Comments
 (0)