wolfhece 2.1.65__py3-none-any.whl → 2.1.67__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.
@@ -22,6 +22,7 @@ import numpy as np
22
22
  from enum import Enum
23
23
  from typing import Literal
24
24
  import urllib.parse
25
+ from pathlib import Path
25
26
 
26
27
  import matplotlib.pyplot as plt
27
28
 
@@ -95,6 +96,9 @@ class kiwis_request_info(Enum):
95
96
  Formats = "Formats"
96
97
  Returnfields = "Returnfields"
97
98
  OptionalFields = "Optionalfields"
99
+ Subdescription = "Subdescription"
100
+ Dateformats = "Dateformats"
101
+ Transformations= "Transformations"
98
102
 
99
103
  class kiwis_token(Enum):
100
104
  ACCESS_TOKEN_KEY = 'access_token'
@@ -136,6 +140,7 @@ class kiwis_keywords_horq(Enum):
136
140
  VMAXAN = 'an.maximum'
137
141
  VMAXANHYD = 'anHydro.maximum'
138
142
  VMINANHYD = 'anHydro.minimum'
143
+
139
144
  class kiwis_keywords_rain(Enum):
140
145
  V5_10MIN = 'production'
141
146
  V1H = '1h.total'
@@ -184,6 +189,22 @@ class quality_code(Enum):
184
189
  VOID = (255, 'black', '.')
185
190
  VOID2 = (-1, 'black', '.')
186
191
 
192
+ class station_fields(Enum):
193
+ STATION_ID = 'station_id'
194
+ STATION_NO = 'station_no'
195
+ STATION_NAME = 'station_name'
196
+ STATION_LOCAL_X = 'station_local_x'
197
+ STATION_LOCAL_Y = 'station_local_y'
198
+ STATION_LATITUDE = 'station_latitude'
199
+ STATION_LONGITUDE = 'station_longitude'
200
+ RIVER_NAME = 'river_name'
201
+
202
+ class timeseries_fields(Enum):
203
+ TS_ID = 'ts_id'
204
+ TS_NAME = 'ts_name'
205
+ TS_UNITNAME = 'ts_unitname'
206
+ TS_UNITSYMBOL ='ts_unitsymbol'
207
+
187
208
  class hydrometry():
188
209
 
189
210
  def __init__(self, url:str=URL_SPW, urltoken:str=URL_TOKEN, credential ='', dir='') -> None:
@@ -226,15 +247,24 @@ class hydrometry():
226
247
  self.realstations = None
227
248
  pass
228
249
 
250
+ def __str__(self) -> str:
251
+ ret='Columns in stations :\n'
252
+ for curcol in self.realstations.columns:
253
+ ret+=curcol+'\n'
254
+ return ret
255
+
229
256
  def _get_commandstr(self, which:str):
257
+ """ Construction de la commande à envoyer au serveur KIWIS """
258
+
230
259
  return self.url+'?request='+which.value+'&format=json'
231
260
 
232
261
  def daily_token(self):
233
262
  """
234
263
  Get daily token to be identified on hydrometry website
235
264
 
236
- @todo : manage error as response
265
+ #FIXME: better manage error as response
237
266
  """
267
+
238
268
  if self.credential == '':
239
269
  self._header = None
240
270
  return
@@ -247,64 +277,97 @@ class hydrometry():
247
277
  else:
248
278
  headers = {'Authorization' : 'Basic {}'.format(self.credential)}
249
279
  data = {'grant_type' :'client_credentials'}
250
- self.token = requests.post(self.urltoken, data=data, headers=headers).json()
251
- with open(today, 'w') as f:
252
- json.dump(self.token, f)
280
+
281
+ try:
282
+ self.token = requests.post(self.urltoken, data=data, headers=headers).json()
283
+
284
+ if 'error' in self.token:
285
+ self.token = None
286
+ self._header = {'Authorization': 'Bearer '}
287
+ return
288
+
289
+ with open(today, 'w') as f:
290
+ json.dump(self.token, f)
291
+ except:
292
+ self._header = {'Authorization': 'Bearer '}
293
+ return
294
+ self.token = None
253
295
 
254
296
  self._header = {'Authorization': 'Bearer {}'.format(self.token['access_token'])}
255
297
 
256
298
  def check_plot(self):
299
+ """ Instance is checked in mapviewer """
257
300
  self.plotted = True
258
301
 
259
302
  def uncheck_plot(self):
303
+ """ Instance is unchecked in mapviewer """
260
304
  self.plotted = False
261
305
 
262
- def save_struct(self,dir=''):
306
+ def save_struct(self, dir=''):
307
+ """Sauvegarde des structures dans un répertoire
308
+
309
+ :param dir: répertoire de sauvegarde
310
+ """
263
311
 
264
312
  if dir=='':
265
313
  return
266
314
 
267
- self.sites.to_csv(join(dir,'sites.csv'))
268
- self.stations.to_csv(join(dir,'stations.csv'))
269
- self.groups.to_csv(join(dir,'groups.csv'))
270
- self.requests.to_csv(join(dir,'requests.csv'))
315
+ dir = Path(dir)
316
+ dir.mkdir(parents=True, exist_ok=True)
271
317
 
272
- def _get_stations_pythonlist(self, site_no, onlyreal=True):
318
+ self.sites.to_csv(dir / 'sites.csv')
319
+ self.stations.to_csv(dir / 'stations.csv')
320
+ self.groups.to_csv(dir / 'groups.csv')
321
+ self.requests.to_csv(dir / 'requests.csv')
322
+
323
+ def _get_stations_pythonlist(self, site_no:str|int, onlyreal:bool= True):
324
+ """ Obtention des stations pour le site en liste python
325
+
326
+ :param site_no: numéro du site
327
+ :param onlyreal: ne prendre que les stations réelles, pas les calculées
328
+ """
273
329
 
