wolfhece 2.1.66__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.
wolfhece/PyDraw.py CHANGED
@@ -8500,8 +8500,8 @@ class WolfMapViewer(wx.Frame):
8500
8500
  # \n \
8501
8501
  # !! ACTIONs !!\n \
8502
8502
  # N : sélection noeud par noeud de la matrice courante\n \
8503
- # B : sélection par vecteur temporaire de la matrice courante\n \
8504
- # V : sélection par vecteur activé de la matrice courante - zone intérieure\n \
8503
+ # b, B : sélection par vecteur de la matrice courante - zone intérieure\n \
8504
+ # v, V : sélection par vecteur de la matrice courante - trace du vecteur\n \
8505
8505
  # r : reset de la sélection de la matrice courante\n \
8506
8506
  # R : reset de toutes les sélections de la matrice courante\n \
8507
8507
  # P : sélection de la section transversale par click souris\n \
@@ -8558,8 +8558,8 @@ class WolfMapViewer(wx.Frame):
8558
8558
  'F11': _('Arrays : select by criteria'),
8559
8559
  'F12': _('Arrays : operations'),
8560
8560
  'n or N': _('Arrays : node-by-node selection'),
8561
- 'b or B': _('Arrays : temporary vector selection'),
8562
- 'v or V': _('Arrays : activated vector selection - inner zone'),
8561
+ 'b or B': _('Arrays : temporary/active vector selection - inside polygon'),
8562
+ 'v or V': _('Arrays : temporary/active vector selection - along polyline'),
8563
8563
 
8564
8564
  'r': _('Arrays : reset the selection'),
8565
8565
  'R': _('Arrays : reset the selection and the associated dictionnary'),
@@ -9011,6 +9011,12 @@ class WolfMapViewer(wx.Frame):
9011
9011
  elif key in LIST_1TO9:
9012
9012
 
9013
9013
  if self.active_array is not None:
9014
+
9015
+ if self.active_array.SelectionData.myselection == 'all':
9016
+ logging.warning(_('No selection to transfer to the dictionary !'))
9017
+ logging.info(_('Please select some nodes before transfering to the dictionary, not ALL !'))
9018
+ return
9019
+
9014
9020
  colors = [(0, 0, 255, 255), (0, 255, 0, 255), (0, 128, 255, 255), (255, 255, 0, 255), (255, 165, 0, 255), (128, 0, 128, 255), (255, 192, 203, 255), (165, 42, 42, 255), (128, 128, 128, 255)]
9015
9021
  idx = LIST_1TO9.index(key)
9016
9022
  if idx > 8:
@@ -9068,16 +9074,33 @@ class WolfMapViewer(wx.Frame):
9068
9074
  if self.active_res2d is not None:
9069
9075
  self.active_res2d.properties.select_node_by_node()
9070
9076
 
9077
+ if self.active_array is None and self.active_res2d is None:
9078
+ logging.warning(_('No active array or result 2D to select node by node !'))
9079
+
9071
9080
  elif key == ord('V'): # V
9072
9081
  if self.active_array is not None:
9073
- self.active_array.myops.select_vector_inside_manager()
9082
+ if shiftdown:
9083
+ self.active_array.myops.select_vector_inside_manager()
9084
+ else:
9085
+ self.active_array.myops.select_vector_inside_tmp()
9086
+ else:
9087
+ logging.warning(_('No active array to select the vector inside !'))
9074
9088
 
9075
9089
  elif key == ord('B'): # B
9076
9090
  if self.active_array is not None:
9077
- self.active_array.myops.select_vector_inside_tmp()
9091
+ if shiftdown:
9092
+ self.active_array.myops.select_vector_under_manager()
9093
+ else:
9094
+ self.active_array.myops.select_vector_under_tmp()
9095
+ else:
9096
+ logging.warning(_('No active array to select the vector inside !'))
9078
9097
 
9079
9098
  elif key == ord('P'): # P
9080
- self.start_action('Select nearest profile', _('Select nearest profile'))
9099
+
9100
+ if self.active_cs is not None:
9101
+ self.start_action('Select nearest profile', _('Select nearest profile'))
9102
+ else:
9103
+ logging.warning(_('No active cross section to select the nearest profile !'))
9081
9104
 
