wolfhece 2.1.75__py3-none-any.whl → 2.1.76__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
@@ -145,14 +145,14 @@ class Colors_1to9(wx.Frame):
145
145
  def __init__(self, parent):
146
146
 
147
147
  self._parent = parent
148
- self.colors1to9 = [(0, 0, 255, 255),
149
- (0, 255, 0, 255),
150
- (0, 128, 255, 255),
151
- (255, 255, 0, 255),
152
- (255, 165, 0, 255),
153
- (128, 0, 128, 255),
154
- (255, 192, 203, 255),
155
- (165, 42, 42, 255),
148
+ self.colors1to9 = [(0, 0, 255, 255),
149
+ (0, 255, 0, 255),
150
+ (0, 128, 255, 255),
151
+ (255, 255, 0, 255),
152
+ (255, 165, 0, 255),
153
+ (128, 0, 128, 255),
154
+ (255, 192, 203, 255),
155
+ (165, 42, 42, 255),
156
156
  (128, 128, 128, 255)]
157
157
 
158
158
  if self.file.exists():
@@ -214,7 +214,7 @@ class Colors_1to9(wx.Frame):
214
214
  self.Bind(wx.EVT_BUTTON, self.OnSave, cmdSave)
215
215
 
216
216
  self.Show()
217
-
217
+
218
218
  def Apply(self):
219
219
 
220
220
  for i in range(9):
@@ -228,7 +228,7 @@ class Colors_1to9(wx.Frame):
228
228
 
229
229
  def OnCancel(self, event):
230
230
  self.Close()
231
-
231
+
232
232
  def OnSetDefault(self, event):
233
233
  self.colors1to9 = [(0, 0, 255, 255),
234
234
  (0, 255, 0, 255),
@@ -1036,6 +1036,7 @@ class WolfMapViewer(wx.Frame):
1036
1036
  updatecolors_laz = self.menulaz.Append(wx.ID_ANY, _('Change colors - Classification'), _('Change color map associated to the current classification'),)
1037
1037
  fillarray_laz = self.menulaz.Append(wx.ID_ANY, _('Fill active array from LAZ data'), _('Fill an array from the LAZ data'),)
1038
1038
  selectarray_laz = self.menulaz.Append(wx.ID_ANY, _('Select cells in array from LAZ data'), _('Select nodes in active array from the LAZ data'),)
1039
+ countarray_laz = self.menulaz.Append(wx.ID_ANY, _('Count LAZ data in cells'), _('Count the number of LAZ data in each cell of the matrix'),)
1039
1040
 
1040
1041
  def menu_wolf2d(self):
1041
1042
 
@@ -2749,7 +2750,7 @@ class WolfMapViewer(wx.Frame):
2749
2750
  self.canvas.Bind(wx.EVT_MOUSEWHEEL, self.OnButton)
2750
2751
 
2751
2752
  self.treelist.Bind(dataview.EVT_TREELIST_ITEM_CHECKED, self.OnCheckItem)
2752
- self.treelist.Bind(dataview.EVT_TREELIST_ITEM_ACTIVATED, self.OnActivateTreeElem)
2753
+ self.treelist.Bind(dataview.EVT_TREELIST_ITEM_ACTIVATED, self.OnActivateTreeElem)
2753
2754
  self.treelist.Bind(dataview.EVT_TREELIST_ITEM_CONTEXT_MENU, self.OntreeRight)
2754
2755
  self.treelist.Bind(wx.EVT_CHAR_HOOK, self.OnHotKey)
2755
2756
  self.treelist.Bind(dataview.EVT_TREELIST_SELECTION_CHANGED,self.OnSelectItem)
@@ -4256,6 +4257,126 @@ class WolfMapViewer(wx.Frame):
4256
4257
 
4257
4258
  logging.info(_('Filling done'))
4258
4259
 
4260
+ def count_active_array_from_laz(self, array:WolfArray = None, used_codes:list = [], chunk_size:float = 500.):
4261
+ """ Fill active array with laz data
4262
+
4263
+ :param array: array to fill
4264
+ :param used_codes: codes to use
4265
+ :param operator: operator to use
4266
+ """
4267
+
4268
+ if self.mylazgrid is None:
4269
+ return
4270
+
4271
+ if array is None:
4272
+ logging.error(_('No array'))
4273
+ return
4274
+
4275
+ if len(used_codes) == 0 :
4276
+ keycode = [key for key,val in self.mylazgrid.colors.classification.items()]
4277
+ names = [val[0] for key,val in self.mylazgrid.colors.classification.items()]
4278
+
4279
+ with wx.MultiChoiceDialog(None, _('Choose the codes to use'), _('Codes'), names) as dlg:
4280
+ if dlg.ShowModal() == wx.ID_OK:
4281
+ data = {}
4282
+ used_codes = dlg.GetSelections()
4283
+ used_codes = [float(keycode[cur]) for cur in used_codes]
4284
+ else:
4285
+ return
4286
+
4287
+ bounds = array.get_bounds()
4288
+
4289
+ # align bounds on chunk_size
4290
+ bounds[0][0] = bounds[0][0] - bounds[0][0] % chunk_size
4291
+ bounds[0][1] = bounds[0][1] + chunk_size - bounds[0][1] % chunk_size
4292
+ bounds[1][0] = bounds[1][0] - bounds[1][0] % chunk_size
4293
+ bounds[1][1] = bounds[1][1] + chunk_size - bounds[1][1] % chunk_size
4294
+
4295
+ chunks_x = np.arange(bounds[0][0], bounds[0][1], chunk_size)
4296
+ chunks_y = np.arange(bounds[1][0], bounds[1][1], chunk_size)
4297
+
4298
+ for curx in tqdm(chunks_x, 'Chunks'):
4299
+ for cury in chunks_y:
4300
+
4301
+ curbounds = [[curx, curx + chunk_size], [cury, cury + chunk_size]]
4302
+
4303
+ logging.info(_('Scan {}-{} {}-{}').format(curbounds[0][0],curbounds[0][1],curbounds[1][0],curbounds[1][1]))
4304
+ self.mylazdata = self.mylazgrid.scan(curbounds)
4305
+
4306
+ if len(self.mylazdata) == 0:
4307
+ continue
4308
+
4309
+ # Test codes
4310
+ data = {}
4311
+ for curcode in used_codes:
4312
+ data[curcode] = self.mylazdata[self.mylazdata[:, 3] == curcode]
4313
+
4314
+ # Treat data for each code
4315
+ for curdata in data.values():
4316
+
4317
+ if curdata.shape[0] == 0:
4318
+ continue
4319
+ else:
4320
+ logging.info(_('Code {} : {} points'.format(curdata[0,3], curdata.shape[0])))
4321
+
4322
+ # get i,j from x,y
4323
+ i,j = array.get_ij_from_xy(curdata[:, 0], curdata[:, 1]) #= np.float32(self.mylazdata[:, 2])
4324
+
4325
+ # keep only valid points -- inside the array
4326
+ used = np.where((i >=0) & (i < array.nbx) & (j >=0) & (j < array.nby))[0]
4327
+
4328
+ if len(used) == 0:
4329
+ continue
4330
+
4331
+ i = i[used]
4332
+ j = j[used]
4333
+ z = curdata[used, 2]
4334
+
4335
+ # create a key array
4336
+ keys = np.vstack((i,j)).T
4337
+ # find unique keys
4338
+ keys = np.unique(keys, axis=0)
4339
+
4340
+ # create a ijz array
4341
+ ijz = np.vstack((i, j, z)).T
4342
+
4343
+ # sort ijz array according to keys
4344
+ #
4345
+ # the most important indice is the last one enumerated in lexsort
4346
+ # see : https://numpy.org/doc/stable/reference/generated/numpy.lexsort.html
4347
+ ijz = ijz[np.lexsort((ijz[:,1], ijz[:,0]))]
4348
+
4349
+ # find first element of each key
4350
+ idx = np.where(np.abs(np.diff(ijz[:,0])) + np.abs(np.diff(ijz[:,1])) != 0)[0]
4351
+
4352
+ # add last element
4353
+ idx = np.concatenate((idx, [ijz.shape[0]]))
4354
+
4355
+ assert len(idx) == keys.shape[0], 'Error in filling'
4356
+
4357
+ logging.info(_('Cells to fill : {}'.format(len(idx))))
4358
+
4359
+ # apply operator
4360
+ vals = {}
4361
+ start_ii = 0
4362
+ for ii, key in enumerate(keys):
4363
+ end_ii = idx[ii]+1
4364
+
4365
+ vals[(key[0], key[1])] = end_ii - start_ii
4366
+
4367
+ start_ii = end_ii
4368
+
4369
+ if len(vals) > 0:
4370
+ # create a new ijz array
4371
+ newijz = np.asarray([[key[0], key[1], val] for key, val in vals.items()], dtype = np.float32)
4372
+
4373
+ array.fillin_from_ijz(newijz)
4374
+
4375
+ array.reset_plot()
4376
+ self.Paint()
4377
+
4378
+ logging.info(_('Counting done'))
4379
+
4259
4380
  def init_laz_from_numpy(self, fn=None):
4260
4381
  """ Read LAZ data stored in numpy array"""
4261
4382
 
@@ -5143,6 +5264,17 @@ class WolfMapViewer(wx.Frame):
5143
5264
  autoscale = False
5144
5265
  self.fill_active_array_from_laz(self.active_array)
5145
5266
 
5267
+ elif itemlabel == _('Count LAZ data in cells'):
5268
+ if self.mylazgrid is None:
5269
+ logging.warning('')
5270
+ return
5271
+ if self.active_array is None:
5272
+ logging.warning(_('No active array -- select an array first and retry!'))
5273
+ return
5274
+
5275
+ autoscale = False
5276
+ self.count_active_array_from_laz(self.active_array)
5277
+
5146
5278
  elif itemlabel == _('Select cells in array from LAZ data'):
5147
5279
  if self.mylazgrid is None:
5148
5280
  logging.warning('')
@@ -7032,7 +7164,7 @@ class WolfMapViewer(wx.Frame):
7032
7164
  self.selected_object.save()
7033
7165
  elif text==_('Up'):
7034
7166
  self.upobj()
7035
-
7167
+
7036
7168
  elif text == _('Down'):
7037
7169
  self.downobj()
7038
7170
 
@@ -7056,7 +7188,7 @@ class WolfMapViewer(wx.Frame):
7056
7188
 
7057
7189
  if self.get_label_selecteditem() == _("Active : ") + label:
7058
7190
  self.set_label_selecteditem(_("Active : ") + newlab)
7059
-
7191
+
7060
7192
  dlg.Destroy()
7061
7193
 
7062
7194
  elif text == _('Duplicate'):
@@ -7071,7 +7203,7 @@ class WolfMapViewer(wx.Frame):
7071
7203
  if ret != wx.ID_OK:
7072
7204
  dlg.Destroy()
7073
7205
  return
7074
-
7206
+
7075
7207
  newlab = dlg.GetValue()
7076
7208
  dlg.Destroy()
7077
7209
 
@@ -8344,7 +8476,7 @@ class WolfMapViewer(wx.Frame):
8344
8476
  # self.mytooltip.SetIcon(self.GetIcon()) # update icon
8345
8477
  self.mytooltip.SetWindowStyle(wx.DEFAULT_FRAME_STYLE) # | wx.STAY_ON_TOP) # on top, with Title bar
8346
8478
 
8347
- # self.mytooltip.Show(True)
8479
+ self.mytooltip.Show(True)
8348
8480
 
8349
8481
  def Autoscale(self, update_backfore=True):
8350
8482
  """ Redimensionnement de la fenêtre pour afficher tous les objets """
@@ -8803,10 +8935,12 @@ class WolfMapViewer(wx.Frame):
8803
8935
 
8804
8936
  elif key == 60 and shiftdown: #'>'
8805
8937
  if self.active_array is not None:
8806
- self.active_array.dilate_contour_selection(1)
8938
+ if self.active_array.SelectionData is not None:
8939
+ self.active_array.SelectionData.dilate_contour_selection(1)
8807
8940
  elif key == 60 and not shiftdown: #'<'
8808
8941
  if self.active_array is not None:
8809
- self.active_array.erode_contour_selection()
8942
+ if self.active_array.SelectionData is not None:
8943
+ self.active_array.SelectionData.erode_contour_selection()
8810
8944
 
8811
8945
  elif key == wx.WXK_F2 and shiftdown:
8812
8946
 
@@ -9076,10 +9210,12 @@ class WolfMapViewer(wx.Frame):
9076
9210
 
9077
9211
  elif key == 60 and shiftdown: #'>'
9078
9212
  if self.active_array is not None:
9079
- self.active_array.dilate_selection(1)
9213
+ if self.active_array.SelectionData is not None:
9214
+ self.active_array.SelectionData.dilate_selection(1)
9080
9215
  elif key == 60 and not shiftdown: #'<'
9081
9216
  if self.active_array is not None:
9082
- self.active_array.erode_selection(1)
9217
+ if self.active_array.SelectionData is not None:
9218
+ self.active_array.SelectionData.erode_selection(1)
9083
9219
 
9084
9220
  elif key == wx.WXK_ESCAPE:
9085
9221
 
@@ -9145,16 +9281,16 @@ class WolfMapViewer(wx.Frame):
9145
9281
  logging.info(_('Please select some nodes before transfering to the dictionary, not ALL !'))
9146
9282
  return
9147
9283
 
9148
- # colors = [(0, 0, 255, 255),
9149
- # (0, 255, 0, 255),
9150
- # (0, 128, 255, 255),
9151
- # (255, 255, 0, 255),
9152
- # (255, 165, 0, 255),
9153
- # (128, 0, 128, 255),
9154
- # (255, 192, 203, 255),
9155
- # (165, 42, 42, 255),
9284
+ # colors = [(0, 0, 255, 255),
9285
+ # (0, 255, 0, 255),
9286
+ # (0, 128, 255, 255),
9287
+ # (255, 255, 0, 255),
9288
+ # (255, 165, 0, 255),
9289
+ # (128, 0, 128, 255),
9290
+ # (255, 192, 203, 255),
9291
+ # (165, 42, 42, 255),
9156
9292
  # (128, 128, 128, 255)]
9157
-
9293
+
9158
9294
  idx = LIST_1TO9.index(key)
9159
9295
  if idx > 8:
9160
9296
  idx -= 9
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 = 75
8
+ self.patch = 76
9
9
 
10
10
  def __str__(self):
11
11
 
@@ -58,9 +58,102 @@ KIWIS WebServices command :
58
58
  """
59
59
 
60
60
  URL_SERVICE = 'https://hydrometrie.wallonie.be/services'
61
+ URL_SERVICE_WATERINFO = 'https://download.waterinfo.be/tsmdownload'
62
+ URL_SERVICE_HICWS = 'https://hicws.vlaanderen.be'
63
+
61
64
  URL_SPW = URL_SERVICE + '/KiWIS/KiWIS'
65
+ URL_WATERINFO = URL_SERVICE_WATERINFO + '/KiWIS/KiWIS'
66
+ URL_HICWS = URL_SERVICE_HICWS + '/KiWIS/KiWIS'
67
+
62
68
  URL_TOKEN = URL_SERVICE + '/auth/token/'
63
69
 
70
+ # See : https://hicws.vlaanderen.be/Manual_for_the_use_of_webservices_HIC.pdf
71
+ class HICWS_GroupID(Enum):
72
+ FlowRate_daily = ('Afvoer_dag', 156169)
73
+ FlowRate_hig_res = ('Afvoer_hoge resolutie', 156170)
74
+ FlowRate_hourly = ('Afvoer_uur', 156171)
75
+ Astronomic_predictions_Scheldt_and_coastal_area = ('Astronomische voorspellingen reeksen Schelde en kust (LAT)', 512458)
76
+ Astronomic_predictions_Scheldt_and_coastal_area_high_res = ('AstroAstronomische voorspellingen reeksen Schelde en kust (mTAW)', 354718)
77
+ Astronomic_predictions_Scheldt_and_coastal_area_high_low = ('Astronomische voorspellingen Hoog-en laagwaters Schelde en kust (LAT)', 515316)
78
+ Astronomic_predictions_Scheldt_and_coastal_area_high_low_highres = ('Astronomische voorspellingen Hoog-en laagwaters Schelde en kust (mTAW)', 350099)
79
+ Calculated_Discharge_important = ('Berekende afvoeren sleutellocaties waterwegen', 260592)
80
+ Calculated_Area_Precipitation = ('Berekende gebiedsneerslagen belangrijke meetlocaties HIC', 156159)
81
+ Chlorophyl_high_res = ('Chlorofyl_hoge resolutie', 156172)
82
+ Conductivity_high_res = ('Conductiviteit_hoge resolutie', 156173)
83
+ Precipitation_daily = ('Neerslag_dag', 156166)
84
+ Precipitation_high_res = ('Neerslag_hoge resolutie', 156167)
85
+ Precipitation_yearly = ('Neerslag_jaar', 156191)
86
+ Precipitation_monthly = ('Neerslag_maand', 156190)
87
+ Precipitation_hourly = ('Neerslag_uur', 156168)
88
+ Salinity_high_res = ('Saliniteit_hoge resolutie', 421208)
89
+ Sediment_Concentration = ('Sedimentconcentratie_hoge resolutie', 156188)
90
+ Flow_Direction_high_res = ('Stroomrichting_hoge resolutie', 156158)
91
+ Flow_Velocity = ('Stroomsnelheid_hoge resolutie', 156199)
92
+ Turbidity = ('Turbiditeit_hoge resolutie', 156202)
93
+ Tidal_Previsions_Scheldt_ensemble = ('Verwachtingen Tijgebied Schelde (HWLW)', 432821)
94
+ Forecast_Discharge_shortterm_48h = ('Voorspellingen afvoer korte termijn (48u)', 506057)
95
+ Forecast_Discharge_longterm_10d = ('Voorspellingen afvoer lange termijn (10 dagen)', 506059)
96
+ Forecast_area_48h = ('Voorspellingen berekende gebiedsneerslagen belangrijke meetlocaties HIC korte termijn (48u)', 506060)
97
+ Forecast_area_10d = ('Voorspellingen berekende gebiedsneerslagen belangrijke meetlocaties HIC lange termijn (10 dagen)', 506061)
98
+ Forecast_waterlevel_48h = ('Voorspellingen waterstand korte termijn (48u)', 506056)
99
+ Forecast_waterlevel_10d = ('Voorspellingen waterstand lange termijn (10 dagen)', 506058)
100
+ Water_Level_daily = ('Waterstand_dag', 156162)
101
+ Water_Level_high_res = ('Waterstand_hoge resolutie', 156163)
102
+ High_Low_water_Scheldt = ('Waterstand_Hoog-en laagwaters tijgebied Schelde', 156165)
103
+ Scheldt_High_Water = ('Waterstand_Hoogwaters tijgebied', 510205)
104
+ Scheldt_Low_Water = ('Waterstand_Laagwaters tijgebied', 510207)
105
+ Water_Level_hourly = ('Waterstand_uur', 156164)
106
+ Water_Temperature = ('Watertemperatuur_hoge resolutie', 156200)
107
+ Oxygen_Concentration = ('Zuurstofgehalte_hoge resolutie', 156207)
108
+ Oxygen_Saturation = ('Zuurstofverzadiging_hoge resolutie', 156208)
109
+ pH = ('Zuurtegraad_hoge resolutie', 156197)
110
+
111
+ #See : https://waterinfo.vlaanderen.be/download/9f5ee0c9-dafa-46de-958b-7cac46eb8c23?dl=0
112
+ class WaterInfo_GroupdID(Enum):
113
+ Flowrate_15m = ('Afvoer_15m', 192786)
114
+ Flowrate_daily = ('Afvoer_dag', 192893)
115
+ Flowrate_yearly = ('Afvoer_jaar', 192895)
116
+ Flowrate_monthly = ('Afvoer_maand', 192894)
117
+ Flowrate_hourly = ('Afvoer_uur', 192892)
118
+ Ground_Saturation = ('Bodemverzadiging_15m', 192929)
119
+ Ground_Humidity = ('Bodemvocht_15m', 192928)
120
+ Dew_Point_Temparature = ('Dauwpunttemperatuur_15m', 192923)
121
+ Salinity = ('EC verziltingsmeetnet', 383065)
122
+ projectmetingen = ('EC projectmetingen', 381863)
123
+ Ground_Temperature = ('Grondtemperatuur_15m', 192924)
124
+ Ground_Heat = ('Grondwarmte_15m', 192916)
125
+ Radiation = ('Instraling_15m', 192920)
126
+ Atmospheric_Pressure = ('Luchtdruk_15m', 192918)
127
+ Atmospheric_Temperature = ('Luchttemperatuur175cm_15m', 192922)
128
+ Rain_15m = ('Neerslag_15m', 192896)
129
+ Rain_1m = ('Neerslag_1m', 199792)
130
+ Rain_daily = ('Neerslag_dag', 192898)
131
+ Rain_yearly = ('Neerslag_jaar', 192900)
132
+ Rain_monthly = ('Neerslag_maand', 192899)
133
+ Rain_hourly = ('Neerslag_uur', 192897)
134
+ Relative_Humidity = ('RelatVocht_15m', 192919)
135
+ Evaporation_Monteih_15m = ('VerdampingMonteith_15m', 192927)
136
+ Evaporation_Monteih_daily = ('VerdampingMonteith_dag', 295480)
137
+ Evaporation_Monteih_yearly = ('VerdampingMonteith_jaar', 295483)
138
+ Evaporation_Monteih_monthly = ('VerdampingMonteith_maand', 295482)
139
+ Evaporation_Penman_15m = ('VerdampingPenman_15m', 204341)
140
+ Evaporation_Penman_daily = ('VerdampingPenman_dag', 295474)
141
+ Evaporation_Penman_yearly = ('VerdampingPenman_jaar', 295479)
142
+ Evaporation_Penman_monthly = ('VerdampingPenman_maand', 295475)
143
+ Water_speed_15m = ('Watersnelheid_15m', 192901)
144
+ Water_speed_daily = ('Watersnelheid_dag', 192903)
145
+ Water_speed_yearly = ('Watersnelheid_jaar', 192905)
146
+ Water_speed_monthly = ('Watersnelheid_maand', 192904)
147
+ Water_speed_hourly = ('Watersnelheid_uur', 192902)
148
+ Water_Level_15m = ('Waterstand_15m', 192780)
149
+ Water_Level_daily = ('Waterstand_dag', 192782)
150
+ Water_Level_yearly = ('Waterstand_jaar', 192784)
151
+ Water_Level_monthly = ('Waterstand_maand', 192783)
152
+ Water_Level_hourly = ('Waterstand_uur', 192785)
153
+ Water_Temperature = ('Watertemperatuur_15m', 325066)
154
+ Wind_Direction = ('Windrichting_15m', 192926)
155
+ Wind_Speed = ('Windsnelheid_15m', 192925)
156
+
64
157
  class kiwis_command(Enum):
65
158
  getrequestinfo = "getrequestinfo"
66
159
  getGroupList = "getGroupList"
@@ -234,8 +327,8 @@ class hydrometry():
234
327
 
235
328
  try:
236
329
  self.daily_token()
237
- except:
238
- logging.warning('No token available')
330
+ except Exception as e:
331
+ logging.warning('No token available or Error in hydrometry init :', e)
239
332
 
240
333
  try:
241
334
  self.get_requests()
@@ -243,7 +336,8 @@ class hydrometry():
243
336
  self.get_stations()
244
337
  self.get_groups()
245
338
  self.save_struct(self.dir)
246
- except:
339
+ except Exception as e:
340
+ print('Error in hydrometry init :', e)
247
341
  self.realstations = None
248
342
  pass
249
343
 
@@ -253,10 +347,16 @@ class hydrometry():
253
347
  ret+=curcol+'\n'
254
348
  return ret
255
349
 
256
- def _get_commandstr(self, which:str):
350
+ def _get_commandstr(self, which:str, format='json'):
257
351
  """ Construction de la commande à envoyer au serveur KIWIS """
258
352
 
259
- return self.url+'?request='+which.value+'&format=json'
353
+ datasource = ''
354
+ if self.url == URL_WATERINFO:
355
+ datasource = '&datasource=1'
356
+ elif self.url == URL_HICWS:
357
+ datasource = '&datasource=4'
358
+
359
+ return self.url+'?request='+which.value+'&format='+format + datasource
260
360
 
261
361
  def daily_token(self):
262
362
  """
@@ -293,7 +393,11 @@ class hydrometry():
293
393
  return
294
394
  self.token = None
295
395
 
296
- self._header = {'Authorization': 'Bearer {}'.format(self.token['access_token'])}
396
+ try:
397
+ self._header = {'Authorization': 'Bearer {}'.format(self.token['access_token'])}
398
+ except Exception as e:
399
+ logging.error('Error in daily_token :', e)
400
+ self._header = None
297
401
 
298
402
  def check_plot(self):
299
403
  """ Instance is checked in mapviewer """
@@ -303,6 +407,10 @@ class hydrometry():
303
407
  """ Instance is unchecked in mapviewer """
304
408
  self.plotted = False
305
409
 
410
+ def get_path(self, dir:Path, filename:str):
411
+ """ Get path of instance """
412
+ return Path(dir) / (self.url.replace('/','_').replace('https:','') + filename)
413
+
306
414
  def save_struct(self, dir=''):
307
415
  """Sauvegarde des structures dans un répertoire
308
416
 
@@ -315,12 +423,12 @@ class hydrometry():
315
423
  dir = Path(dir)
316
424
  dir.mkdir(parents=True, exist_ok=True)
317
425
 
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')
426
+ self.sites.to_csv(self.get_path(dir, 'sites.csv'))
427
+ self.stations.to_csv(self.get_path(dir, 'stations.csv'))
428
+ self.groups.to_csv(self.get_path(dir, 'groups.csv'))
429
+ self.requests.to_csv(self.get_path(dir, 'requests.csv'))
322
430
 
323
- def _get_stations_pythonlist(self, site_no:str|int, onlyreal:bool= True):
431
+ def _get_stations_pythonlist(self, site_no:str|int, onlyreal:bool= True, return_only_name:bool=False):
324
432
  """ Obtention des stations pour le site en liste python
325
433
 
326
434
  :param site_no: numéro du site
@@ -332,10 +440,14 @@ class hydrometry():
332
440
  else:
333
441
  stations = self.stations[self.stations[kiwis_site_fields.site_no.value]==site_no]
334
442
 
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)]
443
+ if return_only_name:
444
+ return [curname for curname in stations[station_fields.STATION_NAME.value].values]
337
445
 