274
330
  if onlyreal:
275
- stations = self.realstations[self.realstations['site_no']==site_no]
331
+ stations = self.realstations[self.realstations[kiwis_site_fields.site_no.value]==site_no]
276
332
  else:
277
- stations = self.stations[self.stations['site_no']==site_no]
333
+ stations = self.stations[self.stations[kiwis_site_fields.site_no.value]==site_no]
278
334
 
279
- list_name_code = [curname+' --- '+curno for curname,curno in zip(stations['station_name'].values,stations['station_no'].values)]
280
- list_code_name = [curno +' --- '+curname for curname,curno in zip(stations['station_name'].values,stations['station_no'].values)]
335
+ list_name_code = [curname+' --- '+curno for curname,curno in zip(stations[station_fields.STATION_NAME.value].values,stations[station_fields.STATION_NO.value].values)]
336
+ list_code_name = [curno +' --- '+curname for curname,curno in zip(stations[station_fields.STATION_NAME.value].values,stations[station_fields.STATION_NO.value].values)]
281
337
 
282
338
  return list_name_code, list_code_name
283
339
 
284
340
  def _get_sites_pythonlist(self):
341
+ """ Obtention des sites en liste python """
285
342
 
286
- list_name_code = [curname+' --- '+curno for curname,curno in zip(self.sites['site_name'].values,self.sites['site_no'].values)]
343
+ list_name_code = [curname+' --- '+curno for curname,curno in zip(self.sites[kiwis_site_fields.site_name.value].values,self.sites[kiwis_site_fields.site_no.value].values)]
287
344
  return list_name_code
288
345
 
289
346
  def get_stations(self):
290
- """Obtention des stations pour le serveur courant
291
-
292
- site_no : numéro du site ; le site correspond au réseau de mesure : DGH pour les stations du SPW-MI et DCENN pour les stations du SPW-ARNE ;
293
- station_no, station_name : code et nom de la station ;
294
- station_local_x, station_local_y : coordonnées de la station en Lambert belge 1972 ;
295
- station_latitude,station_longitude : coordonnées de la station en ETRS89 ;
296
- river_name : nom de la rivière, cette information n’est disponible que pour les stations de mesure de hauteur d’eau et de débits, les pluviomètres ne sont pas installés sur une rivière – il n’y a donc pas de nom de rivière associé ;
297
- parametertype_name : type de paramètre ;
298
- ts_id, ts_name : code et nom de la chronique ;
299
- ts_unitname, ts_unitsymbol : nom et symbole de l’unité de mesure ;
300
- ca_sta&ca_sta_returnfields=BV_DCE : nom du bassin versant principal suivi de son abréviation (2 lettres)
301
- """
302
-
303
- returnfields = 'site_no,'
304
- returnfields += 'station_no,station_name,station_id,'
305
- returnfields += 'station_local_x,station_local_y,'
306
- returnfields += 'station_latitude,station_longitude,'
307
- returnfields += 'river_name,'
347
+ """Obtention des stations pour le serveur courant.
348
+
349
+ Une requête sur le serveur KIWIS retourne les informations pour toutes les stations.
350
+ Une séparation entre station réelle et station calculée est ensuite effectuée:
351
+ - self.realstations
352
+ - self.compstations
353
+
354
+ Champs des stations :
355
+ - site_no : numéro du site ; le site correspond au réseau de mesure : DGH pour les stations du SPW-MI et DCENN pour les stations du SPW-ARNE ;
356
+ - station_no, station_name : code et nom de la station ;
357
+ - station_local_x, station_local_y : coordonnées de la station en Lambert belge 1972 ;
358
+ - station_latitude,station_longitude : coordonnées de la station en ETRS89 ;
359
+ - river_name : nom de la rivière, cette information n’est disponible que pour les stations de mesure de hauteur d’eau et de débits, les pluviomètres ne sont pas installés sur une rivière – il n’y a donc pas de nom de rivière associé ;
360
+ - parametertype_name : type de paramètre ;
361
+ - ts_id, ts_name : code et nom de la chronique ;
362
+ - ts_unitname, ts_unitsymbol : nom et symbole de l’unité de mesure ;
363
+ - ca_sta&ca_sta_returnfields=BV_DCE : nom du bassin versant principal suivi de son abréviation (2 lettres)
364
+ """
365
+
366
+ returnfields = f'{kiwis_site_fields.site_no.value},'
367
+ returnfields += f'{station_fields.STATION_NO.value},{station_fields.STATION_NAME.value},{station_fields.STATION_ID.value},'
368
+ returnfields += f'{station_fields.STATION_LOCAL_X.value},{station_fields.STATION_LOCAL_Y.value},'
369
+ returnfields += f'{station_fields.STATION_LATITUDE.value},{station_fields.STATION_LONGITUDE.value},'
370
+ returnfields += f'{station_fields.RIVER_NAME.value},'
308
371
  returnfields += 'ca_sta'
309
372
 
310
373
  ca_sta_returnfields = 'station_gauge_datum,'
@@ -327,34 +390,67 @@ class hydrometry():
327
390
  self.stations = pd.DataFrame(json_data[1:], columns = json_data[0])
328
391
 
329
392
  #Conversion en minuscules
330
- self.stations['station_name']=self.stations['station_name'].str.lower()
393
+ self.stations[station_fields.STATION_NAME.value]=self.stations[station_fields.STATION_NAME.value].str.lower()
331
394
 