9082
9105
  elif key == ord('Z') and shiftdown: # Z
9083
9106
  self.width = self.width / 1.1
wolfhece/apps/version.py CHANGED
@@ -5,7 +5,7 @@ class WolfVersion():
5
5
 
6
6
  self.major = 2
7
7
  self.minor = 1
8
- self.patch = 66
8
+ self.patch = 67
9
9
 
10
10
  def __str__(self):
11
11
 
@@ -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:
@@ -10,14 +10,15 @@ copying or distribution of this file, via any medium, is strictly prohibited.
10
10
 
11
11
  import wx
12
12
  import logging
13
+ from pathlib import Path
13
14
 
14
15
 
15
16
  from . import Parser, Expression
16
17
 
17
18
  class Calculator(wx.Frame):
18
-
19
+
19
20
  def __init__(self, mapviewer=None):
20
-
21
+
21
22
  from ..PyDraw import WolfMapViewer, draw_type, WolfArray
22
23
 
23
24
  super(Calculator, self).__init__(None, title='Calculator', size=(500, 300))
@@ -38,18 +39,23 @@ class Calculator(wx.Frame):
38
39
  self._comment = wx.TextCtrl(self, style=wx.TE_RIGHT|wx.TE_RICH2|wx.TE_MULTILINE)
39
40
  self.memory = wx.TextCtrl(self, style=wx.TE_RIGHT|wx.TE_RICH2|wx.TE_MULTILINE)
40
41
  self.btn_reset_memory = wx.Button(self, label='Reset Memory')
41
-
42
+
42
43
  self.Bind(wx.EVT_BUTTON, lambda v: self.bt_press(v.EventObject.Label))
43
44
 
44
- self._btns[-1][-2].SetDefault()
45
+ self._btns[-1][-2].SetDefault()
45
46
 
46
47
  self.Bind(wx.EVT_CHAR_HOOK, self.char_press)
47
48
  self.btn_reset_memory.Bind(wx.EVT_BUTTON, lambda v: self._memory.clear())
48
-
49
+
49
50
  self.SetSizer(self.pack([self._disp] + [self.pack(x) for x in self._btns] + [self.pack([self._comment, self.btn_reset_memory, self.memory])], orient=wx.VERTICAL))
50
51
 
51
52
  self._disp.SetFocus()
52
53
 
54
+ icon = wx.Icon()
55
+ icon_path = Path(__file__).parent.parent / "apps/wolf_logo2.bmp"
56
+ icon.CopyFromBitmap(wx.Bitmap(str(icon_path), wx.BITMAP_TYPE_ANY))
57
+ self.SetIcon(icon)
58
+
53
59
  self.Show()
54
60
 
55
61
  def pack(self, items, orient=wx.HORIZONTAL):
@@ -57,11 +63,11 @@ class Calculator(wx.Frame):
57
63
  sizer = wx.BoxSizer(orient)
58
64
  sizer.AddMany((i, 1, wx.EXPAND|wx.ALL, 0) for i in items)
59
65
  return sizer
60
-
66
+
61
67
  @property
62
68
  def command(self) -> str:
63
- return self._disp.Value
64
-
69
+ return self._disp.Value
70
+
65
71
  @command.setter
66
72
  def command(self, value):
67
73
  self._disp.Value = str(value)
@@ -70,16 +76,16 @@ class Calculator(wx.Frame):
70
76
  @property
71
77
  def comment(self) -> str:
72
78
  return self._comment.Value
73
-
79
+
74
80
  @comment.setter
75
81
  def comment(self, value):
76
82
  self._comment.Value = str(value)
77
83
 
78
84
  def check_command(self) -> bool:
79
- """ Check if the command is valid """
80
-
85
+ """ Check if the command is valid """
86
+
81
87
  from ..PyDraw import draw_type
82
-
88
+
83
89
  if '\n' in self.command:
84
90
  self.evaluate_multilines()
85
91
  return False
