wolfhece 2.2.17__py3-none-any.whl → 2.2.20__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/wolf_array.py CHANGED
@@ -2097,7 +2097,19 @@ class Ops_Array(wx.Frame):
2097
2097
 
2098
2098
  self.labelling = wx.Button(self.tools, wx.ID_ANY, _("Labelling"), wx.DefaultPosition,wx.DefaultSize, 0)
2099
2099
 
2100
+ stats_sizer = wx.BoxSizer(wx.HORIZONTAL)
2101
+ stats_sizer2 = wx.BoxSizer(wx.HORIZONTAL)
2102
+
2100
2103
  self.statistics = wx.Button(self.tools, wx.ID_ANY, _("Statistics"), wx.DefaultPosition,wx.DefaultSize, 0)
2104
+ self.plot_stats = wx.Button(self.tools, wx.ID_ANY, _("Plot statistics\nCurrent zoom"), wx.DefaultPosition,wx.DefaultSize, 0)
2105
+ self.plot_stats_zone = wx.Button(self.tools, wx.ID_ANY, _("Plot statistics\nCurrent zone"), wx.DefaultPosition,wx.DefaultSize, 0)
2106
+ self.plot_stats_vector = wx.Button(self.tools, wx.ID_ANY, _("Plot statistics\nCurrent vector"), wx.DefaultPosition,wx.DefaultSize, 0)
2107
+
2108
+ stats_sizer.Add(self.statistics, 1, wx.EXPAND)
2109
+ stats_sizer.Add(self.plot_stats, 1, wx.EXPAND)
2110
+
2111
+ stats_sizer2.Add(self.plot_stats_zone, 1, wx.EXPAND)
2112
+ stats_sizer2.Add(self.plot_stats_vector, 1, wx.EXPAND)
2101
2113
 
2102
2114
  self.clean = wx.Button(self.tools, wx.ID_ANY, _("Clean"), wx.DefaultPosition,wx.DefaultSize, 0)
2103
2115
 
@@ -2117,7 +2129,8 @@ class Ops_Array(wx.Frame):
2117
2129
  Toolssizer.Add(self.labelling, 1, wx.EXPAND)
2118
2130
  Toolssizer.Add(self.clean, 1, wx.EXPAND)
2119
2131
  Toolssizer.Add(self.extract_selection, 1, wx.EXPAND)
2120
- Toolssizer.Add(self.statistics, 1, wx.EXPAND)
2132
+ Toolssizer.Add(stats_sizer, 1, wx.EXPAND)
2133
+ Toolssizer.Add(stats_sizer2, 1, wx.EXPAND)
2121
2134
  Toolssizer.Add(cont_sizer, 1, wx.EXPAND)
2122
2135
 
2123
2136
  self.ApplyTools.SetToolTip(_("Apply Nullvalue into memory/object"))
@@ -2127,6 +2140,7 @@ class Ops_Array(wx.Frame):
2127
2140
  self.clean.SetToolTip(_("Clean the array\n\nRemove small isolated patches of data"))
2128
2141
  self.extract_selection.SetToolTip(_("Extract the current selection"))
2129
2142
  self.statistics.SetToolTip(_("Compute statistics on the array\n\nResults are displayed in a dialog box"))
2143
+ self.plot_stats.SetToolTip(_("Plot statistics on the array\n\nResults are displayed in a separate figure"))
2130
2144
 
2131
2145
  self.tools.SetSizer(Toolssizer)
2132
2146
  self.tools.Layout()
@@ -2500,6 +2514,9 @@ class Ops_Array(wx.Frame):
2500
2514
  self.clean.Bind(wx.EVT_BUTTON, self.OnClean)
2501
2515
  self.labelling.Bind(wx.EVT_BUTTON, self.OnLabelling)
2502
2516
  self.statistics.Bind(wx.EVT_BUTTON, self.OnStatistics)
2517
+ self.plot_stats.Bind(wx.EVT_BUTTON, self.OnPlotStatistics)
2518
+ self.plot_stats_zone.Bind(wx.EVT_BUTTON, self.OnPlotStatisticsZone)
2519
+ self.plot_stats_vector.Bind(wx.EVT_BUTTON, self.OnPlotStatisticsVector)
2503
2520
  self.extract_selection.Bind(wx.EVT_BUTTON, self.OnExtractSelection)
2504
2521
  self._contour_int.Bind(wx.EVT_BUTTON, self.OnContourInt)
2505
2522
  self._contour_list.Bind(wx.EVT_BUTTON, self.OnContourList)
@@ -3008,6 +3025,86 @@ class Ops_Array(wx.Frame):
3008
3025
 
3009
3026
  ret_frame.Show()
3010
3027
 