332
395
  # real stations are those with coordinates and not null
333
- self.realstations = self.stations[(~pd.isnull(self.stations['station_local_x'])) & (self.stations['station_local_x']!='')]
396
+ self.realstations = self.stations[(~pd.isnull(self.stations[station_fields.STATION_LOCAL_X.value])) & (self.stations[station_fields.STATION_LOCAL_X.value]!='')]
334
397
  # computed stations are those without coordinates or null
335
- self.compstations = self.stations[pd.isnull(self.stations['station_local_x']) | self.stations['station_local_x']!='']
398
+ self.compstations = self.stations[pd.isnull(self.stations[station_fields.STATION_LOCAL_X.value]) | self.stations[station_fields.STATION_LOCAL_X.value]!='']
336
399
 
337
400
  def get_names_xy(self, site_no = None):
338
- """Obtention des noms et coordonnées des stations pour le site"""
401
+ """Obtention des noms et coordonnées des stations pour le site
402
+
403
+ :param site_no: numéro du site
404
+ """
405
+
406
+ if site_no is None:
407
+ stations_r = self.realstations
408
+ # stations_c = self.compstations
409
+ else:
410
+ stations_r = self.realstations[self.realstations[kiwis_site_fields.site_no.value]==site_no]
411
+ # stations_c = self.compstations[self.stations[kiwis_site_fields.site_no.value]==site_no]
412
+
413
+ if stations_r is None:
414
+ return ([],[],[])
415
+ else:
416
+ return ([curname + ' - ' + str(curid) for curname, curid in zip(stations_r[station_fields.STATION_NAME.value].values,
417
+ stations_r[station_fields.STATION_ID.value].values)],
418
+ stations_r[station_fields.STATION_LOCAL_X.value].values,
419
+ stations_r[station_fields.STATION_LOCAL_Y.value].values)
420
+
421
+ def get_names_latlon(self, site_no = None):
422
+ """ Obtention des noms et coordonnées des stations pour le site
423
+
424
+ :param site_no: numéro du site
425
+ """
339
426
 
340
427
  if site_no is None:
341
428
  stations_r = self.realstations
342
429
  # stations_c = self.compstations
343
430
  else:
344
- stations_r = self.realstations[self.realstations['site_no']==site_no]
345
- # stations_c = self.compstations[self.stations['site_no']==site_no]
431
+ stations_r = self.realstations[self.realstations[kiwis_site_fields.site_no.value]==site_no]
432
+ # stations_c = self.compstations[self.stations[kiwis_site_fields.site_no.value]==site_no]
346
433
 
347
434
  if stations_r is None:
348
435
  return ([],[],[])
349
436
  else:
350
- return ([curname + ' - ' + str(curid) for curname, curid in zip(stations_r['station_name'].values, stations_r['station_id'].values)], stations_r['station_local_x'].values, stations_r['station_local_y'].values)
437
+ return ([curname + ' - ' + str(curid) for curname, curid in zip(stations_r[station_fields.STATION_NAME.value].values,
438
+ stations_r[station_fields.STATION_ID.value].values)],
439
+ stations_r[station_fields.STATION_LATITUDE.value].values,
440
+ stations_r[station_fields.STATION_LONGITUDE.value].values)
441
+
351
442
 
352
443
  def select_inside(self, xll:float, yll:float, xur:float, yur:float, tolist=False):
353
444
  """
354
445
  Recherche les stations dans une zone rectangulaire
355
446
 
356
- xll, yll : lower left
357
- xur, yur : upper right
447
+ :param xll: X lower left - Lambert 72
448
+ :param yll: Y lower left - Lambert 72
449
+ :param xur: X upper right - Lambert 72
450
+ :param yur: Y upper right - Lambert 72
451
+ :param tolist: retourne une liste de noms et codes de stations et nom un dataframe
452
+
453
+ :return: liste de noms et codes de stations ou dataframe
358
454
  """
359
455
 
360
456
  if xll>xur:
@@ -366,35 +462,103 @@ class hydrometry():
366
462
  yll=yur
367
463
  yur=tmpy
368
464
 
369
- df = self.realstations[(self.realstations['station_local_x'].to_numpy(dtype=np.float64)>=xll) & (self.realstations['station_local_x'].to_numpy(dtype=np.float64)<=xur) & (self.realstations['station_local_y'].to_numpy(dtype=np.float64)>=yll) & (self.realstations['station_local_y'].to_numpy(dtype=np.float64)<=yur)]
465
+ df = self.realstations[(self.realstations[station_fields.STATION_LOCAL_X.value].to_numpy(dtype=np.float64)>=xll) & (self.realstations[station_fields.STATION_LOCAL_X.value].to_numpy(dtype=np.float64)<=xur) & \
466
+ (self.realstations[station_fields.STATION_LOCAL_Y.value].to_numpy(dtype=np.float64)>=yll) & (self.realstations[station_fields.STATION_LOCAL_Y.value].to_numpy(dtype=np.float64)<=yur)]
467
+ if tolist:
468
+ list_name_code = [curname+' --- '+curno for curname,curno in zip(df[station_fields.STATION_NAME.value].values,df[station_fields.STATION_NO.value].values)]
469
+ return list_name_code
470
+ else:
471
+ return df
472
+
473
+ def select_inside_latlon(self, lonll:float, latll:float, lonur:float, latur:float, tolist=False):
474
+ """
475
+ Recherche les stations dans une zone rectangulaire
476
+
477
+ :param lonll: Longitude lower left - WGS84
478
+ :param latll: Latitude lower left - WGS84
479
+ :param lonur: Longitude upper right - WGS84
480
+ :param latur: Latitude upper right - WGS84
481
+ :param tolist: retourne une liste de noms et codes de stations et nom un dataframe
482
+
483
+ :return: liste de noms et codes de stations ou dataframe
484
+ """
485
+
486
+ if lonll>lonur:
487
+ tmpx=lonll
488
+ lonll=lonur
489
+ lonur=tmpx
490
+ if latll>latur:
491
+ tmpy=latll
492
+ latll=latur
493
+ latur=tmpy
494
+
495
+ df = self.realstations[(self.realstations[station_fields.STATION_LONGITUDE.value].to_numpy(dtype=np.float64)>=lonll) & (self.realstations[station_fields.STATION_LONGITUDE.value].to_numpy(dtype=np.float64)<=lonur) & \
496
+ (self.realstations[station_fields.STATION_LATITUDE.value].to_numpy(dtype=np.float64)>=latll) & (self.realstations[station_fields.STATION_LATITUDE.value].to_numpy(dtype=np.float64)<=latur)]
370
497
  if tolist:
371
- list_name_code = [curname+' --- '+curno for curname,curno in zip(df['station_name'].values,df['station_no'].values)]
498
+ list_name_code = [curname+' --- '+curno for curname,curno in zip(df[station_fields.STATION_NAME.value].values,df[station_fields.STATION_NO.value].values)]
372
499
  return list_name_code
373
500
  else:
374
501
  return df
375
502
 
376
- def sort_nearests(self,x:float,y:float):
503
+ def sort_nearests(self, x:float, y:float):
504
+ """
505
+ Trie les stations en fonction de la distance et retourne un index trié
506
+
507
+ :param x: coordonnée x - Lambert 72
508
+ :param y: coordonnée y - Lambert 72
509
+ """
510
+ dist = np.asarray([(float(cur[station_fields.STATION_LOCAL_X.value]) - x)**2 + (float(cur[station_fields.STATION_LOCAL_Y.value]) - y)**2 for idx,cur in self.realstations.iterrows()])
511
+ index = np.arange(len(dist))[dist.argsort()]
512
+
513
+ return index
514
+
515
+ def sort_nearests_latlon(self, lon:float, lat:float):
377
516
  """
378
517
  Trie les stations en fonction de la distance et retourne un index trié
518
+
519
+ :param lon: longitude - WGS84
520
+ :param lat: latitude - WGS84
379
521
  """
380
- dist = np.asarray([(float(cur['station_local_x']) - x)**2 + (float(cur['station_local_y']) - y)**2 for idx,cur in self.realstations.iterrows()])
522
+ dist = np.asarray([(float(cur[station_fields.STATION_LATITUDE.value]) - lat)**2 + (float(cur[station_fields.STATION_LONGITUDE.value]) - lon)**2 for idx,cur in self.realstations.iterrows()])
381
523
  index = np.arange(len(dist))[dist.argsort()]
382
524
 
383
525
  return index
384
526
 
385
- def find_nearest(self,x:float,y:float, tolist=False):
527
+ def find_nearest(self, x:float, y:float, tolist=False):
386
528
  """
387
529
  Trouve la station la plus proche
530
+
531
+ :param x: coordonnée x - Lambert 72
532
+ :param y: coordonnée y - Lambert 72
388
533
  """
389
534
  index = self.sort_nearests(x,y)
390
535
 
391
536
  if tolist:
392
- return [self.realstations.iloc[index[0]]['station_name']+' --- '+self.realstations.iloc[index[0]]['station_no']]
537
+ return [self.realstations.iloc[index[0]][station_fields.STATION_NAME.value]+' --- '+self.realstations.iloc[index[0]][station_fields.STATION_NO.value]]
538
+ else:
539
+ return self.realstations.iloc[index[0]]
540
+
541
+ def find_nearest_latlon(self, lon:float, lat:float, tolist=False):
542
+ """
543
+ Trouve la station la plus proche
544
+
545
+ :param lon: longitude - WGS84
546
+ :param lat: latitude - WGS84
547
+ """
548
+
549
+ index = self.sort_nearests_latlon(lon,lat)
550
+
551
+ if tolist:
552
+ return [self.realstations.iloc[index[0]][station_fields.STATION_NAME.value]+' --- '+self.realstations.iloc[index[0]][station_fields.STATION_NO.value]]
393
553
  else:
394
554
  return self.realstations.iloc[index[0]]
395
555
 
396
556
  def get_timeseries_group(self, rfw:Literal['rain','waterdepth','flowrate'], time:Literal['5min','5or10min','1h','1d','1m']):
397
- """Obtention des stations pour le groupe souhaité"""
557
+ """Obtention des stations pour le groupe souhaité
558
+
559
+ :param rfw: type de groupe - rain, flowrate, waterdepth
560
+ :param time: type de série - 5min, 5or10min, 1h, 1d, 1m
561
+ """
398
562
 
399
563
  if self.url!='':
400
564
  stations=None
@@ -406,21 +570,31 @@ class hydrometry():
406
570
 
407
571
  return stations
408
572
 
409
- def get_sites(self):
410
- """Obtention des sites pour le serveur courant"""
411
- if self.dir!='' and exists(join(self.dir,'sites.csv')):
573
+ def get_sites(self, forcerequest=False):
574
+ """Obtention des sites pour le serveur courant
575
+
576
+ :param forcerequest: force la requête même si les données de cache sont déjà présentes"""
577
+
578
+ if self.dir!='' and exists(join(self.dir,'sites.csv')) and not forcerequest:
412
579
  self.sites = pd.read_csv(join(self.dir,'sites.csv'),index_col=0)