@@ -94,7 +100,7 @@ class Calculator(wx.Frame):
94
100
  if self._mapviewer is not None:
95
101
  id_arrays = self._mapviewer.get_list_keys(drawing_type=draw_type.ARRAYS,
96
102
  checked_state=None)
97
-
103
+
98
104
  for id_array in id_arrays:
99
105
  self._memory[id_array] = self._mapviewer.get_obj_from_id(id_array, drawtype=draw_type.ARRAYS)
100
106
 
@@ -124,27 +130,27 @@ class Calculator(wx.Frame):
124
130
  def evaluate(self, mem_last_command=True):
125
131
  """ Evaluate the command """
126
132
  from ..PyDraw import WolfArray, draw_type
127
-
133
+
128
134
  if mem_last_command:
129
135
  self._last_command = self.command
130
136
 
131
137
  ret = self.check_command()
132
-
138
+
133
139
  if ret:
134
140
  args = {var:self._memory[var] for var in self._parsed_command.variables()}
135
141
  res = self._parsed_command.evaluate(args)
136
142
 
137
143
  if isinstance(res, dict):
138
-
144
+
139
145
  comment = 'Storing\n'
140
-
146
+
141
147
  for key, value in res.items():
142
148
  self._memory[key] = value
143
149
  comment += f'{key} = {value}\n'
144
-
150
+
145
151
  self.comment = comment
146
152
  self.command = ''
147
-
153
+
148
154
  elif isinstance(res, str|int|float):
149
155
  self.command = res
150
156
 
@@ -154,10 +160,10 @@ class Calculator(wx.Frame):
154
160
  id = self.command
155
161
  while id in ids:
156
162
  id += '_'
157
-
163
+
158
164
  self._mapviewer.add_object('array', newobj=res, id = id)
159
165
  self.command = ''
160
-
166
+
161
167
  return res
162
168
 
163
169
  def char_press(self, e:wx.KeyEvent):
@@ -168,13 +174,13 @@ class Calculator(wx.Frame):
168
174
 
169
175
  unicodekey = e.GetUnicodeKey()
170
176
  key = e.GetKeyCode()
171
-
177
+
172
178
  ctrl = e.ControlDown()
173
179
  alt = e.AltDown()
174
180
  shift= e.ShiftDown()
175
181
 
176
182
  if unicodekey in egal_code:
177
- if not shift :
183
+ if not shift :
178
184
  self.evaluate()
179
185
  return
180
186
 
@@ -186,4 +192,3 @@ class Calculator(wx.Frame):
186
192
  elif key == '<': self.command =self._last_command
187
193
  elif key == '=': self.evaluate()
188
194
  else : self._disp.Value += key
189
-
wolfhece/wolf_array.py CHANGED
@@ -2503,6 +2503,8 @@ class Ops_Array(wx.Frame):
2503
2503
  logging.warning(_('Please add points to vector or select another !'))
2504
2504
  return
2505
2505
 
2506
+ logging.info(_('Select nodes inside the active polygon/vector...'))
2507
+
2506
2508
  self._select_vector_inside_manager(self.active_vector)
2507
2509
  self.refresh_array()
2508
2510
 
@@ -2528,9 +2530,11 @@ class Ops_Array(wx.Frame):
2528
2530
  """ Select nodes along the active zone (manager) """
2529
2531
 
2530
2532
  if self.active_zone is None:
2531
- wx.MessageBox('Please select an active zone !')
2533
+ logging.warning(_('Please activate a zone !'))
2532
2534
  return
2533
2535
 
2536
+ logging.info(_('Select nodes along the active zone - all polylines...'))
2537
+
2534
2538
  for curvec in self.active_zone.myvectors:
2535
2539
  self._select_vector_under_manager(curvec)
2536
2540
 
@@ -2539,9 +2543,11 @@ class Ops_Array(wx.Frame):
2539
2543
  def select_vector_under_manager(self):
2540
2544
  """ Select nodes along the active vector (manager) """
2541
2545
  if self.active_vector is None:
2542
- wx.MessageBox('Please select an active vector !')
2546
+ logging.warning(_('Please activate a vector !'))
2543
2547
  return