338
- return list_name_code, list_code_name
446
+ else:
447
+ list_name_code = [curname+' --- '+curno for curname,curno in zip(stations[station_fields.STATION_NAME.value].values,stations[station_fields.STATION_NO.value].values)]
448
+ list_code_name = [curno +' --- '+curname for curname,curno in zip(stations[station_fields.STATION_NAME.value].values,stations[station_fields.STATION_NO.value].values)]
449
+
450
+ return list_name_code, list_code_name
339
451
 
340
452
  def _get_sites_pythonlist(self):
341
453
  """ Obtention des sites en liste python """
@@ -365,7 +477,7 @@ class hydrometry():
365
477
 
366
478
  returnfields = f'{kiwis_site_fields.site_no.value},'
367
479
  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},'
480
+ returnfields += f'{station_fields.STATION_LOCAL_X.value},{station_fields.STATION_LOCAL_Y.value},' if self.url==URL_SPW else ''
369
481
  returnfields += f'{station_fields.STATION_LATITUDE.value},{station_fields.STATION_LONGITUDE.value},'
370
482
  returnfields += f'{station_fields.RIVER_NAME.value},'
371
483
  returnfields += 'ca_sta'
@@ -377,25 +489,50 @@ class hydrometry():
377
489
  # returnfields += 'ts_id,ts_name,'