3028
+ def OnPlotStatistics(self, event:wx.MouseEvent):
3029
+ """ Plot statistics on the current zoom"""
3030
+
3031
+ from .analyze_poly import Array_analysis_onepolygon
3032
+
3033
+ logging.info(_('Plotting statistics on the current zoom'))
3034
+ if self.parentarray.nbnotnull > 50_000:
3035
+ logging.info(_('Quite large array - please wait a bit...'))
3036
+
3037
+ analyzer = Array_analysis_onepolygon(self.parentarray, self.mapviewer.get_bounds_as_polygon())
3038
+
3039
+ try:
3040
+ analyzer.plot_values(engine = 'plotly')
3041
+ except:
3042
+ logging.error(_('Error in plotly engine - Try seaborn engine'))
3043
+ logging.info(_('If you have not installed plotly, please install it with "pip install plotly"'))
3044
+ try:
3045
+ analyzer.plot_values(engine = 'seaborn')
3046
+ except:
3047
+ logging.error('Error in seaborn engine')
3048
+
3049
+ logging.info(_('Done !'))
3050
+
3051
+ def OnPlotStatisticsZone(self, event:wx.MouseEvent):
3052
+ """ Plot statistics on the current zone """
3053
+
3054
+ if self.mapviewer is not None:
3055
+ if self.mapviewer.active_zone is not None:
3056
+ from .analyze_poly import Array_analysis_polygons
3057
+
3058
+ logging.info(_('Plotting statistics on the current zone'))
3059
+
3060
+ analyzer = Array_analysis_polygons(self.parentarray, self.mapviewer.active_zone)
3061
+ try:
3062
+ analyzer.plot_values(engine = 'plotly')
3063
+ except:
3064
+ logging.error(_('Error in plotly engine - Try seaborn engine'))
3065
+ logging.info(_('If you have not installed plotly, please install it with "pip install plotly"'))
3066
+ try:
3067
+ analyzer.plot_values(engine = 'seaborn')
3068
+ except:
3069
+ logging.error('Error in seaborn engine')
3070
+
3071
+ logging.info(_('Done !'))
3072
+
3073
+ else:
3074
+ logging.error(_('No active zone to plot statistics'))
3075
+ logging.info(_('Please select a zone to plot statistics'))
3076
+ else:
3077
+ logging.error(_('No active mapviewer to plot statistics'))
3078
+
3079
+ def OnPlotStatisticsVector(self, event:wx.MouseEvent):
3080
+ """ Plot statistics on the current vector """
3081
+
3082
+ if self.mapviewer is not None:
3083
+ if self.mapviewer.active_vector is not None:
3084
+ from .analyze_poly import Array_analysis_onepolygon
3085
+
3086
+ logging.info(_('Plotting statistics on the current vector'))
3087
+
3088
+ # Get the active vector
3089
+ analyzer = Array_analysis_onepolygon(self.parentarray, self.mapviewer.active_vector)
3090
+ try:
3091
+ analyzer.plot_values(engine = 'plotly')
3092
+ except:
3093
+ logging.error(_('Error in plotly engine - Try seaborn engine'))
3094
+ logging.info(_('If you have not installed plotly, please install it with "pip install plotly"'))
3095
+ try:
3096
+ analyzer.plot_values(engine = 'seaborn')
3097
+ except:
3098
+ logging.error('Error in seaborn engine')
3099
+
3100
+ logging.info(_('Done !'))
3101
+
3102
+ else:
3103
+ logging.error(_('No active vector to plot statistics'))
3104
+ logging.info(_('Please select a vector to plot statistics'))
3105
+ else:
3106
+ logging.error(_('No active mapviewer to plot statistics'))
3107
+
3011
3108
  def OnExtractSelection(self, event:wx.MouseEvent):
3012
3109
  """ Extract the current selection """
3013
3110
 
@@ -4953,7 +5050,10 @@ class SelectionData():
4953
5050
  self.myselection = 'all'
4954
5051
  self.update_nb_nodes_selection()
4955
5052
 
4956
- def interp2Dpolygons(self, working_zone:zone, method:Literal["nearest", "linear", "cubic"] = None, resetplot:bool = True):
5053
+ def interp2Dpolygons(self, working_zone:zone,
5054
+ method:Literal["nearest", "linear", "cubic"] = None,
5055
+ resetplot:bool = True,
5056
+ keep:Literal['all', 'below', 'above'] = 'all'):
4957
5057
  """
4958
5058
  Interpolation sous tous les polygones d'une zone
4959
5059
  cf parent.interp2Dpolygon
@@ -4970,12 +5070,15 @@ class SelectionData():
4970
5070
  method = dlg.GetStringSelection()
4971
5071
  dlg.Destroy()
4972
5072
 
4973
- self.parent.interpolate_on_polygons(working_zone, method)
5073
+ self.parent.interpolate_on_polygons(working_zone, method, keep)
4974
5074
 
4975
5075
  if resetplot:
4976
5076
  self.parent.reset_plot()
4977
5077
 
4978
- def interp2Dpolygon(self, working_vector:vector, method:Literal["nearest", "linear", "cubic"] = None, resetplot:bool = True):
5078
+ def interp2Dpolygon(self, working_vector:vector,
5079
+ method:Literal["nearest", "linear", "cubic"] = None,
5080
+ resetplot:bool = True,
5081
+ keep:Literal['all', 'below', 'above'] = 'all'):
4979
5082
  """
4980
5083
  Interpolation sous un polygone
4981
5084
  cf parent.interp2Dpolygon
@@ -4992,7 +5095,7 @@ class SelectionData():
4992
5095
  method = dlg.GetStringSelection()
4993
5096
  dlg.Destroy()
4994
5097
 
4995
- self.parent.interpolate_on_polygon(working_vector, method)
5098
+ self.parent.interpolate_on_polygon(working_vector, method, keep)
4996
5099
 