2544
2548
 
2549
+ logging.info(_('Select nodes along the active polyline/vector...'))
2550
+
2545
2551
  self._select_vector_under_manager(self.active_vector)
2546
2552
  self.refresh_array()
2547
2553
 
@@ -2567,6 +2573,7 @@ class Ops_Array(wx.Frame):
2567
2573
  """ Select nodes inside the temporary vector """
2568
2574
 
2569
2575
  if self.mapviewer is not None:
2576
+ logging.info(_('Select nodes inside a temporary polygon/vector...'))
2570
2577
  logging.info(_('Please add points to vector by clicks !'))
2571
2578
 
2572
2579
  self.mapviewer.start_action('select by tmp vector inside', _('Please draw a polygon...'))
@@ -2581,9 +2588,9 @@ class Ops_Array(wx.Frame):
2581
2588
  def select_vector_under_tmp(self):
2582
2589
  """ Select nodes along the temporary vector """
2583
2590
  if self.mapviewer is not None:
2591
+ logging.info(_('Select nodes along a temporary polygon/vector...'))
2584
2592
  logging.info(_('Please add points to vector by clicks !'))
2585
2593
 
2586
-
2587
2594
  self.mapviewer.start_action('select by tmp vector along', _('Please draw a polyline...'))
2588
2595
  self.vectmp.reset()
2589
2596
  self.Active_vector(self.vectmp)
@@ -3272,6 +3279,10 @@ class SelectionData():
3272
3279
  myvect.find_minmax()
3273
3280
  mypoints = self.parent.get_ij_under_polyline(myvect)
3274
3281
 
3282
+ if len(mypoints) == 0:
3283
+ logging.info(_('No nodes under the polyline'))
3284
+ return
3285
+
3275
3286
  self._add_nodes_to_selectionij(mypoints, verif=nbini != 0)
3276
3287
 
3277
3288
  if self.parent.myops is not None:
@@ -6784,6 +6795,9 @@ class WolfArray(Element_To_Draw, header_wolf):
6784
6795
 
6785
6796
  allij = np.unique(allij, axis=0)
6786
6797
 
6798
+ # filter negative indexes
6799
+ allij = allij[np.where((allij[:, 0] >= 0) & (allij[:, 1] >= 0) & (allij[:, 0] < self.nbx) & (allij[:, 1] < self.nby))]
6800
+
6787
6801
  if usemask:
6788
6802
  mymask = np.logical_not(self.array.mask[allij[:, 0], allij[:, 1]])
6789
6803
  allij = allij[np.where(mymask)]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wolfhece
3
- Version: 2.1.66
3
+ Version: 2.1.67
4
4
  Author-email: Pierre Archambeau <pierre.archambeau@uliege.be>
5
5
  License: Copyright (c) 2024 University of Liege. All rights reserved.
6
6
  Project-URL: Homepage, https://uee.uliege.be/hece
@@ -7,7 +7,7 @@ wolfhece/ManageParams.py,sha256=EeuUI5Vvh9ixCvYf8YShMC1s1Yacc7OxOCN7q81gqiQ,517
7
7
  wolfhece/Model1D.py,sha256=uL1DJVmDI2xVSE7H6n3icn3QbsPtTHeg8E-6wkDloKw,476914
8
8
  wolfhece/PyConfig.py,sha256=FB8u0belXOXTb03Ln6RdVWvMgjzi3oGPCmw2dWa3lNg,8332
9
9
  wolfhece/PyCrosssections.py,sha256=FnmM9DWY_SAF2EDH9Gu2PojXNtSTRF4-aYQuAAJXBh4,112771
10
- wolfhece/PyDraw.py,sha256=pvvPOhMs1JxyYzEBPwBm7w5oP-0smiZly0pU4mv7LJY,409909
10
+ wolfhece/PyDraw.py,sha256=yHbr9KolS2j0uL9wbzV6McwXvZHVeSSZ64y6-wJot5s,411135
11
11
  wolfhece/PyGui.py,sha256=oBIBpgBQRR_XXucKE5-RFrtqKj0DRg9VlUCRo8Mzalc,105009
