33import numpy as np
44from larray_editor .utils import (get_font , from_qvariant , to_qvariant , to_text_string ,
55 is_float , is_number , LinearGradient , SUPPORTED_FORMATS , scale_to_01range ,
6- Product )
6+ Product , is_number_value , get_sample , get_sample_indices )
77from qtpy .QtCore import Qt , QModelIndex , QAbstractTableModel
88from qtpy .QtGui import QColor
99from qtpy .QtWidgets import QMessageBox
@@ -256,8 +256,8 @@ def _set_data(self, data):
256256 self ._compute_rows_cols_loaded ()
257257
258258 def reset_minmax (self ):
259- data = self .get_values ()
260259 try :
260+ data = self .get_values (sample = True )
261261 color_value = self .color_func (data ) if self .color_func is not None else data
262262 # ignore nan, -inf, inf (setting them to 0 or to very large numbers is not an option)
263263 color_value = color_value [np .isfinite (color_value )]
@@ -336,8 +336,21 @@ def data(self, index, role=Qt.DisplayRole):
336336 elif role == Qt .BackgroundColorRole :
337337 if self .bgcolor_possible and self .bg_gradient is not None and value is not np .ma .masked :
338338 if self .bg_value is None :
339- v = float (self .color_func (value ) if self .color_func is not None else value )
340- v = scale_to_01range (v , self .vmin , self .vmax )
339+ try :
340+ v = self .color_func (value ) if self .color_func is not None else value
341+ if - np .inf < v < self .vmin :
342+ # TODO: this is suboptimal, as it can reset many times (though in practice, it is usually
343+ # ok). When we get buffering, we will need to compute vmin/vmax on the whole buffer
344+ # at once, eliminating this problem (and we could even compute final colors directly
345+ # all at once)
346+ self .vmin = v
347+ self .reset ()
348+ elif self .vmax < v < np .inf :
349+ self .vmax = v
350+ self .reset ()
351+ v = scale_to_01range (v , self .vmin , self .vmax )
352+ except TypeError :
353+ v = np .nan
341354 else :
342355 i , j = index .row (), index .column ()
343356 v = self .bg_value [i , j ]
@@ -346,26 +359,45 @@ def data(self, index, role=Qt.DisplayRole):
346359 # return to_qvariant("{}\n{}".format(repr(value),self.get_labels(index)))
347360 return to_qvariant ()
348361
349- def get_values (self , left = 0 , top = 0 , right = None , bottom = None ):
362+ def get_values (self , left = 0 , top = 0 , right = None , bottom = None , sample = False ):
350363 width , height = self .total_rows , self .total_cols
351364 if right is None :
352365 right = width
353366 if bottom is None :
354367 bottom = height
355- values = self . _data [ left : right , top : bottom ]. copy ()
356- # both versions get the same result, but depending on inputs, the
357- # speed difference can be large.
368+ # this whole bullshit will disappear when we implement undo/redo
369+ values = self . _data [ left : right , top : bottom ]
370+ # both versions get the same result, but depending on inputs, the speed difference can be large.
358371 if values .size < len (self .changes ):
372+ # changes are supposedly relatively small so this case should not be too slow even if we just want a sample
373+ values = values .copy ()
359374 for i in range (left , right ):
360375 for j in range (top , bottom ):
361376 pos = i , j
362377 if pos in self .changes :
363378 values [i - left , j - top ] = self .changes [pos ]
379+ if sample :
380+ return get_sample (values , 500 )
381+ else :
382+ return values
364383 else :
365- for (i , j ), value in self .changes .items ():
366- if left <= i < right and top <= j < bottom :
367- values [i - left , j - top ] = value
368- return values
384+ if sample :
385+ sample_indices = get_sample_indices (values , 500 )
386+ changes = self .changes
387+
388+ def get_val (idx ):
389+ i , j = idx
390+ changes_idx = (i + left , j + top )
391+ return changes [changes_idx ] if changes_idx in changes else values [idx ]
392+
393+ # we need to keep the dtype, otherwise numpy might convert mixed object arrays to strings
394+ return np .array ([get_val (idx ) for idx in zip (* sample_indices )], dtype = values .dtype )
395+ else :
396+ values = values .copy ()
397+ for (i , j ), value in self .changes .items ():
398+ if left <= i < right and top <= j < bottom :
399+ values [i - left , j - top ] = value
400+ return values
369401
370402 def convert_value (self , value ):
371403 """
0 commit comments