378
490
  # returnfields += 'ts_unitname,ts_unitsymbol,'
379
491
 
380
- if self.dir!='' and exists(join(self.dir,'stations.csv')):
381
- self.stations = pd.read_csv(join(self.dir,'stations.csv'),index_col=0)
492
+ if self.dir!='' and self.get_path(self.dir, 'stations.csv').exists():
493
+ self.stations = pd.read_csv(self.get_path(self.dir, 'stations.csv'),index_col=0)
382
494
  elif self.url!='':
383
- json_data = requests.get(self._get_commandstr(kiwis_command.getStationList) \
384
- +'&metadata=true' \
385
- +'&returnfields='+returnfields \
386
- +'&ca_sta_returnfields='+ca_sta_returnfields \
387
- +'&orderby=station_no', \
388
- verify=True, \
389
- headers=self._header).json()
495
+ try:
496
+ if self.url == URL_SPW:
497
+ json_data = requests.get(self._get_commandstr(kiwis_command.getStationList) \
498
+ +'&metadata=true' \
499
+ +'&returnfields='+returnfields \
500
+ +'&ca_sta_returnfields='+ca_sta_returnfields \
501
+ +'&orderby=station_no', \
502
+ verify=True, \
503
+ headers=self._header).json()
504
+ else:
505
+ json_data = requests.get(self._get_commandstr(kiwis_command.getStationList, 'json') \
506
+ +'&metadata=true' \
507
+ +'&returnfields='+returnfields \
508
+ +'&orderby=station_no', \
509
+ verify=True, \
510
+ headers=self._header)
511
+
512
+ json_data = json_data.text.replace('\x1a', ' ')
513
+ json_data = json.loads(json_data)
514
+
515
+ except Exception as e:
516
+ self.stations = None
517
+ return
518
+
390
519
  self.stations = pd.DataFrame(json_data[1:], columns = json_data[0])