12
12
  wolfhece/PyGuiHydrology.py,sha256=f60E8K9eGTnRq5RDF6yvt-ahf2AYegwQ9t25zZ2Mk1A,14946
13
13
  wolfhece/PyHydrographs.py,sha256=jwtSNMMACwarxrtN1UeQYth99UNrhwPx1IGgUwcooHA,3774
@@ -48,7 +48,7 @@ wolfhece/pywalous.py,sha256=yRaWJjKckXef1d9D5devP0yFHC9uc6kRV4G5x9PNq9k,18972
48
48
  wolfhece/rain_SPWMI.py,sha256=qCfcmF7LajloOaCwnTrrSMzyME03YyilmRUOqrPrv3U,13846
49
49
  wolfhece/textpillow.py,sha256=map7HsGYML_o5NHRdFg2s_TVQed_lDnpYNDv27MM0Vw,14130
50
50
  wolfhece/tools_mpl.py,sha256=gQ3Jg1iuZiecmMqa5Eli2ZLSkttu68VXL8YmMDBaEYU,564
51
- wolfhece/wolf_array.py,sha256=Zb93bxUx5JJ8Mq7jQWBMMRAJLsgSjeX5EIA31aJJ8LI,376066
51
+ wolfhece/wolf_array.py,sha256=QmAcZNRMdGwqXRO3MsRMREYW_3ZdJ41i9gg4WMtAbLM,376746
52
52
  wolfhece/wolf_hist.py,sha256=7jeVrgSkM3ErJO6SRMH_PGzfLjIdw8vTy87kesldggk,3582
53
53
  wolfhece/wolf_texture.py,sha256=DS5eobLxrq9ljyebYfpMSQPn8shkUAZZVfqrOKN_QUU,16951
54
54
  wolfhece/wolf_tiles.py,sha256=2Ho2I20rHRY81KXxjgLOYISdF4OkJ2d6omeY4shDoGI,10386
@@ -72,7 +72,7 @@ wolfhece/apps/check_install.py,sha256=Xoi_d8MzKzNAy2xqEpERdsqgRPu0hbBWukI0WkIYzD
72
72
  wolfhece/apps/curvedigitizer.py,sha256=Yps4bcayzbsz0AoVc_dkSk35dEhhn_esIBy1Ziefgmk,5334
73
73
  wolfhece/apps/isocurrent.py,sha256=dagmGR8ja9QQ1gwz_8fU-N052hIw-W0mWGVkzLu6C7I,4247
74
74
  wolfhece/apps/splashscreen.py,sha256=SrustmIQeXnsiD-92OzjdGhBi-S7c_j-cSvuX4T6rtg,2929
75
- wolfhece/apps/version.py,sha256=O8ZZomRXgXIg3ep7c52RJmvZUQl3rFlDBMhUIg4HaA4,388
75
+ wolfhece/apps/version.py,sha256=cRc1I581AOhBuOpRqqnB83bANUXPq9N2wF1OVKOBfno,388
76
76
  wolfhece/apps/wolf.py,sha256=j_CgvsL8rwixbVvVD5Z0s7m7cHZ86gmFLojKGuetMls,729
77
77
  wolfhece/apps/wolf2D.py,sha256=4z_OPQ3IgaLtjexjMKX9ppvqEYyjFLt1hcfFABy3-jU,703
78
78
  wolfhece/apps/wolf_logo.bmp,sha256=ruJ4MA51CpGO_AYUp_dB4SWKHelvhOvd7Q8NrVOjDJk,3126
@@ -126,7 +126,7 @@ wolfhece/hydrology/read.py,sha256=itMat6MMn4Y14C3SMU_9JMBtpXFjG4mLNMfXXd5U6Ns,93
126
126
  wolfhece/hydrology/slope_manager.py,sha256=vlek0z8qcqB61eleiksyOe3QR1vpbtwfeowy6ms7_Fg,5580
127
127
  wolfhece/hydrology/wolfMap_treatment.py,sha256=eAxr24zJGwmDof1aZpcxewVvv_bWDvoO8t9Wwf99Mlo,10606
