Skip to content

Commit fb6d164

Browse files
committed
modifications network file
1 parent 3a54bbb commit fb6d164

File tree

2 files changed

+83
-10
lines changed

2 files changed

+83
-10
lines changed

src/py_eddy_tracker/appli/gui.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from matplotlib.animation import FuncAnimation
1212
from matplotlib.axes import Axes
1313
from matplotlib.collections import LineCollection
14-
from numpy import arange, where
14+
from numpy import arange, where, nan
1515

1616
from .. import EddyParser
1717
from ..gui import GUI
@@ -58,7 +58,10 @@ def setup(
5858
self.kw_label["fontweight"] = kwargs.pop("fontweight", "demibold")
5959
# To text each visible eddy
6060
if field_txt:
61-
self.field_txt = self.eddy[field_txt]
61+
if isinstance(field_txt,str):
62+
self.field_txt = self.eddy[field_txt]
63+
else :
64+
self.field_txt=field_txt
6265
if field_color:
6366
# To color each visible eddy
6467
self.field_color = self.eddy[field_color].astype("f4")

src/py_eddy_tracker/observations/network.py

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@
55
from glob import glob
66
import logging
77
import time
8-
8+
from datetime import timedelta, datetime
9+
import os
910
import netCDF4
1011
from numba import njit, types as nb_types
1112
from numba.typed import List
13+
import numpy as np
1214
from numpy import (
1315
arange,
1416
array,
1517
bincount,
1618
bool_,
1719
concatenate,
20+
1821
empty,
1922
nan,
2023
ones,
@@ -119,13 +122,15 @@ def __repr__(self):
119122
period = (self.period[1] - self.period[0]) / 365.25
120123
nb_by_network = self.network_size()
121124
nb_trash = 0 if self.ref_index != 0 else nb_by_network[0]
125+
lifetime=self.lifetime
122126
big = 50_000
123127
infos = [
124128
f"Atlas with {self.nb_network} networks ({self.nb_network / period:0.0f} networks/year),"
125129
f" {self.nb_segment} segments ({self.nb_segment / period:0.0f} segments/year), {len(self)} observations ({len(self) / period:0.0f} observations/year)",
126130
f" {m_event.size} merging ({m_event.size / period:0.0f} merging/year), {s_event.size} splitting ({s_event.size / period:0.0f} splitting/year)",
127131
f" with {(nb_by_network > big).sum()} network with more than {big} obs and the biggest have {nb_by_network.max()} observations ({nb_by_network[nb_by_network> big].sum()} observations cumulate)",
128132
f" {nb_trash} observations in trash",
133+
f" {lifetime.max()} days max of lifetime",
129134
]
130135
return "\n".join(infos)
131136

@@ -200,6 +205,13 @@ def ref_segment_track_index(self):
200205
@property
201206
def ref_index(self):
202207
return self.index_network[2]
208+
209+
@property
210+
def lifetime(self):
211+
"""Return lifetime for each observation"""
212+
lt=self.networks_period.astype("int")
213+
nb_by_network=self.network_size()
214+
return lt.repeat(nb_by_network)
203215

204216
def network_segment_size(self, id_networks=None):
205217
"""Get number of segment by network
@@ -225,6 +237,15 @@ def network_size(self, id_networks=None):
225237
i = id_networks - self.index_network[2]
226238
return self.index_network[1][i] - self.index_network[0][i]
227239

240+
@property
241+
def networks_period(self):
242+
"""
243+
Return period for each network
244+
"""
245+
return get_period_with_index(self.time, *self.index_network[:2])
246+
247+
248+
228249
def unique_segment_to_id(self, id_unique):
229250
"""Return id network and id segment for a unique id
230251
@@ -274,7 +295,7 @@ def astype(self, cls):
274295
new[k][:] = self[k][:]
275296
new.sign_type = self.sign_type
276297
return new
277-
298+
278299
def longer_than(self, nb_day_min=-1, nb_day_max=-1):
279300
"""
280301
Select network on time duration
@@ -1125,23 +1146,29 @@ def segment_track_array(self):
11251146
self._segment_track_array = build_unique_array(self.segment, self.track)
11261147
return self._segment_track_array
11271148

1128-
def birth_event(self):
1149+
def birth_event(self, only_index=False):
11291150
"""Extract birth events."""
11301151
i_start, _, _ = self.index_segment_track
11311152
indices = i_start[self.previous_obs[i_start] == -1]
11321153
if self.first_is_trash():
11331154
indices = indices[1:]
1134-
return self.extract_event(indices)
1135-
1155+
if only_index:
1156+
return indices
1157+
else :
1158+
return self.extract_event(indices)
1159+
11361160
generation_event = birth_event
11371161

1138-
def death_event(self):
1162+
def death_event(self, only_index=False):
11391163
"""Extract death events."""
11401164
_, i_stop, _ = self.index_segment_track
11411165
indices = i_stop[self.next_obs[i_stop - 1] == -1] - 1
11421166
if self.first_is_trash():
11431167
indices = indices[1:]
1144-
return self.extract_event(indices)
1168+
if only_index:
1169+
return indices
1170+
else :
1171+
return self.extract_event(indices)
11451172

11461173
dissipation_event = death_event
11471174

@@ -1452,7 +1479,7 @@ def plot(self, ax, ref=None, color_cycle=None, **kwargs):
14521479
j += 1
14531480
return mappables
14541481

1455-
def remove_dead_end(self, nobs=3, ndays=0, recursive=0, mask=None):
1482+
def remove_dead_end(self, nobs=3, ndays=0, recursive=0, mask=None, return_mask=False):
14561483
"""
14571484
Remove short segments that don't connect several segments
14581485
@@ -1478,6 +1505,8 @@ def remove_dead_end(self, nobs=3, ndays=0, recursive=0, mask=None):
14781505
)
14791506
# get mask for selected obs
14801507
m = ~self.segment_mask(segments_keep)
1508+
if return_mask:
1509+
return ~m
14811510
self.track[m] = 0
14821511
self.segment[m] = 0
14831512
self.previous_obs[m] = -1
@@ -1495,6 +1524,8 @@ def remove_dead_end(self, nobs=3, ndays=0, recursive=0, mask=None):
14951524
self.sort()
14961525
if recursive > 0:
14971526
self.remove_dead_end(nobs, ndays, recursive - 1)
1527+
1528+
14981529

14991530
def extract_segment(self, segments, absolute=False):
15001531
"""Extract given segments
@@ -2035,6 +2066,29 @@ def group_observations(self, min_overlap=0.2, minimal_area=False, **kwargs):
20352066
results, nb_obs = list(), list()
20362067
# To display print only in INFO
20372068
display_iteration = logger.getEffectiveLevel() == logging.INFO
2069+
2070+
2071+
# Trier les fichiers par date
2072+
def extract_date(file):
2073+
filename = os.path.basename(file)
2074+
date_str = filename.split('_')[-1].split('.')[0] # Extraire la partie date (ex : "20180101")
2075+
return datetime.strptime(date_str, "%Y%m%d") # Convertir en objet datetime
2076+
self.filenames = sorted(self.filenames, key=extract_date)
2077+
2078+
# Detect missing date and print them to inform the user which files are missing
2079+
missing_dates = []
2080+
dates_list = [extract_date(self.filenames[i]) for i in range(len(self.filenames))]
2081+
for i in range(len(dates_list) - 1):
2082+
expected_date = dates_list[i] + timedelta(days=1)
2083+
while expected_date < dates_list[i + 1]:
2084+
missing_dates.append(expected_date)
2085+
expected_date += timedelta(days=1)
2086+
if missing_dates:
2087+
missing_str = ', '.join(date.strftime("%Y-%m-%d") for date in missing_dates)
2088+
raise Exception(f"Following files missing : {missing_str}")
2089+
else:
2090+
print("No missing files")
2091+
20382092
for i, filename in enumerate(self.filenames):
20392093
if display_iteration:
20402094
print(f"{filename} compared to {self.window} next", end="\r")
@@ -2316,3 +2370,19 @@ def mask_follow_obs(m, next_obs, time, indexs, dt=3):
23162370
m[i_next] = True
23172371
i_next = next_obs[i_next]
23182372
dt_ = abs(time[i_next] - t0)
2373+
2374+
@njit(cache=True)
2375+
def get_period_with_index(t, i0, i1):
2376+
"""Return peek to peek cover by each slice define by i0 and i1
2377+
:param array t: array which contain values to estimate spread
2378+
:param array i0: index which determine start of slice
2379+
:param array i1: index which determine end of slice
2380+
:return array: Peek to peek of t
2381+
"""
2382+
periods = np.empty(i0.size, t.dtype)
2383+
for i in range(i0.size):
2384+
if i1[i] == i0[i]:
2385+
periods[i] = 0
2386+
continue
2387+
periods[i] = t[i0[i] : i1[i]].ptp()
2388+
return periods

0 commit comments

Comments
 (0)