391
520
 
392
521
  #Conversion en minuscules
393
522
  self.stations[station_fields.STATION_NAME.value]=self.stations[station_fields.STATION_NAME.value].str.lower()
394
523
 
395
- # real stations are those with coordinates and not null
396
- self.realstations = self.stations[(~pd.isnull(self.stations[station_fields.STATION_LOCAL_X.value])) & (self.stations[station_fields.STATION_LOCAL_X.value]!='')]
397
- # computed stations are those without coordinates or null
398
- self.compstations = self.stations[pd.isnull(self.stations[station_fields.STATION_LOCAL_X.value]) | self.stations[station_fields.STATION_LOCAL_X.value]!='']
524
+ # # In case of Waterinfo, get part of station_id
525
+ # if self.url == URL_WATERINFO:
526
+ # self.stations[station_fields.STATION_ID.value] = self.stations[station_fields.STATION_ID.value].str[2:]
527
+
528
+ if self.url == URL_SPW:
529
+ # real stations are those with coordinates and not null
530
+ self.realstations = self.stations[(~pd.isnull(self.stations[station_fields.STATION_LOCAL_X.value])) & (self.stations[station_fields.STATION_LOCAL_X.value]!='')]
531
+ # computed stations are those without coordinates or null
532
+ self.compstations = self.stations[pd.isnull(self.stations[station_fields.STATION_LOCAL_X.value]) | self.stations[station_fields.STATION_LOCAL_X.value]!='']
533
+ else:
534
+ self.realstations = self.stations
535
+ self.compstations = None
399
536
 
400
537
  def get_names_xy(self, site_no = None):
401
538
  """Obtention des noms et coordonnées des stations pour le site
@@ -572,13 +709,39 @@ class hydrometry():
572
709
 
573
710
  return stations
574
711
 
712
+ def get_timeseries_group_spw(self, rfw:Literal['rain','waterdepth','flowrate'], time:Literal['5min','5or10min','1h','1d','1m']):
713
+ """alias for get_timeseries_group"""
714
+
715
+ return self.get_timeseries_group(rfw, time)
716
+
717
+ def get_timeseries_group_winfo_hic(self, group:WaterInfo_GroupdID | HICWS_GroupID):
718
+ """Obtention des stations pour le groupe souhaité.
719
+
720
+ Temps retourné en UTC
721
+
722
+ :param group: type de groupe - see WaterInfo_GroupdID or HICWS_GroupID
723
+ """
724
+
725
+ if self.url!='':
726
+ stations=None
727
+ group_id = group.value[1]
728
+ returnFields = '&metadata=true&custattr_returnfields=dataprovider,dataowner&md_returnfields=custom_attributes,station_id,station_no,station_name,ts_id,ts_name,stationparameter_name,ts_unitsymbol,parametertype_name'
729
+ json_data = requests.get(self._get_commandstr(kiwis_command.getTimeseriesValueLayer) +
730
+ '&timeseriesgroup_id='+str(group_id)+
731
+ '&orderby=station_no'+
732
+ returnFields,
733
+ verify=True, headers=self._header).json()
734
+ stations = pd.DataFrame(json_data[1:], columns = json_data[0])
735
+
736
+ return stations
737
+
575
738
  def get_sites(self, forcerequest=False):
576
739
  """Obtention des sites pour le serveur courant
577
740
 