4997
5100
  if resetplot:
4998
5101
  self.parent.reset_plot()
@@ -5232,7 +5335,10 @@ class SelectionDataMB(SelectionData):
5232
5335
 
5233
5336
  logging.error(_('Not yet implemented for Multi-Blocks'))
5234
5337
 
5235
- def interp2Dpolygons(self, working_zone:zone, method:Literal["nearest", "linear", "cubic"] = None):
5338
+ def interp2Dpolygons(self, working_zone:zone,
5339
+ method:Literal["nearest", "linear", "cubic"] = None,
5340
+ resetplot:bool = True,
5341
+ keep:Literal['all', 'below', 'above'] = 'all'):
5236
5342
  """
5237
5343
  Interpolation sous tous les polygones d'une zone
5238
5344
  cf parent.interp2Dpolygon
@@ -5249,11 +5355,15 @@ class SelectionDataMB(SelectionData):
5249
5355
  method = dlg.GetStringSelection()
5250
5356
  dlg.Destroy()
5251
5357
 
5252
- self.parent.interpolate_on_polygons(working_zone, method)
5358
+ self.parent.interpolate_on_polygons(working_zone, method, keep)
5253
5359
 
5254
- self.parent.reset_plot()
5360
+ if resetplot:
5361
+ self.parent.reset_plot()
5255
5362
 
5256
- def interp2Dpolygon(self, working_vector:vector, method:Literal["nearest", "linear", "cubic"] = None):
5363
+ def interp2Dpolygon(self, working_vector:vector,
5364
+ method:Literal["nearest", "linear", "cubic"] = None,
5365
+ resetplot:bool = True,
5366
+ keep:Literal['all', 'below', 'above'] = 'all'):
5257
5367
  """
5258
5368
  Interpolation sous un polygone
5259
5369
  cf parent.interp2Dpolygon
@@ -5270,9 +5380,10 @@ class SelectionDataMB(SelectionData):
5270
5380
  method = dlg.GetStringSelection()
5271
5381
  dlg.Destroy()
5272
5382
 
5273
- self.parent.interpolate_on_polygon(working_vector, method)
5383
+ self.parent.interpolate_on_polygon(working_vector, method, keep)
5274
5384
 
5275
- self.parent.reset_plot()
5385
+ if resetplot:
5386
+ self.parent.reset_plot()
5276
5387
 
5277
5388
  def interp2Dpolylines(self, working_zone:zone, resetplot:bool = True):
5278
5389
  """
@@ -5529,6 +5640,24 @@ class WolfArray(Element_To_Draw, header_wolf):
5529
5640
 
5530
5641
  self.add_ops_sel() # Ajout d'un gestionnaire de sélection et d'opérations
5531
5642
 
5643
+ def __getstate__(self):
5644
+ """ Récupération de l'état de l'objet pour la sérialisation """
5645
+ state = self.__dict__.copy()
5646
+
5647
+ # Remove the OpenGL reference to avoid bad references
5648
+ if 'mygrid' in state:
5649
+ state['mygrid'] = {}
5650
+ """ If not empty, the OpenGL list is not properly serialized.
5651
+ During "delete_lists" routine, tghe OpenGL can produce an error.
5652
+ """
5653
+ if 'shaded' in state:
5654
+ state['shaded'] = None # Avoid serializing the shaded WolfArray
5655
+ return state
5656
+
5657
+ def __setstate__(self, state):
5658
+ """ Récupération de l'état de l'objet pour la désérialisation """
5659
+ self.__dict__.update(state)
5660
+
5532
5661
  def set_opacity(self, alpha:float):
5533
5662
  """ Set the transparency of the array """
5534
5663
 
@@ -6124,17 +6253,17 @@ class WolfArray(Element_To_Draw, header_wolf):
6124
6253
 
6125
6254
  if inside_polygon is not None:
6126
6255
  ij = self.get_ij_inside_polygon(inside_polygon)
6127
- vals = self.array[ij]
6256
+ vals = self.array[ij[:,0], ij[:,1]]
6128
6257
  elif self.SelectionData.nb == 0 or self.SelectionData.myselection == 'all':
6129
6258
  logging.info(_('No selection -- statistics on the whole array'))
6130
- vals = self.array[~self.array.mask] # all values
6259
+ vals = self.array[~self.array.mask].ravel().data # all values
6131
6260
  else:
6132
6261
  vals = self.SelectionData.get_values_sel()
6133
6262
 
6134
- mean = np.mean(vals)
6135
- std = np.std(vals)
6136
- median = np.median(vals)
6137
- sum = np.sum(vals)
6263
+ mean = np.ma.mean(vals)
6264
+ std = np.ma.std(vals)
6265
+ median = np.ma.median(vals)
6266
+ sum = np.ma.sum(vals)
6138
6267
  vol = sum * self.dx * self.dy
6139
6268
 
6140
6269
  return {_('Mean'): mean, _('Std'): std, _('Median'): median, _('Sum'): sum, _('Volume'): vol, _('Values'): vals}
@@ -6806,7 +6935,9 @@ class WolfArray(Element_To_Draw, header_wolf):
6806
6935
 
6807
6936
  plt.show()
6808
6937
 
6809
- def interpolate_on_polygon(self, working_vector: vector, method:Literal["nearest", "linear", "cubic"]="linear"):
6938
+ def interpolate_on_polygon(self, working_vector: vector,
6939
+ method:Literal["nearest", "linear", "cubic"]="linear",
6940
+ keep:Literal['all', 'below', 'above'] = 'all'):
6810
6941
  """
