Reduce reallocation in dynamic range limiter (#1556)
* change imports in cupy module to be local * reduced re-allocation in dynamic range limiter, part 1 * minor cleanup
This commit is contained in:
parent
aed2382e38
commit
33365fb730
@ -166,7 +166,9 @@ class PlotDataItem(GraphicsObject):
|
|||||||
self.scatter.sigClicked.connect(self.scatterClicked)
|
self.scatter.sigClicked.connect(self.scatterClicked)
|
||||||
self.scatter.sigHovered.connect(self.scatterHovered)
|
self.scatter.sigHovered.connect(self.scatterHovered)
|
||||||
|
|
||||||
|
self._viewRangeWasChanged = False
|
||||||
self._dataRect = None
|
self._dataRect = None
|
||||||
|
self._drlLastClip = (0.0, 0.0) # holds last clipping points of dynamic range limiter
|
||||||
#self.clear()
|
#self.clear()
|
||||||
self.opts = {
|
self.opts = {
|
||||||
'connect': 'all',
|
'connect': 'all',
|
||||||
@ -200,6 +202,7 @@ class PlotDataItem(GraphicsObject):
|
|||||||
'autoDownsampleFactor': 5., # draw ~5 samples per pixel
|
'autoDownsampleFactor': 5., # draw ~5 samples per pixel
|
||||||
'clipToView': False,
|
'clipToView': False,
|
||||||
'dynamicRangeLimit': 1e6,
|
'dynamicRangeLimit': 1e6,
|
||||||
|
'dynamicRangeHyst': 3.0,
|
||||||
|
|
||||||
'data': None,
|
'data': None,
|
||||||
}
|
}
|
||||||
@ -400,19 +403,28 @@ class PlotDataItem(GraphicsObject):
|
|||||||
self.xDisp = self.yDisp = None
|
self.xDisp = self.yDisp = None
|
||||||
self.updateItems()
|
self.updateItems()
|
||||||
|
|
||||||
def setDynamicRangeLimit(self, limit):
|
def setDynamicRangeLimit(self, limit=1e06, hysteresis=3.):
|
||||||
"""
|
"""
|
||||||
Limit the off-screen positions of data points at large magnification
|
Limit the off-screen positions of data points at large magnification
|
||||||
This avoids errors with plots not displaying because their visibility is incorrectly determined. The default setting repositions far-off points to be within +-1E+06 times the viewport height.
|
This avoids errors with plots not displaying because their visibility is incorrectly determined. The default setting repositions far-off points to be within +-1E+06 times the viewport height.
|
||||||
|
|
||||||
=============== ================================================================
|
=============== ================================================================
|
||||||
**Arguments:**
|
**Arguments:**
|
||||||
limit (float or None) Maximum allowed vertical distance of plotted
|
limit (float or None) Any data outside the range of limit * hysteresis
|
||||||
points in units of viewport height.
|
will be constrained to the limit value limit.
|
||||||
|
All values are relative to the viewport height.
|
||||||
'None' disables the check for a minimal increase in performance.
|
'None' disables the check for a minimal increase in performance.
|
||||||
Default is 1E+06.
|
Default is 1E+06.
|
||||||
|
|
||||||
|
hysteresis (float) Hysteresis factor that controls how much change
|
||||||
|
in zoom level (vertical height) is allowed before recalculating
|
||||||
|
Default is 3.0
|
||||||
=============== ================================================================
|
=============== ================================================================
|
||||||
"""
|
"""
|
||||||
|
if hysteresis < 1.0:
|
||||||
|
hysteresis = 1.0
|
||||||
|
self.opts['dynamicRangeHyst'] = hysteresis
|
||||||
|
|
||||||
if limit == self.opts['dynamicRangeLimit']:
|
if limit == self.opts['dynamicRangeLimit']:
|
||||||
return # avoid update if there is no change
|
return # avoid update if there is no change
|
||||||
self.opts['dynamicRangeLimit'] = limit # can be None
|
self.opts['dynamicRangeLimit'] = limit # can be None
|
||||||
@ -592,7 +604,7 @@ class PlotDataItem(GraphicsObject):
|
|||||||
if self.xData is None:
|
if self.xData is None:
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
if self.xDisp is None:
|
if self.xDisp is None or self._viewRangeWasChanged:
|
||||||
x = self.xData
|
x = self.xData
|
||||||
y = self.yData
|
y = self.yData
|
||||||
|
|
||||||
@ -687,14 +699,41 @@ class PlotDataItem(GraphicsObject):
|
|||||||
data_range = self.dataRect()
|
data_range = self.dataRect()
|
||||||
if data_range is not None:
|
if data_range is not None:
|
||||||
view_height = view_range.height()
|
view_height = view_range.height()
|
||||||
lim = self.opts['dynamicRangeLimit']
|
limit = self.opts['dynamicRangeLimit']
|
||||||
if data_range.height() > lim * view_height:
|
hyst = self.opts['dynamicRangeHyst']
|
||||||
min_val = view_range.top() - lim * view_height
|
# never clip data if it fits into +/- (extended) limit * view height
|
||||||
max_val = view_range.bottom() + lim * view_height
|
if data_range.height() > 2 * hyst * limit * view_height:
|
||||||
y = np.clip(y, a_min=min_val, a_max=max_val)
|
# check if cached display data can be reused:
|
||||||
|
if self.yDisp is not None: # top is minimum value, bottom is maximum value
|
||||||
|
# how many multiples of the current view height does the clipped plot extend to the top and bottom?
|
||||||
|
top_exc =-(self._drlLastClip[0]-view_range.bottom()) / view_height
|
||||||
|
bot_exc = (self._drlLastClip[1]-view_range.top() ) / view_height
|
||||||
|
# print(top_exc, bot_exc, hyst)
|
||||||
|
if ( top_exc >= limit / hyst and top_exc <= limit * hyst
|
||||||
|
and bot_exc >= limit / hyst and bot_exc <= limit * hyst ):
|
||||||
|
# restore cached values
|
||||||
|
x = self.xDisp
|
||||||
|
y = self.yDisp
|
||||||
|
else:
|
||||||
|
min_val = view_range.bottom() - limit * view_height
|
||||||
|
max_val = view_range.top() + limit * view_height
|
||||||
|
if( min_val >= self._drlLastClip[0]
|
||||||
|
and max_val <= self._drlLastClip[1] ):
|
||||||
|
# if we need to clip further, we can work in-place on the output buffer
|
||||||
|
# print('in-place:', end='')
|
||||||
|
np.clip(self.yDisp, out=self.yDisp, a_min=min_val, a_max=max_val)
|
||||||
|
x = self.xDisp
|
||||||
|
y = self.yDisp
|
||||||
|
else:
|
||||||
|
# otherwise we need to recopy from the full data
|
||||||
|
# print('alloc:', end='')
|
||||||
|
y = np.clip(y, a_min=min_val, a_max=max_val)
|
||||||
|
# print('{:.1e}<->{:.1e}'.format( min_val, max_val ))
|
||||||
|
self._drlLastClip = (min_val, max_val)
|
||||||
|
|
||||||
self.xDisp = x
|
self.xDisp = x
|
||||||
self.yDisp = y
|
self.yDisp = y
|
||||||
|
self._viewRangeWasChanged = False
|
||||||
return self.xDisp, self.yDisp
|
return self.xDisp, self.yDisp
|
||||||
|
|
||||||
def dataRect(self):
|
def dataRect(self):
|
||||||
@ -797,12 +836,15 @@ class PlotDataItem(GraphicsObject):
|
|||||||
|
|
||||||
def viewRangeChanged(self):
|
def viewRangeChanged(self):
|
||||||
# view range has changed; re-plot if needed
|
# view range has changed; re-plot if needed
|
||||||
|
self._viewRangeWasChanged = True
|
||||||
if( self.opts['clipToView']
|
if( self.opts['clipToView']
|
||||||
or self.opts['autoDownsample']
|
or self.opts['autoDownsample']
|
||||||
or self.opts['dynamicRangeLimit'] is not None
|
|
||||||
):
|
):
|
||||||
self.xDisp = self.yDisp = None
|
self.xDisp = self.yDisp = None
|
||||||
self.updateItems()
|
self.updateItems()
|
||||||
|
elif self.opts['dynamicRangeLimit'] is not None:
|
||||||
|
# do not discard cached display data
|
||||||
|
self.updateItems()
|
||||||
|
|
||||||
def _fourierTransform(self, x, y):
|
def _fourierTransform(self, x, y):
|
||||||
## Perform fourier transform. If x values are not sampled uniformly,
|
## Perform fourier transform. If x values are not sampled uniformly,
|
||||||
|
Loading…
Reference in New Issue
Block a user