128
128
  wolfhece/hydrometry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
129
- wolfhece/hydrometry/kiwis.py,sha256=KHRfYrtd5hwxKxdChbkTXYH-cDSDcaQJFTEgjrnVMg4,34929
129
+ wolfhece/hydrometry/kiwis.py,sha256=m3LGNxmB_ZY_ug-8BCM8jK_VqN6LtWRGpbPWtgRYFSE,46460
130
130
  wolfhece/hydrometry/kiwis_gui.py,sha256=lApsSeBMJNAR1yocggdoHwz_xe6M_oaZ_E13CfHAlQA,23124
131
131
  wolfhece/hydrometry/kiwis_wolfgui.py,sha256=GPa5YNp2V2ZlxYQjPiCXERgPuWB_zij4ec2yHpRvoFA,4027
132
132
  wolfhece/hydrometry/kiwispie.py,sha256=akOaV46WwzISVlCcPz_phjsBrI_rDACUzdELtjx-xNg,13498
@@ -213,7 +213,7 @@ wolfhece/mar/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
213
213
  wolfhece/mar/commontools.py,sha256=vCmoNI2sMOco6Y4KPpKb7WORq45qFU_lSxbKGV9oZ8A,53824
214
214
  wolfhece/mar/interface_MAR_WOLF.py,sha256=MWeXaHLDT4Eo9jZOAvz013lmpgGYT1v9VUYGAgBgSRU,21454
215
215
  wolfhece/math_parser/__init__.py,sha256=mrD_uFDDZzvyxQkY8ESqcy1bvM7e3__Gi2b_vijvoo8,27977
216
- wolfhece/math_parser/calculator.py,sha256=5VLYWkyvH7u3yMyQpzgc2uNyjgJHoS9HgLDyl6JqG38,6005
216
+ wolfhece/math_parser/calculator.py,sha256=VCXCT5zhyMSgkO5O8dwIhRht9NNBqA0h1QPliOD4N28,6046
217
217
  wolfhece/mesh2d/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
218
218
  wolfhece/mesh2d/bc_manager.py,sha256=QTGkb5TR8Y5xVnGUXPXzscGyTEQ6PA8CZPkVNwrlR1Y,53265
219
219
  wolfhece/mesh2d/cell_tracker.py,sha256=mPmnD5lEf3gLPuLqtAIo-Gp-ipAwQdPxzjWOGt0b7jM,8958
@@ -283,8 +283,8 @@ wolfhece/ui/wolf_multiselection_collapsiblepane.py,sha256=8PlMYrb_8jI8h9F0_EagpM
283
283
  wolfhece/ui/wolf_times_selection_comparison_models.py,sha256=ORy7fz4dcp691qKzaOZHrRLZ0uXNhL-LIHxmpDGL6BI,5007
284
284
  wolfhece/wintab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
285
285
  wolfhece/wintab/wintab.py,sha256=8A-JNONV6ujgsgG3lM5Uw-pVgglPATwKs86oBzzljoc,7179
286
- wolfhece-2.1.66.dist-info/METADATA,sha256=0sC8b4E0or7Irtp909AReOyaA-51BqdzyVnXFochOoo,2570
287
- wolfhece-2.1.66.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
288
- wolfhece-2.1.66.dist-info/entry_points.txt,sha256=Q5JuIWV4odeIJI3qc6fV9MwRoz0ezqPVlFC1Ppm_vdQ,395
289
- wolfhece-2.1.66.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
290
- wolfhece-2.1.66.dist-info/RECORD,,
286
+ wolfhece-2.1.67.dist-info/METADATA,sha256=77W5WHquObr8qkk2A97PzjeORUnqfXAh_0Vo-F0cAaw,2570
287
+ wolfhece-2.1.67.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
288
+ wolfhece-2.1.67.dist-info/entry_points.txt,sha256=Q5JuIWV4odeIJI3qc6fV9MwRoz0ezqPVlFC1Ppm_vdQ,395
289
+ wolfhece-2.1.67.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
290
+ wolfhece-2.1.67.dist-info/RECORD,,