578
741
  :param forcerequest: force la requête même si les données de cache sont déjà présentes"""
579
742
 
580
- if self.dir!='' and exists(join(self.dir,'sites.csv')) and not forcerequest:
581
- self.sites = pd.read_csv(join(self.dir,'sites.csv'),index_col=0)
743
+ if self.dir!='' and self.get_path(self.dir, 'sites.csv').exists() and not forcerequest:
744
+ self.sites = pd.read_csv(self.get_path(self.dir, 'sites.csv'),index_col=0)
582
745
  elif self.url!='' or forcerequest:
583
746
  json_data = requests.get(self._get_commandstr(kiwis_command.getSiteList),verify=True, headers=self._header).json()
584
747
  self.sites = pd.DataFrame(json_data[1:], columns = json_data[0])
@@ -590,8 +753,8 @@ class hydrometry():
590
753
 
591
754
  :param forcerequest: force la requête même si les données de cache sont déjà présentes"""
592
755
 
593
- if self.dir!='' and exists(join(self.dir,'groups.csv')) and not forcerequest:
594
- self.groups = pd.read_csv(join(self.dir,'groups.csv'),index_col=0)
756
+ if self.dir!='' and self.get_path(self.dir, 'groups.csv').exists() and not forcerequest:
757
+ self.groups = pd.read_csv(self.get_path(self.dir, 'groups.csv'),index_col=0)
595
758
  elif self.url!='' or forcerequest:
596
759
  json_data = requests.get(self._get_commandstr(kiwis_command.getGroupList),verify=True, headers=self._header).json()
597
760
  self.groups = pd.DataFrame(json_data[1:], columns = json_data[0])
@@ -611,8 +774,8 @@ class hydrometry():
611
774
 
612
775
  :param forcerequest: force la requête même si les données de cache sont déjà présentes"""
613
776
 
614
- if self.dir!='' and exists(join(self.dir,'requests.csv')) and not forcerequest:
615
- self.requests = pd.read_csv(join(self.dir,'requests.csv'),index_col=0)
777
+ if self.dir!='' and self.get_path(self.dir, 'requests.csv').exists() and not forcerequest:
778
+ self.requests = pd.read_csv(self.get_path(self.dir, 'requests.csv'),index_col=0)
616
779
  elif self.url!='' or forcerequest:
617
780
  json_data = requests.get(self._get_commandstr(kiwis_command.getrequestinfo),verify=True, headers=self._header).json()
618
781
  self.requests = pd.DataFrame(json_data[0]['Requests'])
@@ -709,7 +872,8 @@ class hydrometry():
709
872
  filename = self._get_filename_list(stationname,stationcode)
710
873
  list.to_csv(dir / filename)
711
874
 
712
- def timeseries(self,stationname:str='', stationcode:str='', dir:str='',
875
+ def timeseries(self, stationname:str='', stationcode:str='', stationid:str='',
876
+ dir:str='',
713
877
  fromdate=datetime.now()-timedelta(60), todate=datetime.now(),
714
878
  ts_name:str='', ts_id:str='', interval:int=3600, timezone:str = 'GMT+0'):
715
879
  """
@@ -738,11 +902,14 @@ class hydrometry():
738
902
  cursec = interval
739
903
  # id = ''
740
904
  if ts_id == '':
741
- if stationname=='':
742
- stationname = self.get_stationname(stationcode)
743
- if stationcode=='':
744
- stationcode = self.get_stationcode(stationname)
745
- id = self.get_stationid(stationname,stationcode)
905
+ if str(stationid) !='':
906
+ id = stationid
907
+ else:
908
+ if stationname=='':
909
+ stationname = self.get_stationname(stationcode)
910
+ if stationcode=='':
911
+ stationcode = self.get_stationcode(stationname)
912
+ id = self.get_stationid(stationname,stationcode)
746
913
 
747
914
  if dir=='':