413
- elif self.url!='':
580
+ elif self.url!='' or forcerequest:
414
581
  json_data = requests.get(self._get_commandstr(kiwis_command.getSiteList),verify=True, headers=self._header).json()
415
582
  self.sites = pd.DataFrame(json_data[1:], columns = json_data[0])
583
+ else:
584
+ self.sites = None
585
+
586
+ def get_groups(self, forcerequest=False):
587
+ """Obtention des groupes pour le serveur courant
416
588
 
417
- def get_groups(self):
418
- """Obtention des groupes pour le serveur courant"""
419
- if self.dir!='' and exists(join(self.dir,'groups.csv')):
589
+ :param forcerequest: force la requête même si les données de cache sont déjà présentes"""
590
+
591
+ if self.dir!='' and exists(join(self.dir,'groups.csv')) and not forcerequest:
420
592
  self.groups = pd.read_csv(join(self.dir,'groups.csv'),index_col=0)
421
- elif self.url!='':
593
+ elif self.url!='' or forcerequest:
422
594
  json_data = requests.get(self._get_commandstr(kiwis_command.getGroupList),verify=True, headers=self._header).json()
423
595
  self.groups = pd.DataFrame(json_data[1:], columns = json_data[0])
596
+ else:
597
+ self.groups = None
424
598
 
425
599
  # def get_ratingcurves(self):
426
600
  # """Obtention des courbes de tarage pour le serveur courant"""
@@ -430,15 +604,24 @@ class hydrometry():
430
604
  # json_data = requests.get(self.url+'?request=getRatingCurveList&datasource=0&format=json',verify=True).json()
431
605
  # self.ratingcurves = pd.DataFrame(json_data[1:], columns = json_data[0])
432
606
 
433
- def get_requests(self):
434
- """Obtention des requêtes possibles pour le serveur courant"""
435
- if self.dir!='' and exists(join(self.dir,'requests.csv')):
607
+ def get_requests(self, forcerequest=False):
608
+ """Obtention des requêtes possibles pour le serveur courant
609
+
610
+ :param forcerequest: force la requête même si les données de cache sont déjà présentes"""
611
+
612
+ if self.dir!='' and exists(join(self.dir,'requests.csv')) and not forcerequest:
436
613
  self.requests = pd.read_csv(join(self.dir,'requests.csv'),index_col=0)
437
- elif self.url!='':
614
+ elif self.url!='' or forcerequest:
438
615
  json_data = requests.get(self._get_commandstr(kiwis_command.getrequestinfo),verify=True, headers=self._header).json()
439
616
  self.requests = pd.DataFrame(json_data[0]['Requests'])
617
+ else:
618
+ self.requests = None
619
+
620
+ def print_requestinfo(self, which:kiwis_command):
621
+ """ Affichage des informations pour une requête donnée
622
+
623
+ :param which: requête à afficher"""
440
624
 
441
- def print_requestinfo(self,which:Enum):
442
625
  if self.requests is None:
443
626
  self.get_requests()
444
627
 
@@ -448,8 +631,13 @@ class hydrometry():
448
631
  for cur in kiwis_request_info:
449
632
  print(myrequest[cur.value])
450
633
 
451
- def timeseries_list(self,stationname='',stationcode=''):
452
- """Récupération de la liste des TimeSeries pour l'id d'une station"""
634
+ def timeseries_list(self, stationname:str = '', stationcode:str = ''):
635
+ """Récupération de la liste des TimeSeries pour l'id d'une station
636
+ soit via le nom de la station, soit via le code de la station.
637
+
638
+ :param stationname: nom de la station
639
+ :param stationcode: code de la station
640
+ """
453
641
 
454
642
  if stationname!='':
455
643
  id=self.get_stationid(stationname)
@@ -463,12 +651,15 @@ class hydrometry():
463
651
 
464
652
  return id,pd.DataFrame(json_data[1:], columns = json_data[0])
465
653
 
466
- def save_all_lists(self,dir):
467
- """Sauveragde des listes pour toutes les stations"""
468
- for curstation in self.stations['station_no']:
469
- self.save_list(stationcode=curstation,dir=dir)
654
+ def save_all_lists(self, dir:str):
655
+ """Sauveragde des listes pour toutes les stations
656
+
657
+ :param dir: répertoire de sauvegarde"""
470
658
 
471
- def _get_filename_list(self,stationname='',stationcode=''):
659
+ for curstation in self.stations[station_fields.STATION_NO.value]:
660
+ self.save_list(stationcode=curstation, dir=dir)
661
+
662
+ def _get_filename_list(self, stationname:str='', stationcode:str=''):
472
663
  """retourne un nom de fichier avec la station et le code
473
664
 
474
665
  Utile car dans certains noms de la BDD KIWIS il y a un caractère '/' qui ne peut être utilisé comme nom de fichier
@@ -484,7 +675,8 @@ class hydrometry():
484
675
 
485
676
  return stationname.replace('/','-') + '_' + stationcode + '_' + str(id) + '.csv'
486
677
 
487
- def _get_filename_series(self,stationname='',stationcode='',which:Enum=kiwis_default_q.Q_FULL):
678
+ def _get_filename_series(self,stationname:str='',stationcode:str='',
679
+ which:kiwis_default_q | kiwis_default_h | kiwis_keywords_horq | kiwis_keywords_rain = kiwis_default_q.Q_FULL):
488
680
  """retourne un nom de fichier avec la station et le code et le type de données
489
681
 
490
682
  Utile car dans certains noms de la BDD KIWIS il y a un caractère '/' qui ne peut être utilisé comme nom de fichier
@@ -500,16 +692,24 @@ class hydrometry():
500
692
 
