wolfhece 2.1.92__py3-none-any.whl → 2.1.93__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
@@ -121,6 +121,377 @@ ID_PLOTCS = 1003 #Manageactions ID for profile plots
121
121
 
122
122
  LIST_1TO9 = [wx.WXK_NUMPAD1, wx.WXK_NUMPAD2, wx.WXK_NUMPAD3, wx.WXK_NUMPAD4, wx.WXK_NUMPAD5, wx.WXK_NUMPAD6, wx.WXK_NUMPAD7, wx.WXK_NUMPAD8, wx.WXK_NUMPAD9 ] + [ord(str(cur)) for cur in range(1,10)]
123
123
 
124
+ class Memory_View():
125
+ """ Memory view """
126
+
127
+ def __init__(self, screen_width, screen_height, xmin, xmax, ymin, ymax):
128
+ """ Constructor """
129
+
130
+ self.screen_width = screen_width
131
+ self.screen_height = screen_height
132
+ self.xmin = xmin
133
+ self.xmax = xmax
134
+ self.ymin = ymin
135
+ self.ymax = ymax
136
+
137
+ @property
138
+ def width(self):
139
+ """ Width of the view """
140
+ return self.xmax - self.xmin
141
+
142
+ @property
143
+ def height(self):
144
+ """ Height of the view """
145
+ return self.ymax - self.ymin
146
+
147
+ def __str__(self):
148
+ """ String representation of the view """
149
+
150
+ return f"Memory view : {self.screen_width}x{self.screen_height} ({self.xmin},{self.ymin})-({self.xmax},{self.ymax})"
151
+
152
+ def serialize(self):
153
+ """ Serialize the view """
154
+
155
+ return {
156
+ "screen_width": self.screen_width,
157
+ "screen_height": self.screen_height,
158
+ "xmin": self.xmin,
159
+ "xmax": self.xmax,
160
+ "ymin": self.ymin,
161
+ "ymax": self.ymax
162
+ }
163
+
164
+ @staticmethod
165
+ def deserialize(data:dict):
166
+ """ Deserialize the view """
167
+
168
+ return Memory_View(data["screen_width"], data["screen_height"], data["xmin"], data["xmax"], data["ymin"], data["ymax"])
169
+
170
+ class Memory_View_encoder(json.JSONEncoder):
171
+ """ Memory view encoder """
172
+
173
+ def default(self, o):
174
+ """ Default method """
175
+
176
+ if isinstance(o, Memory_View):
177
+ return o.serialize()
178
+ else:
179
+ return super().default(o)
180
+
181
+ class Memory_View_decoder(json.JSONDecoder):
182
+ """ Memory view decoder """
183
+
184
+ def __init__(self, *args, **kwargs):
185
+ """ Constructor """
186
+
187
+ super().__init__(object_hook=self.object_hook, *args, **kwargs)
188
+
189
+ def object_hook(self, obj):
190
+ """ Decode the object """
191
+
192
+ if "screen_width" in obj and "screen_height" in obj and "xmin" in obj and "xmax" in obj and "ymin" in obj and "ymax" in obj:
193
+ return Memory_View.deserialize(obj)
194
+ else:
195
+ return obj
196
+
197
+ class Memory_Views():
198
+ """ Memory views """
199
+
200
+ def __init__(self):
201
+
202
+ self.views:dict[str,Memory_View] = {}
203
+
204
+ def __len__(self):
205
+ """ Number of views """
206
+
207
+ return len(self.views)
208
+
209
+ def add_view(self, name:str, screen_width:int, screen_height:int, xmin:float, xmax:float, ymin:float, ymax:float):
210
+ """ Add a new view to the memory views """
211
+ self.views[name] = Memory_View(screen_width, screen_height, xmin, xmax, ymin, ymax)
212
+
213
+ def remove_view(self, name:str):
214
+ """ Remove a view from the memory views """
215
+
216
+ if name in self.views:
217
+ self.views.pop(name)
218
+
219
+ def reset(self):
220
+ """ Reset the memory views """
221
+
222
+ self.views = {}
223
+
224
+ def __getitem__(self, name:str) -> Memory_View:
225
+ """ Get a view from the memory views """
226
+
227
+ if name in self.views:
228
+ return self.views[name]
229
+ else:
230
+ return None
231
+
232
+ def zoom_on(self, name:str, mapviewer:"WolfMapViewer"):
233
+ """ Zoom on a view """
234
+
235
+ if name not in self.views:
236
+ return
237
+
238
+ view = self.views[name]
239
+
240
+ mapviewer.zoom_on(width= view.width, height=view.height, xll=view.xmin, yll=view.ymin, canvas_height=view.screen_height)
241
+
242
+ def save(self, filename:str):
243
+ """ Save the memory views """
244
+
245
+ with open(filename, 'w') as f:
246
+ json.dump(self.views, f,
247
+ cls=Memory_View_encoder,
248
+ indent=4)
249
+
250
+ def load(self, filename:str):
251
+ """ Load the memory views """
252
+
253
+ with open(filename, 'r') as f:
254
+ self.views = json.load(f, cls=Memory_View_decoder)
255
+
256
+ # self.views = {k:Memory_View.deserialize(v) for k,v in tmp_views.items()}
257
+
258
+ class Memory_Views_GUI(wx.Frame):
259
+ """ Memory views GUI """
260
+
261
+ def __init__(self, parent, title, memory_views:Memory_Views, mapviewer:"WolfMapViewer"):
262
+ """ Constructor """
263
+
264
+ super(Memory_Views_GUI, self).__init__(parent, title=title, size=(200, 400), style = wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER | wx.MAXIMIZE_BOX | wx.MINIMIZE_BOX | wx.CLOSE_BOX))
265
+ self.mapviewer = mapviewer
266
+ self._memory_views = memory_views
267
+
268
+
269
+ panel = wx.Panel(self)
270
+ panel.SetBackgroundColour(wx.Colour(255, 255, 255))
271
+
272
+ sizer = wx.BoxSizer(wx.VERTICAL)
273
+
274
+ self._views = wx.ListBox(panel, choices= list(memory_views.views.keys()), style=wx.LB_SINGLE)
275
+
276
+ self._cmdZoom = wx.Button(panel, wx.ID_ANY, _('Zoom on'))
277
+ self._cmdZoom.SetToolTip(_('Zoom on the selected view'))
278
+
279
+ self._cmdAdd = wx.Button(panel, wx.ID_ADD, _('+'))
280
+ self._cmdAdd.SetToolTip(_('Add a view based on the current zoom and shape of the canvas'))
281
+
282
+ self._cmdDelete = wx.Button(panel, wx.ID_DELETE, _('-'))
283
+ self._cmdDelete.SetToolTip(_('Delete the selected view'))
284
+
285
+ self._cmdReset = wx.Button(panel, wx.ID_RESET, _('Reset'))
286
+ self._cmdReset.SetToolTip(_('Reset the views'))
287
+
288
+ sizer.Add(self._views, 5, wx.EXPAND | wx.ALL, 2)
289
+
290
+ sizer_but = wx.BoxSizer(wx.HORIZONTAL)
291
+ sizer_but.Add(self._cmdAdd, 1, wx.EXPAND)
292
+ sizer_but.Add(self._cmdDelete, 1, wx.EXPAND)
293
+
294
+ sizer.Add(self._cmdZoom, 1, wx.EXPAND, 2)
295
+ sizer.Add(sizer_but, 1, wx.EXPAND, 2)
296
+ sizer.Add(self._cmdReset, 1, wx.EXPAND , 2)
297
+
298
+ sizer_manual = wx.BoxSizer(wx.VERTICAL)
299
+
300
+ sizer_xmin = wx.BoxSizer(wx.HORIZONTAL)
301
+ self._label_xmin = wx.StaticText(panel, label=_('X min'))
302
+ self._xmin = wx.TextCtrl(panel, value=str(mapviewer.xmin), style=wx.ALIGN_CENTER_HORIZONTAL)
303
+ sizer_xmin.Add(self._label_xmin, 1, wx.ALL, 2)
304
+ sizer_xmin.Add(self._xmin, 1, wx.ALL, 2)
305
+
306
+ sizer_xmax = wx.BoxSizer(wx.HORIZONTAL)
307
+ self._label_xmax = wx.StaticText(panel, label=_('X max'))
308
+ self._xmax = wx.TextCtrl(panel, value=str(mapviewer.xmax), style=wx.ALIGN_CENTER_HORIZONTAL)
309
+ sizer_xmax.Add(self._label_xmax, 1, wx.ALL, 2)
310
+ sizer_xmax.Add(self._xmax, 1, wx.ALL, 2)
311
+
312
+ sizer_ymin = wx.BoxSizer(wx.HORIZONTAL)
313
+ self._label_ymin = wx.StaticText(panel, label=_('Y min'))
314
+ self._ymin = wx.TextCtrl(panel, value=str(mapviewer.ymin), style=wx.ALIGN_CENTER_HORIZONTAL)
315
+ sizer_ymin.Add(self._label_ymin, 1, wx.ALL, 2)
316
+ sizer_ymin.Add(self._ymin, 1, wx.ALL, 2)
317
+
318
+ sizer_ymax = wx.BoxSizer(wx.HORIZONTAL)
319
+ self._label_ymax = wx.StaticText(panel, label=_('Y max'))
320
+ self._ymax = wx.TextCtrl(panel, value=str(mapviewer.ymax), style=wx.ALIGN_CENTER_HORIZONTAL)
321
+ sizer_ymax.Add(self._label_ymax, 1, wx.ALL, 2)
322
+ sizer_ymax.Add(self._ymax, 1, wx.ALL, 2)
323
+
324
+ sizer_canvas_height = wx.BoxSizer(wx.HORIZONTAL)
325
+ self._label_canvas_height = wx.StaticText(panel, label=_('Canvas height'))
326
+ self._canvas_height = wx.TextCtrl(panel, value=str(mapviewer.canvasheight), style=wx.ALIGN_CENTER_HORIZONTAL)
327
+
328
+ self._label_canvas_height.SetToolTip(_('Height of the canvas in pixels'))
329
+ self._canvas_height.SetToolTip(_('Height of the canvas in pixels'))
330
+
331
+ sizer_canvas_height.Add(self._label_canvas_height, 1, wx.ALL, 2)
332
+ sizer_canvas_height.Add(self._canvas_height, 1, wx.ALL, 2)
333
+
334
+ sizer_manual.Add(sizer_xmin, 1, wx.ALL, 2)
335
+ sizer_manual.Add(sizer_xmax, 1, wx.ALL, 2)
336
+ sizer_manual.Add(sizer_ymin, 1, wx.ALL, 2)
337
+ sizer_manual.Add(sizer_ymax, 1, wx.ALL, 2)
338
+ sizer_manual.Add(sizer_canvas_height, 1, wx.ALL, 2)
339
+
340
+ sizer_but2 = wx.BoxSizer(wx.HORIZONTAL)
341
+ self._cmdGet = wx.Button(panel, wx.ID_ANY, _('Get'))
342
+ self._cmdGet.SetToolTip(_('Get the current bounds of the canvas and fill the fields'))
343
+
344
+ self._cmdApply = wx.Button(panel, wx.ID_APPLY, _('Apply'))
345
+ self._cmdApply.SetToolTip(_('Apply the values to the selected view'))
346
+
347
+ self._cmdApply.Bind(wx.EVT_BUTTON, self.OnApply)
348
+ self._cmdGet.Bind(wx.EVT_BUTTON, self.OnGet)
349
+
350
+ sizer_but2.Add(self._cmdGet, 1, wx.ALL, 2)
351
+ sizer_but2.Add(self._cmdApply, 1, wx.ALL, 2)
352
+
353
+ sizer_manual.Add(sizer_but2, 1, wx.EXPAND, 2)
354
+ sizer.Add(sizer_manual, 1, wx.ALL, 2)
355
+
356
+ sizer_save_load = wx.BoxSizer(wx.HORIZONTAL)
357
+ self._cmdSave = wx.Button(panel, wx.ID_SAVE, _('Save'))
358
+ self._cmdSave.SetToolTip(_('Save the memory views to a json file'))
359
+
360
+ self._cmdLoad = wx.Button(panel, wx.ID_OPEN, _('Load'))
361
+ self._cmdLoad.SetToolTip(_('Load the memory views from a json file'))
362
+
363
+ sizer_save_load.Add(self._cmdSave, 1, wx.ALL, 2)
364
+ sizer_save_load.Add(self._cmdLoad, 1, wx.ALL, 2)
365
+
366
+ sizer.Add(sizer_save_load, 1, wx.EXPAND, 2)
367
+
368
+ self._views.Bind(wx.EVT_LISTBOX, self.OnSelectView)
369
+ self.Bind(wx.EVT_BUTTON, self.OnAdd, self._cmdAdd)
370
+ self.Bind(wx.EVT_BUTTON, self.OnDelete, self._cmdDelete)
371
+ self.Bind(wx.EVT_BUTTON, self.OnReset, self._cmdReset)
372
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
373
+ self.Bind(wx.EVT_BUTTON, self.OnSave, self._cmdSave)
374
+ self.Bind(wx.EVT_BUTTON, self.OnLoad, self._cmdLoad)
375
+ self.Bind(wx.EVT_BUTTON, self.OnZoom, self._cmdZoom)
376
+
377
+ panel.SetSizer(sizer)
378
+
379
+ self.CenterOnScreen()
380
+
381
+ icon = wx.Icon()
382
+ icon_path = Path(__file__).parent / "apps/wolf_logo2.bmp"
383
+ icon.CopyFromBitmap(wx.Bitmap(str(icon_path), wx.BITMAP_TYPE_ANY))
384
+ self.SetIcon(icon)
385
+
386
+ self.Show()
387
+
388
+ def OnSave(self, event):
389
+ """ Save the memory views """
390
+
391
+ with wx.FileDialog(self, _('Save the memory views'), wildcard="JSON files (*.json)|*.json",
392
+ style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:
393
+ if fileDialog.ShowModal() == wx.ID_CANCEL:
394
+ return
395
+
396
+ self._memory_views.save(fileDialog.GetPath())
397
+
398
+ def OnLoad(self, event):
399
+ """ Load the memory views """
400
+
401
+ with wx.FileDialog(self, _('Load the memory views'), wildcard="JSON files (*.json)|*.json",
402
+ style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
403
+ if fileDialog.ShowModal() == wx.ID_CANCEL:
404
+ return
405
+
406
+ self._memory_views.load(fileDialog.GetPath())
407
+
408
+ if self._memory_views is None:
409
+ logging.error(_('Error while loading the memory views'))
410
+ return
411
+
412
+ if self._memory_views.views is None:
413
+ logging.error(_('Error while loading the memory views'))
414
+ return
415
+
416
+ self._views.Set(list(self._memory_views.views.keys()))
417
+
418
+ def OnClose(self, event):
419
+ """ Close the memory views GUI """
420
+
421
+ self.mapviewer._memory_views_gui = None
422
+ self.Destroy()
423
+
424
+ def OnSelectView(self, event):
425
+ """ Select a view """
426
+
427
+ view = self._views.GetStringSelection()
428
+ locview = self._memory_views[view]
429
+
430
+ if locview is None:
431
+ return
432
+
433
+ self._xmax.SetValue(str(self._memory_views[view].xmax))
434
+ self._xmin.SetValue(str(self._memory_views[view].xmin))
435
+ self._ymax.SetValue(str(self._memory_views[view].ymax))
436
+ self._ymin.SetValue(str(self._memory_views[view].ymin))
437
+ self._canvas_height.SetValue(str(self._memory_views[view].screen_height))
438
+
439
+ def OnZoom(self, event):
440
+ """ Zoom on the current view """
441
+
442
+ view = self._views.GetStringSelection()
443
+ self._memory_views.zoom_on(view, self.mapviewer)
444
+
445
+ def OnAdd(self, event):
446
+ """ Add a view """
447
+
448
+ name = "View " + str(len(self._memory_views.views) + 1)
449
+ with wx.TextEntryDialog(self, _('Enter the name of the view'), _('Add a view'), name) as dlg:
450
+ if dlg.ShowModal() == wx.ID_OK:
451
+ name = dlg.GetValue()
452
+
453
+ self._memory_views.add_view(name, self.mapviewer.canvaswidth, self.mapviewer.canvasheight, self.mapviewer.xmin, self.mapviewer.xmax, self.mapviewer.ymin, self.mapviewer.ymax)
454
+
455
+ self._views.Set(list(self._memory_views.views.keys()))
456
+
457
+ def OnDelete(self, event):
458
+ """ Delete a view """
459
+
460
+ view = self._views.GetStringSelection()
461
+ self._memory_views.remove_view(view)
462
+
463
+ self._views.Set(list(self._memory_views.views.keys()))
464
+
465
+ def OnReset(self, event):
466
+ """ Reset the views """
467
+
468
+ self._memory_views.reset()
469
+
470
+ def OnApply(self, event):
471
+ """ Apply the changes """
472
+
473
+ view = self._views.GetStringSelection()
474
+
475
+ try:
476
+ xmin = float(self._xmin.GetValue())
477
+ xmax = float(self._xmax.GetValue())
478
+ ymin = float(self._ymin.GetValue())
479
+ ymax = float(self._ymax.GetValue())
480
+ canvas_height = int(self._canvas_height.GetValue())
481
+
482
+ self._memory_views.add_view(view, self.mapviewer.canvaswidth, canvas_height, xmin, xmax, ymin, ymax)
483
+ except:
484
+ logging.error(_('Error while applying the changes'))
485
+
486
+ def OnGet(self, event):
487
+ """ Get the values """
488
+
489
+ self._xmin.SetValue(str(self.mapviewer.xmin))
490
+ self._xmax.SetValue(str(self.mapviewer.xmax))
491
+ self._ymin.SetValue(str(self.mapviewer.ymin))
492
+ self._ymax.SetValue(str(self.mapviewer.ymax))
493
+ self._canvas_height.SetValue(str(self.mapviewer.canvasheight))
494
+
124
495
  class draw_type(Enum):
125
496
  # FIXME: change this to be more robust -> Done !
126
497
  # Be careful with the enum name, it must be the same than the one used to create the tree list elements, but in lower case
@@ -600,7 +971,10 @@ class WolfMapViewer(wx.Frame):
600
971
 
601
972
  self.menu_contour_from_arrays = self.tools_menu.Append(wx.ID_ANY, _("Create contour from checked arrays..."), _("Create contour"))
602
973
  self.menu_calculator = self.tools_menu.Append(wx.ID_ANY, _("Calculator..."), _("Calculator"))
974
+ self.menu_views = self.tools_menu.Append(wx.ID_ANY, _("Memory views..."), _("Memory views"))
603
975
  self.calculator = None
976
+ self.memory_views = None
977
+ self._memory_views_gui = None
604
978
 
605
979
  # Cross sections
606
980
  # ----------------
@@ -5218,6 +5592,18 @@ class WolfMapViewer(wx.Frame):
5218
5592
  else:
5219
5593
  self.calculator.Show()
5220
5594
 
5595
+ elif itemlabel == _("Memory views..."):
5596
+ autoscale = False
5597
+
5598
+ if self.memory_views is None:
5599
+ self.memory_views = Memory_Views()
5600
+ self._memory_views_gui = Memory_Views_GUI(self, _('Memory view manager'), self.memory_views, mapviewer = self)
5601
+ else:
5602
+ if self._memory_views_gui is None:
5603
+ self._memory_views_gui = Memory_Views_GUI(self, _('Memory view manager'), self.memory_views, mapviewer = self)
5604
+
5605
+ self._memory_views_gui.Show()
5606
+
5221
5607
  elif itemlabel == _("Create bridge and export gltf..."):
5222
5608
  autoscale = False
5223
5609
 
wolfhece/PyPalette.py CHANGED
@@ -16,7 +16,7 @@ import numpy as np
16
16
  import numpy.ma as ma
17
17
  from bisect import bisect_left
18
18
  import matplotlib.pyplot as plt
19
- from matplotlib.colors import LinearSegmentedColormap, Normalize
19
+ from matplotlib.colors import LinearSegmentedColormap, Normalize, ListedColormap, BoundaryNorm
20
20
  from collections import OrderedDict
21
21
  import typing
22
22
  import io
@@ -207,6 +207,7 @@ class wolfpalette(wx.Frame, LinearSegmentedColormap):
207
207
  logging.warning('No values in palette - Nothing to do !')
208
208
  return None, None
209
209
 
210
+
210
211
  if fn == '':
211
212
  file = wx.FileDialog(None, "Choose .pal file", wildcard="png (*.png)|*.png|all (*.*)|*.*", style=wx.FD_SAVE)
212
213
  if file.ShowModal() == wx.ID_CANCEL:
@@ -220,14 +221,31 @@ class wolfpalette(wx.Frame, LinearSegmentedColormap):
220
221
  fig, ax = plt.subplots(1, 1)
221
222
  else:
222
223
  fig, ax = figax
223
- plt.colorbar(ScalarMappable(Normalize(self.values[0], self.values[-1]), cmap=self),
224
- cax=ax,
225
- orientation='vertical',
226
- extend='both',
227
- aspect=20,
228
- spacing='proportional',
229
- ticks=self.values,
230
- format='%.3f')
224
+
225
+ if self.interval_cst:
226
+ discrete_cmap = ListedColormap(self.colorsflt[:, :3])
227
+ colorbar = plt.colorbar(ScalarMappable(BoundaryNorm(self.values, ncolors=self.nb-1),
228
+ cmap=discrete_cmap),
229
+ cax=ax,
230
+ orientation='vertical',
231
+ extend='both',
232
+ aspect=20,
233
+ spacing='proportional',
234
+ ticks=self.values,
235
+ format='%.3f')
236
+
237
+ else:
238
+ plt.colorbar(ScalarMappable(Normalize(self.values[0],
239
+ self.values[-1]),
240
+ cmap=self),
241
+ cax=ax,
242
+ orientation='vertical',
243
+ extend='both',
244
+ aspect=20,
245
+ spacing='proportional',
246
+ ticks=self.values,
247
+ format='%.3f')
248
+
231
249
  plt.tick_params(labelsize=14)
232
250
  if figax is None:
233
251
  fig.set_size_inches((2, 10))
@@ -241,13 +259,27 @@ class wolfpalette(wx.Frame, LinearSegmentedColormap):
241
259
  fig, ax = plt.subplots(1, 1)
242
260
  else:
243
261
  fig, ax = figax
244
- plt.colorbar(ScalarMappable(Normalize(self.values[0], self.values[-1]), cmap=self),
245
- cax=ax,
246
- orientation='horizontal',
247
- extend='both',
248
- spacing='proportional',
249
- ticks=self.values,
250
- format='%.3f')
262
+
263
+ if self.interval_cst:
264
+ discrete_cmap = ListedColormap(self.colorsflt[:, :3])
265
+ colorbar = plt.colorbar(ScalarMappable(BoundaryNorm(self.values, ncolors=self.nb-1),
266
+ cmap=discrete_cmap),
267
+ cax=ax,
268
+ orientation='horizontal',
269
+ extend='both',
270
+ aspect=20,
271
+ spacing='proportional',
272
+ ticks=self.values,
273
+ format='%.3f')
274
+ else:
275
+ plt.colorbar(ScalarMappable(Normalize(self.values[0], self.values[-1]), cmap=self),
276
+ cax=ax,
277
+ orientation='horizontal',
278
+ extend='both',
279
+ spacing='proportional',
280
+ ticks=self.values,
281
+ format='%.3f')
282
+
251
283
  plt.tick_params(labelsize=14, rotation=45)
252
284
  if figax is None:
253
285
  fig.set_size_inches((2, 10))
@@ -264,13 +296,26 @@ class wolfpalette(wx.Frame, LinearSegmentedColormap):
264
296
  fig, ax = plt.subplots(1, 1)
265
297
  else:
266
298
  fig, ax = figax
267
- plt.colorbar(ScalarMappable(Normalize(self.values[0], self.values[-1]), cmap=self),
268
- cax=ax,
269
- orientation='vertical',
270
- extend='both',
271
- spacing='proportional',
272
- ticks=self.values,
273
- format='%.3f')
299
+
300
+ if self.interval_cst:
301
+ discrete_cmap = ListedColormap(self.colorsflt[:, :3])
302
+ colorbar = plt.colorbar(ScalarMappable(BoundaryNorm(self.values, ncolors=self.nb-1),
303
+ cmap=discrete_cmap),
304
+ cax=ax,
305
+ orientation='vertical',
306
+ extend='both',
307
+ aspect=20,
308
+ spacing='proportional',
309
+ ticks=self.values,
310
+ format='%.3f')
311
+ else:
312
+ plt.colorbar(ScalarMappable(Normalize(self.values[0], self.values[-1]), cmap=self),
313
+ cax=ax,
314
+ orientation='vertical',
315
+ extend='both',
316
+ spacing='proportional',
317
+ ticks=self.values,
318
+ format='%.3f')
274
319
  plt.tick_params(labelsize=14)
275
320
  fig.set_size_inches((2, 10))
276
321
  fig.tight_layout()
@@ -282,13 +327,25 @@ class wolfpalette(wx.Frame, LinearSegmentedColormap):
282
327
  else:
283
328
  fig, ax = figax
284
329
 
285
- plt.colorbar(ScalarMappable(Normalize(self.values[0], self.values[-1]), cmap=self),
286
- cax=ax,
287
- orientation='horizontal',
288
- extend='both',
289
- spacing='proportional',
290
- ticks=self.values,
291
- format='%.3f')
330
+ if self.interval_cst:
331
+ discrete_cmap = ListedColormap(self.colorsflt[:, :3])
332
+ colorbar = plt.colorbar(ScalarMappable(BoundaryNorm(self.values, ncolors=self.nb-1),
333
+ cmap=discrete_cmap),
334
+ cax=ax,
335
+ orientation='horizontal',
336
+ extend='both',
337
+ aspect=20,
338
+ spacing='proportional',
339
+ ticks=self.values,
340
+ format='%.3f')
341
+ else:
342
+ plt.colorbar(ScalarMappable(Normalize(self.values[0], self.values[-1]), cmap=self),
343
+ cax=ax,
344
+ orientation='horizontal',
345
+ extend='both',
346
+ spacing='proportional',
347
+ ticks=self.values,
348
+ format='%.3f')
292
349
  plt.tick_params(labelsize=14, rotation=45)
293
350
  fig.set_size_inches((10, 2))
294
351
  fig.tight_layout()
@@ -298,26 +355,38 @@ class wolfpalette(wx.Frame, LinearSegmentedColormap):
298
355
  return fig, ax
299
356
 
300
357
  def plot(self, fig: Figure, ax: plt.Axes):
358
+ """ Affichage de la palette de couleurs """
359
+
301
360
  gradient = np.linspace(0, 1, 256)
302
361
  gradient = np.vstack((gradient, gradient))
303
- ax.imshow(gradient, aspect='auto', cmap=self)
304
- ax.set_yticklabels([])
305
362
 
306
363
  pos = []
307
364
  txt = []
308
-
309
365
  dval = (self.values[-1]-self.values[0])
310
366
  if dval == 0.:
311
367
  dval = 1.
312
368
 
313
- for curval in self.values:
314
- pos.append((curval-self.values[0])/dval*256.)
315
- txt.append("{0:.3f}".format(curval))
369
+ if self.interval_cst:
370
+ discrete_cmap = ListedColormap(self.colorsflt[:, :3])
371
+ ax.imshow(gradient, aspect='auto', cmap=discrete_cmap)
372
+
373
+ for idx, curval in enumerate(self.values):
374
+ pos.append(idx/self.nb*256.)
375
+ txt.append("{0:.3f}".format(curval))
376
+ else:
377
+ ax.imshow(gradient, aspect='auto', cmap=self)
378
+
379
+ for curval in self.values:
380
+ pos.append((curval-self.values[0])/dval*256.)
381
+ txt.append("{0:.3f}".format(curval))
316
382
 
383
+ ax.set_yticklabels([])
317
384
  ax.set_xticks(pos)
318
385
  ax.set_xticklabels(txt, rotation=30, fontsize=6)
319
386
 
320
387
  def fillgrid(self, gridto: CpGrid):
388
+ """ Remplissage d'une grille avec les valeurs de la palette """
389
+
321
390
  gridto.SetColLabelValue(0, 'Value')
322
391
  gridto.SetColLabelValue(1, 'R')
323
392
  gridto.SetColLabelValue(2, 'G')
@@ -344,6 +413,8 @@ class wolfpalette(wx.Frame, LinearSegmentedColormap):
344
413
  k += 1
345
414
 
346
415
  def updatefromgrid(self, gridfrom: CpGrid):
416
+ """ Mise à jour de la palette sur base d'une grille """
417
+
347
418
  nbl = gridfrom.GetNumberRows()
348
419
 
349
420
  for i in range(nbl):
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 = 92
8
+ self.patch = 93
9
9
 
10
10
  def __str__(self):
11
11
 
wolfhece/pybridges.py CHANGED
@@ -35,7 +35,7 @@ class stored_values_unk(Enum):
35
35
  WATERLEVEL = (7, views_2D.WATERLEVEL.value)
36
36
  WATERSTAGE = (7, views_2D.WATERLEVEL.value)
37
37
  TOPOGRAPHY = (8, views_2D.TOPOGRAPHY.value)
38
- HEAD = (-1, _('Difference of waterlevel (up-down)'))
38
+ HEAD = (-1, views_2D.HEAD.value)
39
39
  DIFFERENCE_Z_UP_DOWN = (-1, _('Difference of waterlevel (up-down)'))
40
40
  DIFFERENCE_HEAD_UP_DOWN = (-1, _('Difference of head (up-down)'))
41
41
 
@@ -392,16 +392,25 @@ class Polygons_Analyze(Zones):
392
392
  self.linked:Union[dict,list] = None # type is depending on the type of linked arrays
393
393
  self.river_values:dict = None
394
394
 
395
+ # The riverbed axis is the second vector of the first zone
395
396
  self.riverbed = self.get_zone(0).myvectors[1]
396
397
  self.riverbed.prepare_shapely()
397
398
 
398
399
  self.polygons_zone:zone
399
400
  self.polygons_zone = self.get_zone(-1)
400
401
 
402
+ # The curvilinear distance of the polygons is stored in the 'z' attribute of the vertices
401
403
  self.polygons_curvi = {}
402
404
  for curvert in self.polygons_zone.myvectors:
403
405
  self.polygons_curvi[curvert.myname] = curvert.myvertices[0].z
404
406
 
407
+ # The mean center of the polygons
408
+ self.polygons_meanxy = {}
409
+ for curvert in self.polygons_zone.myvectors:
410
+ # Centre du polygone
411
+ centroid = curvert.asshapely_pol().centroid
412
+ self.polygons_meanxy[curvert.myname] = (centroid.x, centroid.y)
413
+
405
414
  for vec in self.polygons_zone.myvectors:
406
415
  vec.myprop.used=False # cache les polygones pour ne pas surcharger l'affichage éventuel
407
416
 
@@ -495,7 +504,9 @@ class Polygons_Analyze(Zones):
495
504
  locdict = self.river_values[curproj][curpoly][curgroup] = {}
496
505
 
497
506
  for cursim, curnparray in curarray.items():
498
- locdict[cursim] = np.array([np.array([ tuple(lst1), np.array(lst2, dtype= np.int32)], dtype=object ) for lst1, lst2 in curnparray], dtype=object)
507
+ vals = curnparray[0]
508
+ xy = curnparray[1]
509
+ locdict[cursim] = (np.array([np.array([ tuple(lst1), np.array(lst2, dtype= np.int32)], dtype=object ) for lst1, lst2 in vals], dtype=object), np.array(xy))
499
510
 
500
511
  elif isinstance(tmp_linked, list):
501
512
  self.linked = [(curlink[0], Wolfresults_2D if curlink[1] == 'CPU' else wolfres2DGPU) for curlink in tmp_linked]
@@ -508,7 +519,9 @@ class Polygons_Analyze(Zones):
508
519
  locdict = self.river_values[curpoly][curgroup] = {}
509
520
 
510
521
  for cursim, curnparray in curarray.items():
511
- locdict[cursim] = np.array([np.array([ tuple(lst1), np.array(lst2, dtype= np.int32)], dtype=object ) for lst1, lst2 in curnparray], dtype=object)
522
+ vals = curnparray[0]
523
+ xy = curnparray[1]
524
+ locdict[cursim] = (np.array([np.array([ tuple(lst1), np.array(lst2, dtype= np.int32)], dtype=object ) for lst1, lst2 in vals], dtype=object), np.array(xy))
512
525
 
513
526
 
514
527
  def compute_distance(self, poly:LineString | vector):
@@ -523,10 +536,8 @@ class Polygons_Analyze(Zones):
523
536
 
524
537
  for curvert in self.polygons_zone.myvectors:
525
538
  # Centre du polygone
526
- centerx = np.sum(np.asarray([cur.x for cur in curvert.myvertices[:4]]))/4.
527
- centery = np.sum(np.asarray([cur.y for cur in curvert.myvertices[:4]]))/4.
528
-
529
- self.polygons_curvi[curvert.myname] = poly.project(Point([centerx,centery]))
539
+ centroid = curvert.asshapely_pol().centroid
540
+ self.polygons_curvi[curvert.myname] = poly.project(Point([centroid.x, centroid.y]))
530
541
 
531
542
  def find_values_inside_parts(self, linked_arrays:Union[dict,list]):
532
543
  """
@@ -560,11 +571,11 @@ class Polygons_Analyze(Zones):
560
571
  if isinstance(linked_arrays, dict):
561
572
  self.river_values={}
562
573
  for curkey, curgroup in linked_arrays.items():
563
- self.river_values[curkey] = curzone.get_all_values_linked_polygon(curgroup, key_idx_names='name')
574
+ self.river_values[curkey] = curzone.get_all_values_linked_polygon(curgroup, key_idx_names='name', getxy=True)
564
575
 
565
576
  elif isinstance(linked_arrays, list):
566
577
 
567
- self.river_values = curzone.get_all_values_linked_polygon(linked_arrays, key_idx_names='name')
578
+ self.river_values = curzone.get_all_values_linked_polygon(linked_arrays, key_idx_names='name', getxy=True)
568
579
 
569
580
  def _get_river_heads(self, which_group= None):
570
581
  """Compute Head
@@ -586,7 +597,9 @@ class Polygons_Analyze(Zones):
586
597
  return head
587
598
 
588
599
  def get_river_values(self,
589
- which_value:Union[stored_values_unk,stored_values_pos],
600
+ which_value:Union[stored_values_unk,
601
+ stored_values_pos,
602
+ stored_values_coords],
590
603
  which_group=None) -> dict:
591
604
  """
592
605
  Get values for the river polygons
@@ -619,15 +632,35 @@ class Polygons_Analyze(Zones):
619
632
 
620
633
  create=False
621
634
  for curarray in curarrays.values():
622
- if len(curarray)>0:
623
- create=True
635
+ # if len(curarray)>0:
636
+ # create=True
637
+ if isinstance(curarray, tuple):
638
+ # on a également repris les coordonnées
639
+ if len(curarray[0])>0:
640
+ create=True
641
+ else:
642
+ if len(curarray)>0:
643
+ create=True
624
644
 
625
645
  if create:
626
646
  for idarray, curarray in enumerate(curarrays.values()):
627
- if len(curarray)>0:
628
- vallist = [curval[pos1][pos2] for curval in curarray]
629
- curdict[part_names[idarray][0]] = vallist
630
-
647
+ # if len(curarray)>0:
648
+ # vallist = [curval[pos1][pos2] for curval in curarray]
649
+ # curdict[part_names[idarray][0]] = vallist
650
+
651
+ if isinstance(curarray, tuple):
652
+ if pos1==-1:
653
+ if len(curarray[1])>0:
654
+ vallist = [curval[pos2] for curval in curarray[1]]
655
+ curdict[part_names[idarray][0]] = vallist
656
+ else:
657
+ if len(curarray[0])>0:
658
+ vallist = [curval[pos1][pos2] for curval in curarray[0]]
659
+ curdict[part_names[idarray][0]] = vallist
660
+ else:
661
+ if len(curarray)>0:
662
+ vallist = [curval[pos1][pos2] for curval in curarray]
663
+ curdict[part_names[idarray][0]] = vallist
631
664
  return locvalues
632
665
 
633
666
  if isinstance(self.linked, dict):
@@ -641,6 +674,9 @@ class Polygons_Analyze(Zones):
641
674
  elif which_value in stored_values_pos:
642
675
  values = fillin(1, which_value.value[0], self.river_values[which_group], self.linked[which_group])
643
676
  return values
677
+ elif which_value in stored_values_coords:
678
+ values = fillin(-1, which_value.value[0], self.river_values[which_group], self.linked[which_group])
679
+ return values
644
680
  else:
645
681
  return None
646
682
  else:
@@ -653,6 +689,8 @@ class Polygons_Analyze(Zones):
653
689
  values[curkey] = fillin(0, which_value.value[0], curgroup, curnames)
654
690
  elif which_value in stored_values_pos:
655
691
  values[curkey] = fillin(1, which_value.value[0], curgroup, curnames)
692
+ elif which_value in stored_values_coords:
693
+ values[curkey] = fillin(-1, which_value.value[0], curgroup, curnames)
656
694
  return values
657
695
  else:
658
696
  if which_value in stored_values_unk:
@@ -666,11 +704,15 @@ class Polygons_Analyze(Zones):
666
704
  elif which_value in stored_values_pos:
667
705
  values = fillin(1, which_value.value[0], self.river_values, self.linked)
668
706
  return values
707
+ elif which_value in stored_values_coords:
708
+ values = fillin(-1, which_value.value[0], self.river_values, self.linked)
669
709
  else:
670
710
  return None
671
711
 
672
712
  def get_river_values_op(self,
673
- which_value:Union[stored_values_unk,stored_values_pos],
713
+ which_value:Union[stored_values_unk,
714
+ stored_values_pos,
715
+ stored_values_coords],
674
716
  which_group=None,
675
717
  operator:operators=operators.MEDIAN) -> dict:
676
718
  """
@@ -741,10 +783,13 @@ class Polygons_Analyze(Zones):
741
783
  return ret
742
784
 
743
785
  def get_s_values(self,
744
- which_value:Union[stored_values_unk,stored_values_pos]=stored_values_unk.WATERLEVEL,
786
+ which_value:Union[stored_values_unk,
787
+ stored_values_pos,
788
+ stored_values_coords]=stored_values_unk.WATERLEVEL,
745
789
  which_group:str=None,
746
790
  which_sim:str=None,
747
791
  operator:operators=operators.MEDIAN):
792
+
748
793
  """ Get the values of the river polygons for a specific simulation
749
794
 
750
795
  :param which_value: value to get
@@ -763,6 +808,10 @@ class Polygons_Analyze(Zones):
763
808
  val.append(curval[which_sim])
764
809
  s.append(self.polygons_curvi[curkey])
765
810
 
811
+ if len(s) != len(val):
812
+ logging.error(_('Error in get_s_values'))
813
+ return [], []
814
+
766
815
  # Tri des valeurs selon l'absisse curviligne
767
816
  ret = sorted(zip(s, val))
768
817
 
@@ -771,6 +820,97 @@ class Polygons_Analyze(Zones):
771
820
 
772
821
  return s, val
773
822
 
823
+ def get_s_xy(self):
824
+ """ Get the centroids of the river polygons """
825
+
826
+ s = []
827
+ x = []
828
+ y = []
829
+
830
+ for curval in self.polygons_curvi.values():
831
+ s.append(curval)
832
+
833
+ for curval in self.polygons_meanxy.values():
834
+ x.append(curval[0])
835
+ y.append(curval[1])
836
+
837
+ if len(s) != len(x) or len(s) != len(y):
838
+ logging.error(_('Error in get_s_centroidsxy'))
839
+ return [], [], []
840
+
841
+ # Tri des valeurs selon l'absisse curviligne
842
+ ret = sorted(zip(s, x, y))
843
+
844
+ # Séparation des listes triées
845
+ s, x, y = zip(*ret)
846
+
847
+ return s, x, y
848
+
849
+ def get_s_xy4sim(self, which_group:str, which_sim:str, operator:operators=operators.MEDIAN):
850
+ """ Get the position for a specific simulation """
851
+
852
+ s1, x = self.get_s_values(which_value= stored_values_coords.X, which_group= which_group, which_sim= which_sim, operator= operator)
853
+ s2, y = self.get_s_values(which_value= stored_values_coords.Y, which_group= which_group, which_sim= which_sim, operator= operator)
854
+
855
+ assert s1 == s2, _('Error in get_s_xy4sim')
856
+
857
+ return s1, x, y
858
+
859
+ def save_xy_s_tofile(self, outputfile:str):
860
+ """ Save the centroids of the river polygons to a file """
861
+
862
+ s, x, y = self.get_s_xy()
863
+
864
+ with open(outputfile, 'w') as f:
865
+ f.write('x,y,s\n')
866
+ for curs, curx, cury in zip(s, x, y):
867
+ f.write('{0},{1},{2}\n'.format(curx, cury, curs))
868
+
869
+ def save_xy_s_tofile_4sim(self, outputfile:str, which_group:str, which_sim:str):
870
+ """ Save the centroids of the river polygons to a file """
871
+
872
+ s, x, y = self.get_s_xy4sim(which_group= which_group, which_sim= which_sim)
873
+
874
+ with open(outputfile, 'w') as f:
875
+ f.write('x,y,s\n')
876
+ for curs, curx, cury in zip(s, x, y):
877
+ f.write('{0},{1},{2}\n'.format(curx, cury, curs))
878
+
879
+ def export_as(self, outputfile:Path, unks:list[stored_values_unk | stored_values_coords], which_group:str, which_sim:str, operator:operators=operators.MEDIAN):
880
+ """ Export the values of the river polygons to a file
881
+
882
+ :param outputfile: output file (supported formats: csv, xlsx)
883
+ :param unks: list of values to export
884
+ :param which_group: group to export
885
+ :param which_sim: simulation to export
886
+ :param operator: operator to use for values (coordinates will be exported as MEDIAN)
887
+ """
888
+
889
+ outputfile = Path(outputfile)
890
+ if not (outputfile.suffix == '.csv' or outputfile.suffix == '.xlsx'):
891
+ logging.error(_('Unsupported format for export -- Must be csv or xlsx'))
892
+ return
893
+
894
+ import pandas as pd
895
+
896
+ s,x,y = self.get_s_xy4sim(which_group, which_sim, operators.MEDIAN)
897
+
898
+ vals = {curunk.value[1]:self.get_s_values(which_value= curunk,
899
+ which_group = which_group,
900
+ which_sim= which_sim,
901
+ operator= operator)[1] for curunk in unks}
902
+
903
+ cols_names = ['s [m]', 'x centroid [m]', 'y centroid [m]']
904
+ vals[cols_names[0]] = s
905
+ vals[cols_names[1]] = x
906
+ vals[cols_names[2]] = y
907
+
908
+ df = pd.DataFrame(vals, columns = [cur for cur in cols_names] + [curunk.value[1] for curunk in unks])
909
+
910
+ if outputfile.suffix == '.csv':
911
+ df.to_csv(outputfile, index=False)
912
+ elif outputfile.suffix == '.xlsx':
913
+ df.to_excel(outputfile, index=False)
774
914
 
775
915
  def plot_unk(self,
776
916
  figax = None,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wolfhece
3
- Version: 2.1.92
3
+ Version: 2.1.93
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,11 +7,11 @@ wolfhece/ManageParams.py,sha256=EeuUI5Vvh9ixCvYf8YShMC1s1Yacc7OxOCN7q81gqiQ,517
7
7
  wolfhece/Model1D.py,sha256=SI4oNF_J3MdjiWZoizS8kuRXLMVyymX9dYfYJNVCQVI,476989
8
8
  wolfhece/PyConfig.py,sha256=UNtl5UzZ399JqjJT67-4DWaIkv76sc1FiEsSDJpXlL0,10458
9
9
  wolfhece/PyCrosssections.py,sha256=FnmM9DWY_SAF2EDH9Gu2PojXNtSTRF4-aYQuAAJXBh4,112771
10
- wolfhece/PyDraw.py,sha256=-WHY2_slvEwaK2FilmI8oLRcXZGTk2pkBwDt1qd66zY,427847
10
+ wolfhece/PyDraw.py,sha256=KkqxUazcXhenwBVCE69EHd_lt0g9fiX6R4p3IBS2pnI,442172
11
11
  wolfhece/PyGui.py,sha256=HY0beOMSp1JEyq8-vfVynzVrmKxvaO_sJSMwlNqCNrg,105289
12
12
  wolfhece/PyGuiHydrology.py,sha256=f60E8K9eGTnRq5RDF6yvt-ahf2AYegwQ9t25zZ2Mk1A,14946
13
13
  wolfhece/PyHydrographs.py,sha256=jwtSNMMACwarxrtN1UeQYth99UNrhwPx1IGgUwcooHA,3774
14
- wolfhece/PyPalette.py,sha256=QCzXBnYlv7YfHjpJWyO_8F-uOLOe7O_RbkyrnMYzgM4,28146
14
+ wolfhece/PyPalette.py,sha256=81n1P-olOe4wElTLv-miSDhqvJU_RHcxgfpHt794dSw,31436
15
15
  wolfhece/PyParams.py,sha256=6fREK5cUCGw84SDyPvuSzidnX-9BXOX3fve5XBG1K_I,98114
16
16
  wolfhece/PyPictures.py,sha256=m1kY0saW6Y9Q0bDCo47lW6XxDkBrbQG-Fd8uVn8G5ic,2514
17
17
  wolfhece/PyTranslate.py,sha256=4appkmNeHHZLFmUtaA_k5_5QL-5ymxnbVN4R2OblmtE,622
@@ -38,10 +38,10 @@ wolfhece/ismember.py,sha256=fkLvaH9fhx-p0QrlEzqa6ySO-ios3ysjAgXVXzLgSpY,2482
38
38
  wolfhece/multiprojects.py,sha256=Sd6Bl6YP33jlR79A6rvSLu23vq8sqbFYL8lWuVPkEpE,21549
39
39
  wolfhece/picc.py,sha256=ueujnw03BQz-nPxKGzfDzZbtruTzvnqd6Gm8lOvBYzw,8802
40
40
  wolfhece/pyGui1D.py,sha256=9g7OS3YiKsqy--6y0cBD7x2gaqTTYFXWkxImpgnTA20,121937
41
- wolfhece/pybridges.py,sha256=xbZPuX40c4EKqws4OKNbUVUBPKIzLTbSdYVyrNf_kIE,57418
41
+ wolfhece/pybridges.py,sha256=EU_r6yRYDf5zKmwwXEBsGYvTKFbSfE3iTxPwusKR-1I,57398
42
42
  wolfhece/pydike.py,sha256=hPBQsmSTW4QAp1wcOzb-TL3L7eet2WT1sJx2q-WNQ-Q,2241
43
43
  wolfhece/pylogging.py,sha256=4TI8hgBB65z-zpvU5Rfa2jkPXPhJaqXjHVPwbcdzTNc,4528
44
- wolfhece/pypolygons_scen.py,sha256=C0qxVUsBHWZVkurZV-DI1GMN1J1B-ul93n2fs16UjoI,39718
44
+ wolfhece/pypolygons_scen.py,sha256=vMfAKXKrW6vKR7l9Fl2hEt-jihLwIiMur7qNTNfwRg4,46101
45
45
  wolfhece/pyshields.py,sha256=6YncgmcA6QvbyIl4jbFRf24uJVjhiSplQKWtZH42lXI,24108
46
46
  wolfhece/pyviews.py,sha256=5Hqqo9MRw1eiomYkmc7QywNu1KmEkytLJG-wH_aG38Y,13748
47
47
  wolfhece/pywalous.py,sha256=yRaWJjKckXef1d9D5devP0yFHC9uc6kRV4G5x9PNq9k,18972
@@ -75,7 +75,7 @@ wolfhece/apps/curvedigitizer.py,sha256=Yps4bcayzbsz0AoVc_dkSk35dEhhn_esIBy1Ziefg
75
75
  wolfhece/apps/hydrometry.py,sha256=lhhJsFeb4zGL4bNQTs0co85OQ_6ssL1Oy0OUJCzhfYE,656
76
76
  wolfhece/apps/isocurrent.py,sha256=dagmGR8ja9QQ1gwz_8fU-N052hIw-W0mWGVkzLu6C7I,4247
77
77
  wolfhece/apps/splashscreen.py,sha256=SrustmIQeXnsiD-92OzjdGhBi-S7c_j-cSvuX4T6rtg,2929
78
- wolfhece/apps/version.py,sha256=_TUgNtGFMedLigBPzswBYH6ZQUUs5BrsfxgN7xUDxWI,388
78
+ wolfhece/apps/version.py,sha256=uhn_xV3CTGZbQdI3Z2ZnOh4S6W8nowYt7Tj4x2XrHlo,388
79
79
  wolfhece/apps/wolf.py,sha256=j_CgvsL8rwixbVvVD5Z0s7m7cHZ86gmFLojKGuetMls,729
80
80
  wolfhece/apps/wolf2D.py,sha256=4z_OPQ3IgaLtjexjMKX9ppvqEYyjFLt1hcfFABy3-jU,703
81
81
  wolfhece/apps/wolf_logo.bmp,sha256=ruJ4MA51CpGO_AYUp_dB4SWKHelvhOvd7Q8NrVOjDJk,3126
@@ -285,8 +285,8 @@ wolfhece/ui/wolf_multiselection_collapsiblepane.py,sha256=8PlMYrb_8jI8h9F0_EagpM
285
285
  wolfhece/ui/wolf_times_selection_comparison_models.py,sha256=ORy7fz4dcp691qKzaOZHrRLZ0uXNhL-LIHxmpDGL6BI,5007
286
286
  wolfhece/wintab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
287
287
  wolfhece/wintab/wintab.py,sha256=8A-JNONV6ujgsgG3lM5Uw-pVgglPATwKs86oBzzljoc,7179
288
- wolfhece-2.1.92.dist-info/METADATA,sha256=B4LcZnRdMaSUQCv2aRIMVjVyH07wlmRL60l-8kWXXck,2548
289
- wolfhece-2.1.92.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
290
- wolfhece-2.1.92.dist-info/entry_points.txt,sha256=ZZ-aSfbpdcmo-wo84lRFzBN7LaSnD1XRGSaAKVX-Gpc,522
291
- wolfhece-2.1.92.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
292
- wolfhece-2.1.92.dist-info/RECORD,,
288
+ wolfhece-2.1.93.dist-info/METADATA,sha256=Rws7W6QN1NdDV2S30eXAeX-vTVauNTaWIzCTfEzkOpk,2548
289
+ wolfhece-2.1.93.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
290
+ wolfhece-2.1.93.dist-info/entry_points.txt,sha256=ZZ-aSfbpdcmo-wo84lRFzBN7LaSnD1XRGSaAKVX-Gpc,522
291
+ wolfhece-2.1.93.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
292
+ wolfhece-2.1.93.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.0.0)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5