6811
6942
  Interpolation sous un polygone
6812
6943
 
@@ -6818,6 +6949,14 @@ class WolfArray(Element_To_Draw, header_wolf):
6818
6949
  depuis les vertices 3D du polygone
6819
6950
  """
6820
6951
 
6952
+ if keep not in ['all', 'below', 'above']:
6953
+ logging.error(_('keep must be "all", "below" or "above"'))
6954
+ raise ValueError
6955
+
6956
+ if method not in ['nearest', 'linear', 'cubic']:
6957
+ logging.error(_('method must be "nearest", "linear" or "cubic"'))
6958
+ raise ValueError
6959
+
6821
6960
  if self.mngselection is None:
6822
6961
  destxy = self.get_xy_inside_polygon(working_vector)
6823
6962
  if len(destxy)==0:
@@ -6841,6 +6980,9 @@ class WolfArray(Element_To_Draw, header_wolf):
6841
6980
  else:
6842
6981
  destxy = self.SelectionData.myselection
6843
6982
 
6983
+ # if isinstance(destxy, list):
6984
+ # destxy = np.asarray(destxy)
6985
+
6844
6986
  if len(destxy)==0:
6845
6987
  logging.debug(_('No points to interpolate'))
6846
6988
  return
@@ -6851,7 +6993,13 @@ class WolfArray(Element_To_Draw, header_wolf):
6851
6993
 
6852
6994
  newvalues = griddata(xyz[:, :2], xyz[:, 2], destxy, method=method, fill_value=-99999.)
6853
6995
 
6854
- locmask = np.where(newvalues != -99999.)
6996
+ if keep == 'all':
6997
+ locmask = np.where(newvalues != -99999.)
6998
+ elif keep == 'below':
6999
+ locmask = np.where((newvalues != -99999.) & (newvalues < self.array.data[destij[:, 0], destij[:, 1]]))
7000
+ elif keep == 'above':
7001
+ locmask = np.where((newvalues != -99999.) & (newvalues > self.array.data[destij[:, 0], destij[:, 1]]))
7002
+
6855
7003
  self.array.data[destij[locmask][:, 0], destij[locmask][:, 1]] = newvalues[locmask]
6856
7004
 
6857
7005
  def rasterize_vector_valuebyid(self, working_vector: vector, id,
@@ -6910,14 +7058,16 @@ class WolfArray(Element_To_Draw, header_wolf):
6910
7058
  for curzone in working_zones.myzones:
6911
7059
  self.rasterize_zone_valuebyid(curzone, id, method)
6912
7060
 
6913
- def interpolate_on_polygons(self, working_zone:zone, method:Literal["nearest", "linear", "cubic"]="linear"):
7061
+ def interpolate_on_polygons(self, working_zone:zone,
7062
+ method:Literal["nearest", "linear", "cubic"]="linear",
7063
+ keep:Literal['all', 'below', 'above'] = 'all'):
6914
7064
  """
6915
7065
  Interpolation sous plusieurs polygones d'une même zone
6916
7066
 
6917
7067
  """
6918
7068
 
6919
7069
  for curvec in working_zone.myvectors:
6920
- self.interpolate_on_polygon(curvec, method)
7070
+ self.interpolate_on_polygon(curvec, method, keep)
6921
7071
 
6922
7072
  def interpolate_on_polyline(self, working_vector:vector, usemask=True):
6923
7073
  """
@@ -6994,7 +7144,9 @@ class WolfArray(Element_To_Draw, header_wolf):
6994
7144
 