501
693
  return stationname.replace('/','-') + '_' + stationcode + '_' + str(id) + '_' + which.value + '.csv'
502
694
 
503
- def save_list(self,stationname='',stationcode='',dir=''):
504
- """Sauvegarde de la liste des des timeseries dans un fichier"""
505
- if not exists(dir):
506
- mkdir(dir)
695
+ def save_list(self, stationname:str = '', stationcode:str = '', dir:str = ''):
696
+ """Sauvegarde de la liste des des timeseries dans un fichier
697
+
698
+ :param stationname: nom de la station
699
+ :param stationcode: code de la station
700
+ :param dir: répertoire de sauvegarde"""
701
+
702
+ dir = Path(dir)
703
+ if not dir.exists():
704
+ dir.mkdir(parents=True, exist_ok=True)
507
705
 
508
706
  id,list=self.timeseries_list(stationname=stationname,stationcode=stationcode)
509
707
  filename = self._get_filename_list(stationname,stationcode)
510
- list.to_csv(join(dir,filename))
708
+ list.to_csv(dir / filename)
511
709
 
512
- def timeseries(self,stationname='', stationcode='', dir='', fromdate=datetime.now()-timedelta(60), todate=datetime.now(), ts_name:str='', ts_id:str='', interval=3600, timezone = 'GMT+0'):
710
+ def timeseries(self,stationname:str='', stationcode:str='', dir:str='',
711
+ fromdate=datetime.now()-timedelta(60), todate=datetime.now(),
712
+ ts_name:str='', ts_id:str='', interval:int=3600, timezone:str = 'GMT+0'):
513
713
  """
514
714
  Récupération des valeurs d'une TimeSerie
515
715
  - sur base des dates
@@ -517,6 +717,16 @@ class hydrometry():
517
717
  - le nom de la station ou le code ET le nom de la timeserie --> dans ce cas, la routine commence par retrouver l'id de la ts
518
718
  - directement l'id de la timeserie
519
719
 
720
+ :param stationname: nom de la station
721
+ :param stationcode: code de la station
722
+ :param dir: répertoire de sauvegarde
723
+ :param fromdate: date de début
724
+ :param todate: date de fin
725
+ :param ts_name: nom de la timeserie
726
+ :param ts_id: id de la timeserie
727
+ :param interval: intervalle de temps
728
+ :param timezone: timezone
729
+
520
730
  """
521
731
 
522
732
  if timezone=='Europe/Brussels' or timezone=='local':
@@ -542,11 +752,11 @@ class hydrometry():
542
752
  if len(json_data)==1:
543
753
  return None
544
754
 
545
- ts_id = str(int(pd.DataFrame(json_data[1:], columns = json_data[0])['ts_id'].iloc[0]))
755
+ ts_id = str(int(pd.DataFrame(json_data[1:], columns = json_data[0])[timeseries_fields.TS_ID.value].iloc[0]))
546
756
  else:
547
757
  filename = self._get_filename_list(stationname,stationcode)
548
758
  curlist=pd.read_csv(join(dir,filename),index_col=0)
549
- ts_id = str(int(curlist.loc(curlist['ts_name'==ts_name])['ts_id']))
759
+ ts_id = str(int(curlist.loc(curlist[timeseries_fields.TS_NAME.value==ts_name])[timeseries_fields.TS_ID.value]))
550
760
 
551
761
  if "1h" in ts_name:
552
762
  nb = (todate - fromdate).days*24
@@ -573,7 +783,10 @@ class hydrometry():
573
783
  locts=[]
574
784
  while curfrom<todate:
575
785
  print(curfrom, curend)
576
- locts.append(self.timeseries(stationname, stationcode, dir, curfrom, curend, ts_name, ts_id, timezone=timezone))
786
+ tmpts = self.timeseries(stationname, stationcode, dir, curfrom, curend, ts_name, ts_id, timezone=timezone)
787
+ if len(tmpts)>0:
788
+ locts.append(tmpts)
789
+
577
790
  curfrom = curend
578
791
  curend = curfrom+timedelta(seconds=200000 * cursec)
579
792
  if curend>todate:
@@ -596,7 +809,9 @@ class hydrometry():
596
809
 
597
810
  return df.squeeze()
598
811
 
599
- def timeseries_qc(self,stationname='', stationcode='', dir='', fromdate=datetime.now()-timedelta(60), todate=datetime.now(), ts_name:str='', ts_id:str='', interval=3600, timezone = 'GMT+0'):
812
+ def timeseries_qc(self, stationname:str='', stationcode:str='', dir:str='',
813
+ fromdate=datetime.now()-timedelta(60), todate=datetime.now(),
814
+ ts_name:str='', ts_id:str='', interval:int=3600, timezone:str = 'GMT+0'):
600
815
  """
601
816
  Récupération des quality code d'une TimeSerie
602
817
  - sur base des dates
@@ -604,6 +819,16 @@ class hydrometry():
604
819
  - le nom de la station ou le code ET le nom de la timeserie --> dans ce cas, la routine commence par retrouver l'id de la ts
605
820
  - directement l'id de la timeserie
606
821
 
822
+ :param stationname: nom de la station
823
+ :param stationcode: code de la station
824
+ :param dir: répertoire de sauvegarde
825
+ :param fromdate: date de début
826
+ :param todate: date de fin
827
+ :param ts_name: nom de la timeserie
828
+ :param ts_id: id de la timeserie
829
+ :param interval: intervalle de temps
830
+ :param timezone: timezone
831
+
607
832
  """
608
833
  if timezone=='Europe/Brussels' or timezone=='local':
