Use math module for isfinite or isnan for scalars
Various places in the library attempt to check if scalars are finite via numpy methods, which are intended to be used on numpy arrays. Using the math module equivalent functions on scalars is significantly faster. In a few places, I also use numpy methods explicitly (np.all vs. all)
This commit is contained in:
parent
b0769f4be9
commit
314121192a
@ -60,12 +60,10 @@ def siScale(x, minVal=1e-25, allowUnicode=True):
|
||||
|
||||
if isinstance(x, decimal.Decimal):
|
||||
x = float(x)
|
||||
|
||||
try:
|
||||
if np.isnan(x) or np.isinf(x):
|
||||
if not math.isfinite(x):
|
||||
return(1, '')
|
||||
except:
|
||||
print(x, type(x))
|
||||
raise
|
||||
if abs(x) < minVal:
|
||||
m = 0
|
||||
@ -295,9 +293,7 @@ def mkColor(*args):
|
||||
else:
|
||||
raise TypeError(err)
|
||||
|
||||
args = [r,g,b,a]
|
||||
args = [0 if np.isnan(a) or np.isinf(a) else a for a in args]
|
||||
args = list(map(int, args))
|
||||
args = [int(a) if math.isfinite(a) else 0 for a in (r, g, b, a)]
|
||||
return QtGui.QColor(*args)
|
||||
|
||||
|
||||
@ -458,7 +454,7 @@ def eq(a, b):
|
||||
|
||||
1. Returns True if a IS b, even if a==b still evaluates to False.
|
||||
2. While a is b will catch the case with np.nan values, special handling is done for distinct
|
||||
float('nan') instances using np.isnan.
|
||||
float('nan') instances using math.isnan.
|
||||
3. Tests for equivalence using ==, but silently ignores some common exceptions that can occur
|
||||
(AtrtibuteError, ValueError).
|
||||
4. When comparing arrays, returns False if the array shapes are not the same.
|
||||
@ -472,7 +468,7 @@ def eq(a, b):
|
||||
|
||||
# The above catches np.nan, but not float('nan')
|
||||
if isinstance(a, float) and isinstance(b, float):
|
||||
if np.isnan(a) and np.isnan(b):
|
||||
if math.isnan(a) and math.isnan(b):
|
||||
return True
|
||||
|
||||
# Avoid comparing large arrays against scalars; this is expensive and we know it should return False.
|
||||
|
@ -4,7 +4,7 @@ from ..python2_3 import asUnicode
|
||||
import numpy as np
|
||||
from ..Point import Point
|
||||
from .. import debug as debug
|
||||
from math import ceil, floor, log, log10
|
||||
from math import ceil, floor, log, log10, isfinite
|
||||
import sys
|
||||
import weakref
|
||||
from .. import functions as fn
|
||||
@ -512,7 +512,7 @@ class AxisItem(GraphicsWidget):
|
||||
def setRange(self, mn, mx):
|
||||
"""Set the range of values displayed by the axis.
|
||||
Usually this is handled automatically by linking the axis to a ViewBox with :func:`linkToView <pyqtgraph.AxisItem.linkToView>`"""
|
||||
if any(np.isinf((mn, mx))) or any(np.isnan((mn, mx))):
|
||||
if not isfinite(mn) or not isfinite(mx):
|
||||
raise Exception("Not setting range to [%s, %s]" % (str(mn), str(mx)))
|
||||
self.range = [mn, mx]
|
||||
if self.autoSIPrefix:
|
||||
@ -767,7 +767,7 @@ class AxisItem(GraphicsWidget):
|
||||
## remove any ticks that were present in higher levels
|
||||
## we assume here that if the difference between a tick value and a previously seen tick value
|
||||
## is less than spacing/100, then they are 'equal' and we can ignore the new tick.
|
||||
values = list(filter(lambda x: all(np.abs(allValues-x) > spacing/self.scale*0.01), values))
|
||||
values = list(filter(lambda x: np.all(np.abs(allValues-x) > spacing/self.scale*0.01), values))
|
||||
allValues = np.concatenate([allValues, values])
|
||||
ticks.append((spacing/self.scale, values))
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
from ..Qt import QtGui, QtCore
|
||||
import math
|
||||
import numpy as np
|
||||
from ..colormap import ColorMap
|
||||
from .GraphicsObject import GraphicsObject
|
||||
@ -94,7 +95,7 @@ class NonUniformImage(GraphicsObject):
|
||||
value = 0.0
|
||||
elif np.isposinf(value):
|
||||
value = 1.0
|
||||
elif np.isnan(value):
|
||||
elif math.isnan(value):
|
||||
continue # ignore NaN
|
||||
else:
|
||||
value = (value - mn) / (mx - mn) # normalize
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from ..Qt import QtCore, QtGui, QtWidgets
|
||||
HAVE_OPENGL = hasattr(QtWidgets, 'QOpenGLWidget')
|
||||
|
||||
import math
|
||||
import warnings
|
||||
import numpy as np
|
||||
from .GraphicsObject import GraphicsObject
|
||||
@ -131,6 +131,8 @@ class PlotCurveItem(GraphicsObject):
|
||||
elif ax == 1:
|
||||
d = y
|
||||
d2 = x
|
||||
else:
|
||||
raise ValueError("Invalid axis value")
|
||||
|
||||
## If an orthogonal range is specified, mask the data now
|
||||
if orthoRange is not None:
|
||||
@ -149,7 +151,7 @@ class PlotCurveItem(GraphicsObject):
|
||||
# All-NaN data is acceptable; Explicit numpy warning is not needed.
|
||||
warnings.simplefilter("ignore")
|
||||
b = (np.nanmin(d), np.nanmax(d))
|
||||
if any(np.isinf(b)):
|
||||
if math.isinf(b[0]) or math.isinf(b[1]):
|
||||
mask = np.isfinite(d)
|
||||
d = d[mask]
|
||||
if len(d) == 0:
|
||||
|
@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import warnings
|
||||
import math
|
||||
import numpy as np
|
||||
from .. import metaarray as metaarray
|
||||
from ..Qt import QtCore
|
||||
@ -660,7 +661,7 @@ class PlotDataItem(GraphicsObject):
|
||||
eps = np.finfo(y.dtype).eps
|
||||
else:
|
||||
eps = 1
|
||||
y = np.sign(y) * np.log10(np.abs(y)+eps)
|
||||
y = np.copysign(np.log10(np.abs(y)+eps), y)
|
||||
|
||||
ds = self.opts['downsample']
|
||||
if not isinstance(ds, int):
|
||||
@ -799,10 +800,10 @@ class PlotDataItem(GraphicsObject):
|
||||
# All-NaN data is handled by returning None; Explicit numpy warning is not needed.
|
||||
warnings.simplefilter("ignore")
|
||||
ymin = np.nanmin(self.yData)
|
||||
if np.isnan( ymin ):
|
||||
if math.isnan( ymin ):
|
||||
return None # most likely case for all-NaN data
|
||||
xmin = np.nanmin(self.xData)
|
||||
if np.isnan( xmin ):
|
||||
if math.isnan( xmin ):
|
||||
return None # less likely case for all-NaN data
|
||||
ymax = np.nanmax(self.yData)
|
||||
xmax = np.nanmax(self.xData)
|
||||
|
@ -1425,7 +1425,7 @@ class Handle(UIGraphicsItem):
|
||||
menu = self.scene().addParentContextMenus(self, self.getMenu(), ev)
|
||||
|
||||
## Make sure it is still ok to remove this handle
|
||||
removeAllowed = all([r.checkRemoveHandle(self) for r in self.rois])
|
||||
removeAllowed = all(r.checkRemoveHandle(self) for r in self.rois)
|
||||
self.removeAction.setEnabled(removeAllowed)
|
||||
pos = ev.screenPos()
|
||||
menu.popup(QtCore.QPoint(pos.x(), pos.y()))
|
||||
|
@ -6,6 +6,7 @@ try:
|
||||
except ImportError:
|
||||
imap = map
|
||||
import itertools
|
||||
import math
|
||||
import numpy as np
|
||||
import weakref
|
||||
from ..Qt import QtGui, QtCore, QT_LIB
|
||||
@ -116,7 +117,7 @@ def renderSymbol(symbol, size, pen, brush, device=None):
|
||||
for more information).
|
||||
"""
|
||||
## Render a spot with the given parameters to a pixmap
|
||||
penPxWidth = max(np.ceil(pen.widthF()), 1)
|
||||
penPxWidth = max(math.ceil(pen.widthF()), 1)
|
||||
if device is None:
|
||||
device = QtGui.QImage(int(size+penPxWidth), int(size+penPxWidth), QtGui.QImage.Format_ARGB32)
|
||||
device.fill(0)
|
||||
@ -950,6 +951,8 @@ class ScatterPlotItem(GraphicsObject):
|
||||
elif ax == 1:
|
||||
d = self.data['y']
|
||||
d2 = self.data['x']
|
||||
else:
|
||||
raise ValueError("Invalid axis value")
|
||||
|
||||
if orthoRange is not None:
|
||||
mask = (d2 >= orthoRange[0]) * (d2 <= orthoRange[1])
|
||||
|
@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import weakref
|
||||
import sys
|
||||
import math
|
||||
from copy import deepcopy
|
||||
import numpy as np
|
||||
from ...Qt import QtGui, QtCore
|
||||
@ -552,7 +553,7 @@ class ViewBox(GraphicsWidget):
|
||||
xpad = 0.0
|
||||
|
||||
# Make sure no nan/inf get through
|
||||
if not all(np.isfinite([mn, mx])):
|
||||
if not math.isfinite(mn) or not math.isfinite(mx):
|
||||
raise Exception("Cannot set range [%s, %s]" % (str(mn), str(mx)))
|
||||
|
||||
# Apply padding
|
||||
@ -903,11 +904,11 @@ class ViewBox(GraphicsWidget):
|
||||
targetRect[ax] = childRange[ax]
|
||||
args['xRange' if ax == 0 else 'yRange'] = targetRect[ax]
|
||||
|
||||
# check for and ignore bad ranges
|
||||
# check for and ignore bad ranges
|
||||
for k in ['xRange', 'yRange']:
|
||||
if k in args:
|
||||
if not np.all(np.isfinite(args[k])):
|
||||
r = args.pop(k)
|
||||
if not math.isfinite(args[k][0]) or not math.isfinite(args[k][1]):
|
||||
_ = args.pop(k)
|
||||
#print("Warning: %s is invalid: %s" % (k, str(r))
|
||||
|
||||
if len(args) == 0:
|
||||
@ -1369,10 +1370,20 @@ class ViewBox(GraphicsWidget):
|
||||
xr = item.dataBounds(0, frac=frac[0], orthoRange=orthoRange[0])
|
||||
yr = item.dataBounds(1, frac=frac[1], orthoRange=orthoRange[1])
|
||||
pxPad = 0 if not hasattr(item, 'pixelPadding') else item.pixelPadding()
|
||||
if xr is None or (xr[0] is None and xr[1] is None) or np.isnan(xr).any() or np.isinf(xr).any():
|
||||
if (
|
||||
xr is None or
|
||||
(xr[0] is None and xr[1] is None) or
|
||||
not math.isfinite(xr[0]) or
|
||||
not math.isfinite(xr[1])
|
||||
):
|
||||
useX = False
|
||||
xr = (0,0)
|
||||
if yr is None or (yr[0] is None and yr[1] is None) or np.isnan(yr).any() or np.isinf(yr).any():
|
||||
if (
|
||||
yr is None or
|
||||
(yr[0] is None and yr[1] is None) or
|
||||
not math.isfinite(yr[0]) or
|
||||
not math.isfinite(yr[1])
|
||||
):
|
||||
useY = False
|
||||
yr = (0,0)
|
||||
|
||||
|
@ -214,7 +214,7 @@ class RangeColorMapItem(ptree.types.SimpleParameter):
|
||||
cmap = self.value()
|
||||
colors = cmap.map(scaled, mode='float')
|
||||
|
||||
mask = np.isnan(data) | np.isinf(data)
|
||||
mask = np.invert(np.isfinite(data))
|
||||
nanColor = self['NaN']
|
||||
nanColor = (nanColor.red()/255., nanColor.green()/255., nanColor.blue()/255., nanColor.alpha()/255.)
|
||||
colors[mask] = nanColor
|
||||
|
Loading…
x
Reference in New Issue
Block a user