6995
7145
  def interpolate_on_triangulation(self, coords, triangles,
6996
7146
  grid_x=None, grid_y = None,
6997
- mask_tri=None, interp_method:Literal['matplotlib','scipy'] = 'matplotlib'):
7147
+ mask_tri=None,
7148
+ interp_method:Literal['matplotlib','scipy'] = 'matplotlib',
7149
+ keep:Literal['all', 'below', 'above'] = 'all'):
6998
7150
  """
6999
7151
  Interpolation sur une triangulation.
7000
7152
 
@@ -7003,7 +7155,8 @@ class WolfArray(Element_To_Draw, header_wolf):
7003
7155
  - dans les mailles contenues dans la triangulation sinon
7004
7156
 
7005
7157
  Matplotlib is used by default, but Scipy(griddata) can be used as well. If Matplotlib crashes, try with Scipy.
7006
- Matplotlib is more strict on the quality of the triangulation.
7158
+
7159
+ **Matplotlib is more strict on the quality of the triangulation.**
7007
7160
 
7008
7161
  :param coords: numpy.array of vertices - shape (n,3)
7009
7162
  :param triangles: numpy.array of triangles - shape (m,3)
@@ -7011,6 +7164,7 @@ class WolfArray(Element_To_Draw, header_wolf):
7011
7164
  :param grid_y: numpy.array of y values where the interpolation will be done -- if None, the grid is created from the array
7012
7165
  :param mask_tri: numpy.array of mask for the triangles
7013
7166
  :param interp_method: method for the interpolation -- 'matplotlib' or 'scipy'
7167
+ :param keep: 'all' to keep all values, 'below' to keep only values below the current array, 'above' to keep only values above the current array
7014
7168
 
7015
7169
  For matplotlib algo, see : https://matplotlib.org/stable/gallery/images_contours_and_fields/triinterp_demo.html
7016
7170
  For scipy algo, see : https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.griddata.html
@@ -7019,6 +7173,7 @@ class WolfArray(Element_To_Draw, header_wolf):
7019
7173
 
7020
7174
 
7021
7175
  if interp_method =='matplotlib':
7176
+ # FIXME : This part could be optimized, I think
7022
7177
 
7023
7178
  import matplotlib.tri as mtri
7024
7179
 
@@ -7027,6 +7182,9 @@ class WolfArray(Element_To_Draw, header_wolf):
7027
7182
  try:
7028
7183
  if self.mngselection is not None:
7029
7184
  if self.mngselection.myselection != [] and self.mngselection.myselection != 'all':
7185
+ # interpolation only in the selected cells
7186
+
7187
+ # Convert coordinates to indices
7030
7188
  ij = np.asarray([self.get_ij_from_xy(x, y) for x, y in self.mngselection.myselection])
7031
7189
 
7032
7190
  try:
@@ -7037,17 +7195,60 @@ class WolfArray(Element_To_Draw, header_wolf):
7037
7195
  interplin = mtri.LinearTriInterpolator(triang, coords[:,2]) # Interpolation et récupération dans le numpy.array de l'objet Wolf
7038
7196
  except:
7039
7197
  raise Warning(_('Bad triangulation - try with another method like Scipy'))
7198
+
7040
7199
  newvalues = np.ma.masked_array([interplin(x, y) for x, y in self.mngselection.myselection])
7041
7200
 
7042
- ij = ij[np.where(~newvalues.mask)]
7043
- self.array.data[ij[:, 0], ij[:, 1]] = newvalues.data[np.where(~newvalues.mask)]
7201
+ if newvalues.mask.shape!=():
7202
+ # We have a mask
7203
+
7204
+ nonmasked_values = np.where(~newvalues.mask)
7205
+ ij = ij[nonmasked_values]
7206
+ newvalues = newvalues[nonmasked_values]
7207
+
7208
+ if keep == 'below':
7209
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data[ij[:, 0], ij[:, 1]]))
7210
+
7211
+ nonmasked_values = np.where(~newvalues.mask)
7212
+ ij = ij[np.where(~newvalues.mask)]
7213
+ newvalues = newvalues[nonmasked_values]
7214
+
7215
+ elif keep == 'above':
7216
+ newvalues = np.ma.masked_array(newvalues[nonmasked_values], mask=(newvalues[nonmasked_values] < self.array.data[ij[:, 0], ij[:, 1]]))
7217
+
7218
+ nonmasked_values = np.where(~newvalues.mask)
7219
+ ij = ij[np.where(~newvalues.mask)]
7220
+ newvalues = newvalues[nonmasked_values]
7221
+
7222
+ self.array.data[ij[:, 0], ij[:, 1]] = newvalues
7223
+ else:
7224
+ # No mask --> boolean
7225
+
7226
+ if keep == 'below':
7227
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data[ij[:, 0], ij[:, 1]]))
7228
+
7229
+ nonmasked_values = np.where(~newvalues.mask)
7230
+ ij = ij[np.where(~newvalues.mask)]
7231
+ newvalues = newvalues[nonmasked_values]
7232
+
7233
+ elif keep == 'above':
7234
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues < self.array.data[ij[:, 0], ij[:, 1]]))
7235
+
7236
+ nonmasked_values = np.where(~newvalues.mask)
7237
+ ij = ij[np.where(~newvalues.mask)]
7238
+ newvalues = newvalues[nonmasked_values]
7239
+
7240
+ self.array.data[ij[:, 0], ij[:, 1]] = newvalues
7044
7241
 
7045
7242
  elif self.mngselection.myselection == 'all' and (grid_x is None and grid_y is None):
7243
+ # interpolation in all the cells
7244
+
7245
+ # Creating a grid for all cells
7046
7246
  decalx = self.origx + self.translx
7047
7247
  decaly = self.origy + self.transly
7048
7248
  x = np.arange(self.dx / 2. + decalx, float(self.nbx) * self.dx + self.dx / 2 + decalx, self.dx)
7049
7249
  y = np.arange(self.dy / 2. + decaly, float(self.nby) * self.dy + self.dy / 2 + decaly, self.dy)
7050
7250
  grid_x, grid_y = np.meshgrid(x, y, indexing='ij')
7251
+ grid_ij = self.xy2ij_np(np.concatenate([grid_x.ravel()[:, np.newaxis], grid_y.ravel()[:, np.newaxis]], axis=1))
7051
7252
 
7052
7253
  try:
7053
7254
  # Opérateur d'interpolation linéaire
@@ -7057,11 +7258,32 @@ class WolfArray(Element_To_Draw, header_wolf):
7057
7258
  interplin = mtri.LinearTriInterpolator(triang, coords[:,2])
7058
7259
  except:
7059
7260
  raise Warning(_('Bad triangulation - try with another method like Scipy'))
7261
+
7060
7262
  # Interpolation et récupération dans le numpy.array de l'objet Wolf
7061
- newvalues = interplin(grid_x,grid_y).astype(np.float32)
7062
- self.array.data[~newvalues.mask] = newvalues[~newvalues.mask]
7263
+ newvalues = interplin(grid_x,grid_y)
7264
+
7265
+ nonmasked_values = np.where(~newvalues.mask)
7266
+ ij = grid_ij[nonmasked_values]
7267
+ newvalues = newvalues[nonmasked_values]
7268
+
7269
+ if keep == 'below':
7270
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data[grid_ij[:, 0], grid_ij[:, 1]]))
7271
+
7272
+ nonmasked_values = np.where(~newvalues.mask)
7273
+ ij = grid_ij[nonmasked_values]
7274
+ newvalues = newvalues[nonmasked_values]
7275
+
7276
+ elif keep == 'above':
7277
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues < self.array.data[grid_ij[:, 0], grid_ij[:, 1]]))
7278
+
7279
+ nonmasked_values = np.where(~newvalues.mask)
7280
+ ij = grid_ij[nonmasked_values]
7281
+ newvalues = newvalues[nonmasked_values]
7282
+
7283
+ self.array.data[ij[:, 0], ij[:, 1]] = newvalues
7284
+
7063
7285
  elif (grid_x is not None and grid_y is not None):
7064
- ij = np.asarray([self.get_ij_from_xy(x, y) for x, y in zip(grid_x.flatten(),grid_y.flatten())])
7286
+ # Working on an imposed grid
7065
7287
 
7066
7288
  # Opérateur d'interpolation linéaire
7067
7289
  try:
@@ -7069,16 +7291,56 @@ class WolfArray(Element_To_Draw, header_wolf):
7069
7291
  if mask_tri is not None:
7070
7292
  triang.set_mask(mask_tri)
7071
7293
  interplin = mtri.LinearTriInterpolator(triang, coords[:,2]) # Interpolation et récupération dans le numpy.array de l'objet Wolf
7072
- newvalues = np.ma.masked_array([interplin(x, y) for x, y in zip(grid_x.flatten(),grid_y.flatten())])
7294
+ newvalues = np.ma.masked_array([interplin(x, y) for x, y in zip(grid_x.ravel(),grid_y.ravel())])
7073
7295
  except:
7074
7296
  raise Warning(_('Bad triangulation - try with another method like Scipy'))
7075
7297
 
7298
+ # newvalues is a vector of values
7299
+
7300
+ # ij is a vector of indices
7301
+ ij = np.asarray([self.get_ij_from_xy(x, y) for x, y in zip(grid_x.ravel(),grid_y.ravel())])
7302
+
7076
7303
  if newvalues.mask.shape!=():
7077
- ij = ij[np.where(~newvalues.mask)]
7078
- self.array.data[ij[:, 0], ij[:, 1]] = newvalues.data[np.where(~newvalues.mask)]
7304
+
7305
+ nonmasked_values = np.where(~newvalues.mask)
7306
+ ij = ij[nonmasked_values]
7307
+ newvalues = newvalues[nonmasked_values]
7308
+
7309
+ if keep == 'below':
7310
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data[ij[:, 0], ij[:, 1]]))
7311
+
7312
+ nonmasked_values = np.where(~newvalues.mask)
7313
+ ij = ij[nonmasked_values]
7314
+ newvalues = newvalues[nonmasked_values]
7315
+
7316
+ elif keep == 'above':
7317
+
7318
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues < self.array.data[ij[:, 0], ij[:, 1]]))
7319
+
7320
+ nonmasked_values = np.where(~newvalues.mask)
7321
+ ij = ij[nonmasked_values]
7322
+ newvalues = newvalues[nonmasked_values]
7323
+
7324
+ self.array.data[ij[:, 0], ij[:, 1]] = newvalues
7079
7325
  else:
7080
- self.array.data[ij[:, 0], ij[:, 1]] = newvalues.data
7326
+
7327
+ if keep == 'below':
7328
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data[ij[:, 0], ij[:, 1]]))
7329
+ nonmasked_values = np.where(~newvalues.mask)
7330
+ ij = ij[nonmasked_values]
7331
+ newvalues = newvalues[nonmasked_values]
7332
+ elif keep == 'above':
7333
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues < self.array.data[ij[:, 0], ij[:, 1]]))
7334
+ nonmasked_values = np.where(~newvalues.mask)
7335
+ ij = ij[nonmasked_values]
7336
+ newvalues = newvalues[nonmasked_values]
7337
+
7338
+ self.array.data[ij[:, 0], ij[:, 1]] = newvalues
7339
+
7081
7340
  else:
7341
+ # Working on the whole array
7342
+
7343
+ # Creating a grid for all cells
7082
7344
  decalx = self.origx + self.translx
7083
7345
  decaly = self.origy + self.transly
7084
7346
  x = np.arange(self.dx / 2. + decalx, float(self.nbx) * self.dx + self.dx / 2 + decalx, self.dx)
@@ -7092,12 +7354,25 @@ class WolfArray(Element_To_Draw, header_wolf):
7092
7354
  triang.set_mask(mask_tri)
7093
7355
  interplin = mtri.LinearTriInterpolator(triang, coords[:,2])
7094
7356
  # Interpolation et récupération dans le numpy.array de l'objet Wolf
7357
+
7358
+ # newvalues is an array
7095
7359
  newvalues = interplin(grid_x,grid_y).astype(np.float32)
7096
- self.array.data[~newvalues.mask] = newvalues[~newvalues.mask]
7360
+
7361
+ assert newvalues.shape == (self.nbx, self.nby), _('Bad shape for newvalues')
7362
+
7363
+ if keep == 'below':
7364
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data))
7365
+ elif keep == 'above':
7366
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues < self.array.data))
7367
+
7368
+ nonmasked_values = np.where(~newvalues.mask)
7369
+
7370
+ self.array.data[nonmasked_values] = newvalues[nonmasked_values]
7097
7371
  except:
7098
7372
  raise Warning(_('Bad triangulation - try with another method like Scipy'))
7099
7373
  else:
7100
7374
  if grid_x is None and grid_y is None:
7375
+
7101
7376
  decalx = self.origx + self.translx
7102
7377
  decaly = self.origy + self.transly
7103
7378
  x = np.arange(self.dx / 2. + decalx, float(self.nbx) * self.dx + self.dx / 2 + decalx, self.dx)
@@ -7108,22 +7383,80 @@ class WolfArray(Element_To_Draw, header_wolf):
7108
7383
  triang = mtri.Triangulation(coords[:,0],coords[:,1],triangles)
7109
7384
  interplin = mtri.LinearTriInterpolator(triang, coords[:,2])
7110
7385
  # Interpolation et récupération dans le numpy.array de l'objet Wolf
7111
- newvalues = np.ma.masked_array([interplin(x, y) for x, y in zip(grid_x.flatten(),grid_y.flatten())])
7386
+ newvalues = np.ma.masked_array([interplin(x, y) for x, y in zip(grid_x.ravel(), grid_y.ravel())])
7112
7387
  # newvalues = interplin(grid_x,grid_y).astype(np.float32)
7113
- self.array.data[~newvalues.mask] = newvalues[~newvalues.mask]
7388
+
7389
+ nonmasked_values = np.where(~newvalues.mask)
7390
+ grid_x = grid_x.ravel()[nonmasked_values]
7391
+ grid_y = grid_y.ravel()[nonmasked_values]
7392
+ newvalues = newvalues[nonmasked_values]
7393
+
7394
+ # make a shape (n, 2) from grid_x and grid_y
7395
+ grid_x = grid_x[:, np.newaxis]
7396
+ grid_y = grid_y[:, np.newaxis]
7397
+ # concatenate grid_x and grid_y
7398
+ grid_ij = self.xy2ij_np(np.concatenate([grid_x, grid_y], axis=1))
7399
+
7400
+ if keep == 'below':
7401
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data[grid_ij[:,0], grid_ij[:,1]]))
7402
+
7403
+ nonmasked_values = np.where(~newvalues.mask)
7404
+ grid_ij = grid_ij[nonmasked_values]
7405
+ newvalues = newvalues[nonmasked_values]
7406
+
7407
+ elif keep == 'above':
7408
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues < self.array.data[grid_ij[:,0], grid_ij[:,1]]))
7409
+
7410
+ nonmasked_values = np.where(~newvalues.mask)
7411
+ grid_ij = grid_ij[nonmasked_values]
7412
+ newvalues = newvalues[nonmasked_values]
7413
+
7414
+ self.array.data[grid_ij[:,0], grid_ij[:,1]] = newvalues
7415
+
7114
7416
  else:
7115
- ij = np.asarray([self.get_ij_from_xy(x, y) for x, y in zip(grid_x.flatten(),grid_y.flatten())])
7417
+ ij = np.asarray([self.get_ij_from_xy(x, y) for x, y in zip(grid_x.ravel(),grid_y.ravel())])
7116
7418
 
7117
7419
  # Opérateur d'interpolation linéaire
7118
7420
  triang = mtri.Triangulation(coords[:,0],coords[:,1],triangles)
7119
7421
  interplin = mtri.LinearTriInterpolator(triang, coords[:,2]) # Interpolation et récupération dans le numpy.array de l'objet Wolf
7120
- newvalues = np.ma.masked_array([interplin(x, y) for x, y in zip(grid_x.flatten(),grid_y.flatten())])
7422
+ newvalues = np.ma.masked_array([interplin(x, y) for x, y in zip(grid_x.ravel(), grid_y.ravel())])
7121
7423
 
7122
7424
  if newvalues.mask.shape!=():
7123
- ij = ij[np.where(~newvalues.mask)]
7124
- self.array.data[ij[:, 0], ij[:, 1]] = newvalues.data[np.where(~newvalues.mask)]
7425
+ nonmasked_values = np.where(~newvalues.mask)
7426
+ ij = ij[nonmasked_values]
7427
+ newvalues = newvalues[nonmasked_values]
7428
+
7429
+ if keep == 'below':
7430
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data[ij[:, 0], ij[:, 1]]))
7431
+
7432
+ nonmasked_values = np.where(~newvalues.mask)
7433
+ ij = ij[nonmasked_values]
7434
+ newvalues = newvalues[nonmasked_values]
7435
+
7436
+ elif keep == 'above':
7437
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues < self.array.data[ij[:, 0], ij[:, 1]]))
7438
+
7439
+ nonmasked_values = np.where(~newvalues.mask)
7440
+ ij = ij[nonmasked_values]
7441
+ newvalues = newvalues[nonmasked_values]
7442
+
7443
+ self.array.data[ij[:, 0], ij[:, 1]] = newvalues
7125
7444
  else:
7126
- self.array.data[ij[:, 0], ij[:, 1]] = newvalues.data
7445
+ if keep == 'below':
7446
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues > self.array.data[ij[:, 0], ij[:, 1]]))
7447
+
7448
+ nonmasked_values = np.where(~newvalues.mask)
7449
+ ij = ij[nonmasked_values]
7450
+ newvalues = newvalues[nonmasked_values]
7451
+
7452
+ elif keep == 'above':
7453
+ newvalues = np.ma.masked_array(newvalues, mask=(newvalues < self.array.data[ij[:, 0], ij[:, 1]]))
7454
+
7455
+ nonmasked_values = np.where(~newvalues.mask)
7456
+ ij = ij[nonmasked_values]
7457
+ newvalues = newvalues[nonmasked_values]
7458
+
7459
+ self.array.data[ij[:, 0], ij[:, 1]] = newvalues
7127
7460
 
7128
7461
  #on force les valeurs masquées à nullvalue afin que l'interpolation n'applique pas ses effets dans cette zone
7129
7462
  self.array.data[self.array.mask]= self.nullvalue
@@ -7131,13 +7464,15 @@ class WolfArray(Element_To_Draw, header_wolf):
7131
7464
  use_scipy=True
7132
7465
 
7133
7466
  if interp_method != 'matplotlib' or use_scipy:
7467
+ # We need to convert the triangle to a vector to call the interpolation
7468
+
7134
7469
  for curtri in triangles:
7135
7470
  curvec = vector(is2D=False)
7136
7471
  for curpt in curtri:
7137
- curvec.add_vertex(wolfvertex(coords[curpt,0],coords[curpt,1], coords[curpt,2]))
7472
+ curvec.add_vertex(wolfvertex(coords[curpt,0], coords[curpt,1], coords[curpt,2]))
7138
7473
  curvec.close_force()
7139
7474
 
7140
- self.interpolate_on_polygon(curvec, "linear")
7475
+ self.interpolate_on_polygon(curvec, "linear", keep)
7141
7476
 
7142
7477
  self.reset_plot()
7143
7478
  return
@@ -8558,7 +8893,7 @@ class WolfArray(Element_To_Draw, header_wolf):
8558
8893
  :param step_factor: step factor for the discretization of myvect (<1 for thinner, >1 for coarser)
8559
8894
  """