609
834
  timezone=''
@@ -629,11 +854,11 @@ class hydrometry():
629
854
  if len(json_data)==1:
630
855
  return None
631
856
 
632
- ts_id = str(int(pd.DataFrame(json_data[1:], columns = json_data[0])['ts_id'].iloc[0]))
857
+ ts_id = str(int(pd.DataFrame(json_data[1:], columns = json_data[0])[timeseries_fields.TS_ID.value].iloc[0]))
633
858
  else:
634
859
  filename = self._get_filename_list(stationname,stationcode)
635
860
  curlist=pd.read_csv(join(dir,filename),index_col=0)
636
- ts_id = str(int(curlist.loc(curlist['ts_name'==ts_name])['ts_id']))
861
+ ts_id = str(int(curlist.loc(curlist[timeseries_fields.TS_NAME.value==ts_name])[timeseries_fields.TS_ID.value]))
637
862
 
638
863
  if "1h" in ts_name:
639
864
  nb = (todate - fromdate).days*24
@@ -683,14 +908,27 @@ class hydrometry():
683
908
 
684
909
  return df.squeeze()
685
910
 
686
- def fromcsv(self,dir='spw',stationname='',stationcode='',which:Enum=kiwis_default_q.Q_FULL,fromdate:datetime=None,todate:datetime=None):
911
+ def fromcsv(self, dir:str='spw', stationname:str='', stationcode:str='',
912
+ which:kiwis_default_q | kiwis_default_h | kiwis_keywords_horq | kiwis_keywords_rain = kiwis_default_q.Q_FULL,
913
+ fromdate:datetime=None, todate:datetime=None):
687
914
  """
688
- Lecture depuis un fichier csv créé depuis un import précédent
689
- Les fichiers doivent être disponibles depuis un sous-répertoire spw
915
+ Lecture depuis un fichier csv créé depuis un import précédent.
916
+ Les fichiers doivent être disponibles depuis un sous-répertoire spw.
917
+
918
+ :param dir: répertoire de sauvegarde
919
+ :param stationname: nom de la station
920
+ :param stationcode: code de la station
921
+ :param which: type de données
922
+ :param fromdate: date de début
923
+ :param todate: date de fin
924
+
690
925
  """
691
- filename=filename=self._get_filename_series(stationname,stationcode,which)
926
+ filename=self._get_filename_series(stationname,stationcode,which)
927
+
928
+ dir = Path(dir)
929
+ filename = dir / filename
692
930
 
693
- if exists(filename):
931
+ if filename.exists():
694
932
  mydata= pd.read_csv(filename,header=0,index_col=0,parse_dates=True,engine='pyarrow').squeeze("columns")
695
933
  else:
696
934
  return
@@ -704,88 +942,134 @@ class hydrometry():
704
942
  else:
705
943
  return mydata[fromdate:todate]
706
944
 
707
- def saveas(self,flow:pd.Series,dir:str,stationname='',stationcode='',which:Enum=kiwis_default_q.Q_FULL):
708
- """Sauvegarde d'une series pandas dans un fichier .csv"""
945
+ def saveas(self, flow:pd.Series, dir:str, stationname='', stationcode='',
946
+ which:kiwis_default_q | kiwis_default_h | kiwis_keywords_horq | kiwis_keywords_rain = kiwis_default_q.Q_FULL):
947
+ """Sauvegarde d'une series pandas dans un fichier .csv
948
+
949
+ :param flow: série pandas
950
+ :param dir: répertoire de sauvegarde
951
+ :param stationname: nom de la station
952
+ :param stationcode: code de la station
953
+ :param which: type de données
954
+ """
955
+
709
956
  filename=self._get_filename_series(stationname,stationcode,which.value)
957
+
958
+ dir = Path(dir)
959
+ filename = dir / filename
960
+
710
961
  flow.to_csv(filename,header=['Data'], date_format="%Y-%m-%dT%H:%M:%S.%f%z")
711
962
 
712
- def get_stationid(self,name:str='',code=''):
713
- """Récupération de l'id sur base du nom ou du code"""
963
+ def get_stationid(self, name:str='', code:str='') -> int:
964
+ """Récupération de l'id sur base du nom ou du code
965
+
966
+ :param name: nom de la station
967
+ :param code: code de la station"""
968
+
714
969
  if name!='':
715
- return int(self.stations.loc[self.stations['station_name']==name.lower()]['station_id'].iloc[0])
970
+ return int(self.stations.loc[self.stations[station_fields.STATION_NAME.value]==name.lower()][station_fields.STATION_ID.value].iloc[0])
716
971
  elif code!='':
717
- return int(self.stations.loc[self.stations['station_no']==code]['station_id'].iloc[0])
972
+ return int(self.stations.loc[self.stations[station_fields.STATION_NO.value]==code][station_fields.STATION_ID.value].iloc[0])
718
973
  else:
719
974
  return None
720
975
 
721
- def get_gauge_datum(self,name:str='',code=''):
722
- """Récupération de l'altitude de référence sur base du nom ou du code"""
976
+ def get_gauge_datum(self,name:str='',code:str=''):
977
+ """Récupération de l'altitude de référence sur base du nom ou du code
978
+
979
+ :param name: nom de la station
980
+ :param code: code de la station"""
981
+
723
982
  try:
724
983
  if name!='':
725
- return self.stations.loc[self.stations['station_name']==name.lower()]['station_gauge_datum'].iloc[0]
984
+ return self.stations.loc[self.stations[station_fields.STATION_NAME.value]==name.lower()]['station_gauge_datum'].iloc[0]
726
985
  elif code!='':