748
915
  json_data = requests.get(self._get_commandstr(kiwis_command.getTimeseriesList)
@@ -190,7 +190,7 @@ class hydrometry_gui(wx.Frame):
190
190
  self.tenyears.Bind(wx.EVT_BUTTON, self.setdate)
191
191
 
192
192
 
193
- self.hydro = hydrometry(credential=credential, dir=kw.get('dir',''))
193
+ self.hydro = hydrometry(credential=credential, dir=kw.get('dir',''), url=kw.get('url',''))
194
194
 
195
195
  self.figsaxes=[]
196
196
 
wolfhece/wolf_array.py CHANGED
@@ -1410,7 +1410,42 @@ class CropDialog(wx.Dialog):
1410
1410
 
1411
1411
  return myhead
1412
1412
 
1413
-
1413
+ import string
1414
+ class IntValidator(wx.Validator):
1415
+ ''' Validates data as it is entered into the text controls. '''
1416
+
1417
+ #----------------------------------------------------------------------
1418
+ def __init__(self):
1419
+ super(IntValidator, self).__init__()
1420
+ self.Bind(wx.EVT_CHAR, self.OnChar)
1421
+
1422
+ #----------------------------------------------------------------------
1423
+ def Clone(self):
1424
+ '''Required Validator method'''
1425
+ return IntValidator()
1426
+
1427
+ #----------------------------------------------------------------------
1428
+ def Validate(self, win):
1429
+ return True
1430
+
1431
+ #----------------------------------------------------------------------
1432
+ def TransferToWindow(self):
1433
+ return True
1434
+
1435
+ #----------------------------------------------------------------------
1436
+ def TransferFromWindow(self):
1437
+ return True
1438
+
1439
+ #----------------------------------------------------------------------
1440
+ def OnChar(self, event):
1441
+ keycode = int(event.GetKeyCode())
1442
+ if keycode < 256:
1443
+ #print keycode
1444
+ key = chr(keycode)
1445
+
1446
+ if key not in string.digits:
1447
+ return
1448
+ event.Skip()
1414
1449
  class Ops_Array(wx.Frame):
1415
1450
  """
1416
1451
  Operations wx.Frame on WolfArray class
@@ -1771,32 +1806,54 @@ class Ops_Array(wx.Frame):
1771
1806
  _("Select all nodes"), wx.DefaultPosition,
1772
1807
  wx.DefaultSize, 0)
1773
1808
  self.AllSelection.SetToolTip(_("Select all nodes in one click - store 'All' in the selection list"))
1774
- bSizer16_1.Add(self.AllSelection, 0, wx.EXPAND)
1809
+ bSizer16_1.Add(self.AllSelection, 1, wx.EXPAND)
1775
1810
 
1811
+ memory_sizer = wx.BoxSizer(wx.HORIZONTAL)
1776
1812
  self.MoveSelection = wx.Button(self.selection, wx.ID_ANY,
1777
- _("Move current selection to..."), wx.DefaultPosition,
1813
+ _("Move selection to..."), wx.DefaultPosition,
1778
1814
  wx.DefaultSize, 0)
1779
1815
  self.MoveSelection.SetToolTip(_("Store the current selection in an indexed list -- useful for some interpolation methods"))
1780
- bSizer16_1.Add(self.MoveSelection, 0, wx.EXPAND)
1781
1816
 
1782
1817
  self.ReselectMemory = wx.Button(self.selection, wx.ID_ANY,
1783
1818
  _("Reselect from..."), wx.DefaultPosition,
1784
1819
  wx.DefaultSize, 0)
1785
1820
  self.ReselectMemory.SetToolTip(_("Reselect the nodes from an indexed list"))
1786
- bSizer16_1.Add(self.ReselectMemory, 0, wx.EXPAND)
1787
1821
 
1822
+ memory_sizer.Add(self.MoveSelection, 1, wx.EXPAND)
1823
+ memory_sizer.Add(self.ReselectMemory, 1, wx.EXPAND)
1824
+ bSizer16_1.Add(memory_sizer, 1, wx.EXPAND)
1825
+
1826
+ reset_sizer = wx.BoxSizer(wx.HORIZONTAL)
1788
1827
  self.ResetSelection = wx.Button(self.selection, wx.ID_ANY,
1789
1828
  _("Reset"), wx.DefaultPosition,
1790
1829
  wx.DefaultSize, 0)
1791
1830
  self.ResetSelection.SetToolTip(_("Reset the current selection list (keyboard shortcut r)"))
1792
- bSizer16_1.Add(self.ResetSelection, 0, wx.EXPAND)
1793
-
1831
+
1794
1832
  self.ResetAllSelection = wx.Button(self.selection, wx.ID_ANY,
1795
1833
  _("Reset All"), wx.DefaultPosition,
1796
1834
  wx.DefaultSize, 0)
1797
1835
  self.ResetAllSelection.SetToolTip(_("Reset the current selection list and the indexed lists (keyboard shortcut R)"))
1798
- bSizer16_1.Add(self.ResetAllSelection, 0, wx.EXPAND)
1799
1836
 
1837
+ reset_sizer.Add(self.ResetSelection, 1, wx.EXPAND)
1838
+ reset_sizer.Add(self.ResetAllSelection, 1, wx.EXPAND)
1839
+ bSizer16_1.Add(reset_sizer, 1, wx.EXPAND)
1840
+
1841
+ save_load_sizer = wx.BoxSizer(wx.HORIZONTAL)
1842
+ self.SaveSelection = wx.Button(self.selection, wx.ID_ANY,
1843
+ _("Save"), wx.DefaultPosition,
1844
+ wx.DefaultSize, 0)
1845
+ self.SaveSelection.SetToolTip(_("Save the current selection list to disk"))
1846
+
1847
+ self.LoadSelection = wx.Button(self.selection, wx.ID_ANY,
1848
+ _("Load"), wx.DefaultPosition,
1849
+ wx.DefaultSize, 0)
1850
+ self.LoadSelection.SetToolTip(_("Load a selection list from disk"))
1851
+
1852
+ save_load_sizer.Add(self.SaveSelection, 1, wx.EXPAND)
1853
+ save_load_sizer.Add(self.LoadSelection, 1, wx.EXPAND)
1854
+ bSizer16_1.Add(save_load_sizer, 1, wx.EXPAND)
1855
+
1856
+ clipboad_sizer = wx.BoxSizer(wx.HORIZONTAL)
1800
1857
  self.to_clipboard_str = wx.Button(self.selection, wx.ID_ANY, _("To clipboard (str)"), wx.DefaultPosition,
1801
1858
  wx.DefaultSize, 0)
1802
1859
  self.to_clipboard_str.SetToolTip(_("Copy the current selection to the clipboard as a string"))
@@ -1805,19 +1862,19 @@ class Ops_Array(wx.Frame):
1805
1862
  wx.DefaultSize, 0)
1806
1863
  self.to_clipboard_script.SetToolTip(_("Copy the current selection to the clipboard as a script"))
1807
1864
 
1808
- bSizer16_2.Add(self.to_clipboard_str, 0, wx.EXPAND, 2)
1809
- bSizer16_2.Add(self.to_clipboard_script, 0, wx.EXPAND, 2)
1865
+ clipboad_sizer.Add(self.to_clipboard_str, 1, wx.EXPAND)
1866
+ clipboad_sizer.Add(self.to_clipboard_script, 1, wx.EXPAND)
1810
1867
 
1811
1868
  erode_dilate_sizer = wx.BoxSizer(wx.VERTICAL)
1812
- self.expand_selection = wx.Button(self.selection, wx.ID_ANY, _("Expand/Dilate selection"), wx.DefaultPosition,
1869
+ self.expand_selection = wx.Button(self.selection, wx.ID_ANY, _("Dilate"), wx.DefaultPosition,
1813
1870
  wx.DefaultSize, 0)
1814
1871
  self.expand_selection.SetToolTip(_("Expand the current selection to the nearest nodes"))
1815
1872
 
1816
- self.contract_selection = wx.Button(self.selection, wx.ID_ANY, _("Contract/Erode selection"), wx.DefaultPosition,
1873
+ self.contract_selection = wx.Button(self.selection, wx.ID_ANY, _("Erode"), wx.DefaultPosition,
1817
1874
  wx.DefaultSize, 0)
1818
1875
  self.contract_selection.SetToolTip(_("Contract the current selection to the nearest nodes"))
1819
1876
 
1820
- self.expand_unselect_interior = wx.Button(self.selection, wx.ID_ANY, _("Expand/Dilate contour"), wx.DefaultPosition,
1877
+ self.expand_unselect_interior = wx.Button(self.selection, wx.ID_ANY, _("Dilate contour"), wx.DefaultPosition,
1821
1878
  wx.DefaultSize, 0)
1822
1879
  self.expand_unselect_interior.SetToolTip(_("Expand the contour of the current selection and unselect the interior nodes"))
1823
1880
 
@@ -1825,25 +1882,31 @@ class Ops_Array(wx.Frame):
1825
1882
  wx.DefaultSize, 0)
1826
1883
  self.unselect_interior.SetToolTip(_("Conserve the contour of the current selection and unselect the interior nodes"))
1827
1884
 
1828
- erode_dilate_sizer.Add(self.expand_selection, 0, wx.EXPAND)
1829
- erode_dilate_sizer.Add(self.contract_selection, 0, wx.EXPAND)
1830
- erode_dilate_sizer.Add(self.expand_unselect_interior, 0, wx.EXPAND)
1831
- erode_dilate_sizer.Add(self.unselect_interior, 0, wx.EXPAND)
1885
+ er_dil_1 = wx.BoxSizer(wx.HORIZONTAL)
1886
+ er_dil_2 = wx.BoxSizer(wx.HORIZONTAL)
1887
+ er_dil_1.Add(self.expand_selection, 1, wx.EXPAND)
1888
+ er_dil_1.Add(self.contract_selection, 1, wx.EXPAND)
1889
+ er_dil_2.Add(self.expand_unselect_interior, 1, wx.EXPAND)
1890
+ er_dil_2.Add(self.unselect_interior, 1, wx.EXPAND)
1891
+
1892
+ erode_dilate_sizer.Add(er_dil_1, 1, wx.EXPAND)
1893
+ erode_dilate_sizer.Add(er_dil_2, 1, wx.EXPAND)
1832
1894
 
1833
1895
  erode_dilate_options = wx.BoxSizer(wx.HORIZONTAL)
1834
1896
  self._label_passes = wx.StaticText(self.selection, wx.ID_ANY, _("Passes"), wx.DefaultPosition, wx.DefaultSize, 0)
1835
1897
  self._erode_dilate_value = wx.TextCtrl(self.selection, wx.ID_ANY, u"1", wx.DefaultPosition, wx.DefaultSize, style=wx.TE_CENTER)
1836
1898
  self._erode_dilate_value.SetToolTip(_("Number of passes for the erode/dilate operation"))
1837
-
1838
- erode_dilate_options.Add(self._label_passes, 0, wx.EXPAND)
1839
- erode_dilate_options.Add(self._erode_dilate_value, 0, wx.EXPAND)
1899
+ self._erode_dilate_value.SetValidator(validator=IntValidator())
1900
+
1901
+ erode_dilate_options.Add(self._label_passes, 1, wx.EXPAND)
1902
+ erode_dilate_options.Add(self._erode_dilate_value, 1, wx.EXPAND)
1840
1903
 
1841
1904
  self._erode_dilate_structure = wx.ComboBox(self.selection, wx.ID_ANY, _("Cross"), wx.DefaultPosition, wx.DefaultSize,
1842
1905
  ["Cross", "Square"], wx.CB_READONLY)
1843
1906
  self._erode_dilate_structure.SetToolTip(_("Structuring element for the erode/dilate operation"))
1844
1907
  erode_dilate_options.Add(self._erode_dilate_structure, 1, wx.EXPAND)
1845
1908
 
1846
- erode_dilate_sizer.Add(erode_dilate_options, 0, wx.EXPAND)
1909
+ erode_dilate_sizer.Add(erode_dilate_options, 1, wx.EXPAND)
1847
1910
 
1848
1911
  # MultiBlocks
1849
1912
  # ----------------
@@ -1870,8 +1933,10 @@ class Ops_Array(wx.Frame):
1870
1933
  # bSizer16.Add(self._open_block, 0, wx.EXPAND)
1871
1934
 
1872
1935
  bSizer16_1.Add(erode_dilate_sizer, 1, wx.EXPAND, 5)
1936
+ bSizer16_1.Add(clipboad_sizer, 1, wx.EXPAND)
1937
+
1873
1938
  bSizer16.Add(bSizer16_1, 1, wx.EXPAND, 5)
1874
- bSizer16.Add(bSizer16_2, 1, wx.EXPAND, 5)
1939
+ # bSizer16.Add(bSizer16_2, 1, wx.EXPAND, 5)
1875
1940
  bSizer21.Add(bSizer16, 1, wx.EXPAND, 5)
1876
1941
 
1877
1942
  # VECTORS Manager
@@ -2052,6 +2117,9 @@ class Ops_Array(wx.Frame):
2052
2117
  self.to_clipboard_str.Bind(wx.EVT_BUTTON, self.OnToClipboardStr)
2053
2118
  self.to_clipboard_script.Bind(wx.EVT_BUTTON, self.OnToClipboardStr)
2054
2119
 
2120
+ self.SaveSelection.Bind(wx.EVT_BUTTON, self.OnSaveSelection)
2121
+ self.LoadSelection.Bind(wx.EVT_BUTTON, self.OnLoadSelection)
2122
+
2055
2123
  self.m_button2.Bind(wx.EVT_BUTTON, self.OnManageVectors)
2056
2124
  self.loadvec.Bind(wx.EVT_BUTTON, self.OnLoadvec)
2057
2125
  self.saveas.Bind(wx.EVT_BUTTON, self.OnSaveasvec)
@@ -2294,7 +2362,8 @@ class Ops_Array(wx.Frame):
2294
2362
 
2295
2363
  usemask = self.selectrestricttomask.GetValue()
2296
2364
 
2297
- self.parentarray.erode_selection(nb, usemask = usemask, structure = structure)
2365
+ self.parentarray.SelectionData.erode_selection(nb, usemask, structure)
2366
+ self.refresh_array()
2298
2367
 
2299
2368
  def OnExpandSelection(self, event):
2300
2369
  """ Expand selection """
@@ -2306,7 +2375,8 @@ class Ops_Array(wx.Frame):
2306
2375
 
2307
2376
  usemask = self.selectrestricttomask.GetValue()
2308
2377
 
2309
- self.parentarray.dilate_selection(nb, usemask, structure)
2378
+ self.parentarray.SelectionData.dilate_selection(nb, usemask, structure)
2379
+ self.refresh_array()
2310
2380
 
2311
2381
  def OnExpandUnselectInterior(self, event):
2312
2382
  """ Expand contour """
@@ -2319,11 +2389,13 @@ class Ops_Array(wx.Frame):
2319
2389
 
2320
2390
  usemask = self.selectrestricttomask.GetValue()
2321
2391
 
2322
- self.parentarray.dilate_contour_selection(nb, usemask, structure)
2392
+ self.parentarray.SelectionData.dilate_contour_selection(nb, usemask, structure)
2393
+ self.refresh_array()
2323
2394
 
2324
2395
  def OnUnselectInterior(self, event):
2325
2396
  """ Contract contour """
2326
- self.parentarray.erode_contour_selection()
2397
+ self.parentarray.SelectionData.erode_contour_selection()
2398
+ self.refresh_array()
2327
2399
 
2328
2400
  def reset_selection(self):
2329
2401
  """
@@ -2363,6 +2435,20 @@ class Ops_Array(wx.Frame):
2363
2435
  self.reset_all_selection()
2364
2436
  self.refresh_array()
2365
2437
 
2438
+ def OnSaveSelection(self, event):
2439
+ """
2440
+ Save the current selection
2441
+ """
2442
+
2443
+ self.parentarray.SelectionData.save_selection()
2444
+
2445
+ def OnLoadSelection(self, event):
2446
+ """
2447
+ Load a selection
2448
+ """
2449
+
2450
+ self.parentarray.SelectionData.load_selection()
2451
+
2366
2452
  def OnToClipboardStr(self, event):
2367
2453
  """
2368
2454
  Copy the current selection to the clipboard as a string
@@ -3165,16 +3251,19 @@ class SelectionData():
3165
3251
  self.myselection = []
3166
3252
  self.selections = {}
3167
3253
 
3168
- def get_string(self, which:str = None) -> str:
3254
+ def get_string(self, which:str = None, all_memories:bool= False) -> str:
3169
3255
  """ Get string of the current selection or of a stored one """
3170
3256
 
3171
3257
  if which is None:
3172
3258
  curlist = self.myselection
3173
- txt = 'X\tY'
3259
+ txt = 'X\tY\n'
3174
3260
  else:
3175
3261
  if str(which) in self.selections:
3262
+ all_memories = False
3176
3263
  curlist = self.selections[str(which)]['select']
3177
- txt = 'Selection {}\n'.format(which) + 'X\tY\n'
3264
+ txt = 'Selection {}\n'.format(which)
3265
+ txt += 'Color : {}\n'.format(self.selections[str(which)]['color'])
3266
+ txt += 'X\tY\n'
3178
3267
  else:
3179
3268
  logging.error(_('Selection {} does not exist').format(which))
3180
3269
  return ''
@@ -3194,6 +3283,10 @@ class SelectionData():
3194
3283
  i,j = self.parent.get_ij_from_xy(cur[0], cur[1], aswolf=True)
3195
3284
  txt += str(i) + '\t' + str(j) + '\n'
3196
3285
 
3286
+ if all_memories:
3287
+ for key, cur in self.selections.items():
3288
+ txt += self.get_string(key)
3289
+
3197
3290
  return txt
3198
3291
 
3199
3292
  def get_script(self, which:int = None) -> str:
@@ -3627,6 +3720,101 @@ class SelectionData():
3627
3720
 
3628
3721
  self.update_nb_nodes_selection()
3629
3722
 
3723
+ def dilate_contour_selection(self, nbiter:int= 1, use_mask:bool = True, structure:np.ndarray = np.ones((3,3))):
3724
+ """ Dilate the contour of the selection """
3725
+
3726
+ if self.nb > 0:
3727
+ oldsel = self.myselection.copy()
3728
+ self.dilate_selection(nbiter, use_mask, structure)
3729
+ newsel = self.myselection.copy()
3730
+ self.myselection = [cur for cur in newsel if cur not in oldsel]
3731
+ self.update_nb_nodes_selection()
3732
+ else:
3733
+ logging.info('No selection to expand/dilate')
3734
+
3735
+ def erode_contour_selection(self):
3736
+ """ Erode the contour of the selection """
3737
+
3738
+ if self.nb > 0:
3739
+ oldselect = self.myselection.copy()
3740
+ self.erode_selection(1)
3741
+ newselect = self.myselection.copy()
3742
+ self.myselection = [cur for cur in oldselect if cur not in newselect]
3743
+ self.update_nb_nodes_selection()
3744
+ else:
3745
+ logging.info('No selection to contract/erode')
3746
+
3747
+ def save_selection(self, filename:str=None):
3748
+ """ Save the selection to a file """
3749
+
3750
+ if filename is None:
3751
+ with wx.FileDialog(None, 'Save selection', wildcard='Text files (*.txt)|*.txt',
3752
+ style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as dlg:
3753
+ if dlg.ShowModal() == wx.ID_CANCEL:
3754
+ return
3755
+ filename = dlg.GetPath()
3756
+
3757
+ with open(filename, 'w') as f:
3758
+ f.write(self.get_string(all_memories=True))
3759
+
3760
+ def load_selection(self, filename:str=None):
3761
+ """ Load a selection from a file """
3762
+
3763
+ if filename is None:
3764
+ with wx.FileDialog(None, 'Load selection', wildcard='Text files (*.txt)|*.txt',
3765
+ style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as dlg:
3766
+ if dlg.ShowModal() == wx.ID_CANCEL:
3767
+ return
3768
+ filename = dlg.GetPath()
3769
+
3770
+ with open(filename, 'r') as f:
3771
+ lines = f.readlines()
3772
+
3773
+ xy = []
3774
+ k=0
3775
+ for line in lines:
3776
+ if line[0] == 'X':
3777
+ k+=1
3778
+ continue
3779
+ if line[0] == 'i':
3780
+ k+=1
3781
+ break
3782
+ x, y = line.split()
3783
+ xy.append((float(x), float(y)))
3784
+ k+=1
3785
+
3786
+ self.myselection = xy
3787
+ self.update_nb_nodes_selection()
3788
+
3789
+ k += len(xy)
3790
+
3791
+ while k < len(lines):
3792
+ lines = lines[k:]
3793
+ k=0
3794
+ for line in lines:
3795
+ if 'Selection' in line:
3796
+ idx = line.split()[1]
3797
+ self.selections[idx] = {}
3798
+ xy = []
3799
+ k+=1
3800
+ elif 'Color' in line:
3801
+ color = [int(x.replace('[','').replace(']','').replace(',','')) for x in line.split()[2:]]
3802
+ self.selections[idx]['Color'] = color
3803
+ k+=1
3804
+ elif line[0] == 'X':
3805
+ k+=1
3806
+ continue
3807
+ elif line[0] == 'i':
3808
+ k+=len(xy)+1
3809
+ self.selections[idx]['select']=xy
3810
+ break
3811
+ else:
3812
+ x, y = line.split()
3813
+ xy.append((float(x), float(y)))
3814
+ k+=1
3815
+
3816
+ self.parent.reset_plot()
3817
+
3630
3818
  def update_nb_nodes_selection(self):
3631
3819
  """ Update the number of selected nodes """
3632
3820
 
@@ -4386,6 +4574,14 @@ class SelectionDataMB(SelectionData):
4386
4574
  def get_string(self, which:str = None) -> str:
4387
4575
 
4388
4576
  logging.error(_('Not yet implemented for Multi-Blocks'))
4577
+
4578
+ def save_selection(self, filename:str=None, which:str = None):
4579
+
4580
+ logging.error(_('Not yet implemented for Multi-Blocks'))
4581
+
4582
+ def load_selection(self, filename:str=None, which:str = None):
4583
+
4584
+ logging.error(_('Not yet implemented for Multi-Blocks'))
4389
4585
 
4390
4586
  def get_script(self, which:int = None) -> str:
4391
4587
 
@@ -4417,6 +4613,18 @@ class SelectionDataMB(SelectionData):
4417
4613
  for curblock in self.parent.active_blocks:
4418
4614
  curblock.SelectionData.select_underpoly(myvect)
4419
4615
 
4616
+ def dilate_selection(self, nb_iterations:int, use_mask:bool = True, structure:np.ndarray = None):
4617
+ """ Extend the selection """
4618
+
4619
+ for curblock in self.parent.active_blocks:
4620
+ curblock.SelectionData.dilate_selection(nb_iterations, use_mask, structure)
4621
+
4622
+ def erode_selection(self, nb_iterations:int, use_mask:bool = True, structure:np.ndarray = None):
4623
+ """ Reduce the selection """
4624
+
4625
+ for curblock in self.parent.active_blocks:
4626
+ curblock.SelectionData.erode_selection(nb_iterations, use_mask, structure)
4627
+
4420
4628
  def update_nb_nodes_selection(self):
4421
4629
  """ Update the number of nodes selected """
4422
4630
 
@@ -4767,55 +4975,6 @@ class WolfArray(Element_To_Draw, header_wolf):
4767
4975
 
4768
4976
  self.add_ops_sel() # Ajout d'un gestionnaire de sélection et d'opérations
4769
4977
 
4770
- def erode_selection(self, nbiter:int= 1, usemask:bool = True, structure:np.ndarray = np.ones((3,3))):
4771
- """ Erode the selection """
4772
-
4773
- if self.SelectionData is not None:
4774
- if self.SelectionData.nb > 0:
4775
- self.SelectionData.erode_selection(nbiter, usemask, structure)
4776
- self.SelectionData.update_nb_nodes_selection()
4777
- self.reset_plot()
4778
- else:
4779
- logging.info('No selection to contract/erode')
4780
-
4781
- def dilate_selection(self, nbiter:int= 1, usemask:bool = True, structure:np.ndarray = np.ones((3,3))):
4782
- """ Dilate the selection """
4783
-
4784
- if self.SelectionData is not None:
4785
- if self.SelectionData.nb > 0:
4786
- self.SelectionData.dilate_selection(nbiter, usemask, structure)
4787
- self.SelectionData.update_nb_nodes_selection()
4788
- self.reset_plot()
4789
- else:
4790
- logging.info('No selection to dilate')
4791
-
4792
- def dilate_contour_selection(self, nbiter:int= 1, usemask:bool = True, structure:np.ndarray = np.ones((3,3))):
4793
- """ Dilate the contour of the selection """
4794
-
4795
- if self.SelectionData is not None:
4796
- if self.SelectionData.nb > 0:
4797
- oldsel = self.SelectionData.myselection.copy()
4798
- self.SelectionData.dilate_selection(nbiter, usemask, structure)
4799
- newsel = self.SelectionData.myselection.copy()
4800
- self.SelectionData.myselection = [cur for cur in newsel if cur not in oldsel]
4801
- self.SelectionData.update_nb_nodes_selection()
4802
- self.reset_plot()
4803
- else:
4804
- logging.info('No selection to expand/dilate')
4805
-
4806
- def erode_contour_selection(self):
4807
- """ Erode the contour of the selection """
4808
- if self.SelectionData is not None:
4809
- if self.SelectionData.nb > 0:
4810
- oldselect = self.SelectionData.myselection.copy()
4811
- self.SelectionData.erode_selection(1)
4812
- newselect = self.SelectionData.myselection.copy()
4813
- self.SelectionData.myselection = [cur for cur in oldselect if cur not in newselect]
4814
- self.SelectionData.update_nb_nodes_selection()
4815
- self.reset_plot()
4816
- else:
4817
- logging.info('No selection to contract/erode')
4818
-
4819
4978
  def set_opacity(self, alpha:float):
4820
4979
  """ Set the transparency of the array """
4821
4980
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wolfhece
3
- Version: 2.1.75
3
+ Version: 2.1.76
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=SI4oNF_J3MdjiWZoizS8kuRXLMVyymX9dYfYJNVCQVI,476989
8
8
  wolfhece/PyConfig.py,sha256=FB8u0belXOXTb03Ln6RdVWvMgjzi3oGPCmw2dWa3lNg,8332
9
9
  wolfhece/PyCrosssections.py,sha256=FnmM9DWY_SAF2EDH9Gu2PojXNtSTRF4-aYQuAAJXBh4,112771
10
- wolfhece/PyDraw.py,sha256=nud0raPc9AYDLgA3dYNOaOXQCWzLzCicxmxp7VihYtQ,416394
10
+ wolfhece/PyDraw.py,sha256=VPe_MTPd6_gjyRL627yEWnE6RbL9t-EQmEDLa1t1dVM,421909
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=4D2fj4-Zaqe-IBRB-X4rhjAuHNlnYl9mT15KJeeyl50,395523
51
+ wolfhece/wolf_array.py,sha256=Rj_N7yg4OqwLRAWwDBl0VwwpXLzP0hPwhTRcwB3P5yA,400860
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=xL8JIrHIqANzTmqWx_eqnA9DTXZoDlLxaaofqhuey1I,388
75
+ wolfhece/apps/version.py,sha256=mJE6gMQ0LXmVC2n9qC4xJHXz1aj3sU-1ej5zEwZ8K4E,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,8 +126,8 @@ 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=jW5ivM0h_wZ_jM6OWh994iwQtsCZdwmQsMA7TMnCxMg,46495
130
- wolfhece/hydrometry/kiwis_gui.py,sha256=lApsSeBMJNAR1yocggdoHwz_xe6M_oaZ_E13CfHAlQA,23124
129
+ wolfhece/hydrometry/kiwis.py,sha256=br80IMFvg2xfTjaUaYT9QS7q1LBzQ8kvPBxJDcSujrA,55991
130
+ wolfhece/hydrometry/kiwis_gui.py,sha256=SdO8EmyFzhzjHlEjZtNJ68HXBOLkK9l40c0750F39V4,23146
131
131
  wolfhece/hydrometry/kiwis_wolfgui.py,sha256=GPa5YNp2V2ZlxYQjPiCXERgPuWB_zij4ec2yHpRvoFA,4027
132
132
  wolfhece/hydrometry/kiwispie.py,sha256=akOaV46WwzISVlCcPz_phjsBrI_rDACUzdELtjx-xNg,13498
133
133
  wolfhece/icons/folder_open.png,sha256=ykBlU2FtGcpjAu1YO4_eGlDg2svgs_IAs-4d5O2e3AM,2329
@@ -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.75.dist-info/METADATA,sha256=90OU0iX7noC8qKik5I2b-UqAjkalAUEMy8qdKctQovo,2570
287
- wolfhece-2.1.75.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
288
- wolfhece-2.1.75.dist-info/entry_points.txt,sha256=Q5JuIWV4odeIJI3qc6fV9MwRoz0ezqPVlFC1Ppm_vdQ,395
289
- wolfhece-2.1.75.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
290
- wolfhece-2.1.75.dist-info/RECORD,,
286
+ wolfhece-2.1.76.dist-info/METADATA,sha256=MjRjAJdHj-X5rrJuDTOU25orlRrGES6yus46PEGqQQw,2570
287
+ wolfhece-2.1.76.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
288
+ wolfhece-2.1.76.dist-info/entry_points.txt,sha256=Q5JuIWV4odeIJI3qc6fV9MwRoz0ezqPVlFC1Ppm_vdQ,395
289
+ wolfhece-2.1.76.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
290
+ wolfhece-2.1.76.dist-info/RECORD,,