8560
8895
 
8561
- if step_factor>=1.0:
8896
+ if step_factor>1.0:
8562
8897
  logging.warning("Step_factor greater than 1.0 may lead to lots of missing (i,j) even if faster")
8563
8898
  else:
8564
8899
  def mod_fix(x, y, tol=1e-10):
@@ -10054,7 +10389,12 @@ class WolfArray(Element_To_Draw, header_wolf):
10054
10389
  nbx = curlist['nbx']
10055
10390
  nby = curlist['nby']
10056
10391
  first = curlist['firstlist']
10057
- glDeleteLists(first, nbx * nby)
10392
+
10393
+ try:
10394
+ glDeleteLists(first, nbx * nby)
10395
+ except Exception as e:
10396
+ logging.error(_('OpenGL error in WolfArray.delete_lists -- Please report this case with the data file and the context in which the error occured'))
10397
+ logging.error(e)
10058
10398
 
10059
10399
  logging.debug(str(first)+' '+str(nbx * nby))
10060
10400
 
@@ -11214,7 +11554,9 @@ class WolfArrayMB(WolfArray):
11214
11554
 
11215
11555
  self.reset_plot()
11216
11556
 
11217
- def interpolate_on_polygon(self, working_vector: vector, method:Literal["nearest", "linear", "cubic"]="linear"):
11557
+ def interpolate_on_polygon(self, working_vector: vector,
11558
+ method:Literal["nearest", "linear", "cubic"]="linear",
11559
+ keep:Literal['all', 'below', 'above'] = 'all'):
11218
11560
  """
11219
11561
  Interpolation sous un polygone
11220
11562
 
@@ -11227,12 +11569,14 @@ class WolfArrayMB(WolfArray):
11227
11569
  """
11228
11570
 
11229
11571
  for curblock in self.myblocks.values():
11230
- curblock.interpolate_on_polygon(working_vector, method)
11572
+ curblock.interpolate_on_polygon(working_vector, method, keep)
11231
11573
 
11232
- def interpolate_on_polygons(self, working_zone: zone, method:Literal["nearest", "linear", "cubic"]="linear"):
11574
+ def interpolate_on_polygons(self, working_zone: zone,
11575
+ method:Literal["nearest", "linear", "cubic"]="linear",
11576
+ keep:Literal['all', 'below', 'above'] = 'all'):
11233
11577
 
11234
11578
  for curvector in working_zone.myvectors:
11235
- self.interpolate_on_polygon(curvector, method)
11579
+ self.interpolate_on_polygon(curvector, method, keep)
11236
11580
 
11237
11581
  def interpolate_on_polyline(self, working_vector:vector, usemask=True):
11238
11582
  """