727
- return self.stations.loc[self.stations['station_no']==code]['station_gauge_datum'].iloc[0]
986
+ return self.stations.loc[self.stations[station_fields.STATION_NO.value]==code]['station_gauge_datum'].iloc[0]
728
987
  else:
729
988
  return None
730
989
  except:
731
990
  return None
732
991
 
733
- def get_catchment_size(self,name:str='',code=''):
734
- """Récupération de la surface du BV de référence sur base du nom ou du code"""
992
+ def get_catchment_size(self,name:str='',code:str=''):
993
+ """Récupération de la surface du BV de référence sur base du nom ou du code
994
+
995
+ :param name: nom de la station
996
+ :param code: code de la station"""
997
+
735
998
  try:
736
999
  if name!='':
737
- return self.stations.loc[self.stations['station_name']==name.lower()]['CATCHMENT_SIZE'].iloc[0]
1000
+ return self.stations.loc[self.stations[station_fields.STATION_NAME.value]==name.lower()]['CATCHMENT_SIZE'].iloc[0]
738
1001
  elif code!='':
739
- return self.stations.loc[self.stations['station_no']==code]['CATCHMENT_SIZE'].iloc[0]
1002
+ return self.stations.loc[self.stations[station_fields.STATION_NO.value]==code]['CATCHMENT_SIZE'].iloc[0]
740
1003
  else:
741
1004
  return None
742
1005
  except:
743
1006
  return None
744
1007
 
745
- def get_bv_dce(self,name:str='',code=''):
746
- """Récupération du nom de BV au sens de la DCE "Directive Cadre Eau" sur base du nom ou du code"""
1008
+ def get_bv_dce(self,name:str='',code:str=''):
1009
+ """Récupération du nom de BV au sens de la DCE "Directive Cadre Eau" sur base du nom ou du code
1010
+
1011
+ :param name: nom de la station
1012
+ :param code: code de la station"""
1013
+
747
1014
  try:
748
1015
  if name!='':
749
- return self.stations.loc[self.stations['station_name']==name.lower()]['BV_DCE'].iloc[0]
1016
+ return self.stations.loc[self.stations[station_fields.STATION_NAME.value]==name.lower()]['BV_DCE'].iloc[0]
750
1017
  elif code!='':
751
- return self.stations.loc[self.stations['station_no']==code]['BV_DCE'].iloc[0]
1018
+ return self.stations.loc[self.stations[station_fields.STATION_NO.value]==code]['BV_DCE'].iloc[0]
752
1019
  else:
753
1020
  return None
754
1021
  except:
755
1022
  return None
756
1023
 
757
1024
  def get_stationcode(self,name:str=''):
758
- """Récupération du code sur base du nom"""
1025
+ """Récupération du code sur base du nom
1026
+
1027
+ :param name: nom de la station
1028
+ """
1029
+
759
1030
  if name!='':
760
- return self.stations.loc[self.stations['station_name']==name.lower()]['station_no'].squeeze()
1031
+ return self.stations.loc[self.stations[station_fields.STATION_NAME.value]==name.lower()][station_fields.STATION_NO.value].squeeze()
761
1032
  else:
762
1033
  return None
763
1034
 
764
1035
  def get_stationname(self,code:str=''):
765
- """Récupération du nom sur base du code"""
1036
+ """Récupération du nom sur base du code
1037
+
1038
+ :param code: code de la station"""
1039
+
766
1040
  if code!='':
767
- return self.stations.loc[self.stations['station_no']==code]['station_name'].squeeze()
1041
+ return self.stations.loc[self.stations[station_fields.STATION_NO.value]==code][station_fields.STATION_NAME.value].squeeze()
768
1042
  else:
769
1043
  return None
770
1044
 
771
- def get_siteid(self,name:str='',code=''):
772
- """Récupération de l'id sur base du nom ou du code"""
1045
+ def get_siteid(self,name:str='',code:str=''):
1046
+ """Récupération de l'id sur base du nom ou du code
1047
+
1048
+ :param name: nom de la station
1049
+ :param code: code de la station"""
1050
+
773
1051
  if name!='':
774
- return int(self.sites.loc[self.sites[kiwis_site_fields.site_name.value]==name.lower()]['site_id'])
1052
+ return int(self.sites.loc[self.sites[kiwis_site_fields.site_name.value]==name.lower()][kiwis_site_fields.site_id.value])
775
1053
  elif code!='':
776
- return int(self.sites.loc[self.sites[kiwis_site_fields.site_no.value]==code]['site_id'])
1054
+ return int(self.sites.loc[self.sites[kiwis_site_fields.site_no.value]==code][kiwis_site_fields.site_id.value])
777
1055
  else:
778
1056
  return None
779
1057
 
780
- def get_sitecode(self,name:str=''):
781
- """Récupération du code sur base du nom"""
1058
+ def get_sitecode(self, name:str=''):
1059
+ """Récupération du code sur base du nom
1060
+
1061
+ :param name: nom de la station"""
1062
+
782
1063
  if name!='':
783
1064
  return self.sites.loc[self.sites[kiwis_site_fields.site_name.value]==name.lower()][kiwis_site_fields.site_no.value].squeeze()
784
1065
  else:
785
1066
  return None
786
1067
 
787
1068
  def get_sitename(self,code:str=''):
788
- """Récupération du nom sur base du code"""
1069
+ """Récupération du nom sur base du code
1070
+
1071
+ :param code: code de la station"""
1072
+
789
1073
  if code!='':
790
1074
  return self.sites.loc[self.sites[kiwis_site_fields.site_no.value]==code][kiwis_site_fields.site_name.value].squeeze()
791
1075
  else: