Use math module methods for singular values

Using numpy methods that are intended for vectorized operations is
substantially slower than using the math module, so when feasible the
math module methods should be used.
This commit is contained in:
Ogi Moore 2021-04-17 20:08:57 -07:00
parent 1326ebe2f4
commit b0a3849960
11 changed files with 53 additions and 57 deletions

View File

@ -7,6 +7,7 @@ This example uses the isosurface function to convert a scalar field
## Add path to library (just for examples; you do not need this) ## Add path to library (just for examples; you do not need this)
import initExample import initExample
import numpy as np
from pyqtgraph.Qt import QtCore, QtGui from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg import pyqtgraph as pg
import pyqtgraph.opengl as gl import pyqtgraph.opengl as gl
@ -22,23 +23,17 @@ g = gl.GLGridItem()
g.scale(2,2,1) g.scale(2,2,1)
w.addItem(g) w.addItem(g)
import numpy as np
## Define a scalar field from which we will generate an isosurface ## Define a scalar field from which we will generate an isosurface
def psi(i, j, k, offset=(25, 25, 50)): def psi(i, j, k, offset=(25, 25, 50)):
x = i-offset[0] x = i-offset[0]
y = j-offset[1] y = j-offset[1]
z = k-offset[2] z = k-offset[2]
th = np.arctan2(z, (x**2+y**2)**0.5) th = np.arctan2(z, np.sqrt(x**2+y**2))
phi = np.arctan2(y, x) phi = np.arctan2(y, x)
r = (x**2 + y**2 + z **2)**0.5 r = np.sqrt(x**2 + y**2 + z **2)
a0 = 1 a0 = 1
#ps = (1./81.) * (2./np.pi)**0.5 * (1./a0)**(3/2) * (6 - r/a0) * (r/a0) * np.exp(-r/(3*a0)) * np.cos(th)
ps = (1./81.) * 1./(6.*np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * np.exp(-r/(3*a0)) * (3 * np.cos(th)**2 - 1) ps = (1./81.) * 1./(6.*np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * np.exp(-r/(3*a0)) * (3 * np.cos(th)**2 - 1)
return ps return ps
#return ((1./81.) * (1./np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * (r/a0) * np.exp(-r/(3*a0)) * np.sin(th) * np.cos(th) * np.exp(2 * 1j * phi))**2
print("Generating scalar field..") print("Generating scalar field..")

View File

@ -7,6 +7,7 @@ Demonstrates GLVolumeItem for displaying volumetric data.
## Add path to library (just for examples; you do not need this) ## Add path to library (just for examples; you do not need this)
import initExample import initExample
import numpy as np
import pyqtgraph as pg import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl import pyqtgraph.opengl as gl
@ -23,7 +24,6 @@ g = gl.GLGridItem()
g.scale(10, 10, 1) g.scale(10, 10, 1)
w.addItem(g) w.addItem(g)
import numpy as np
## Hydrogen electron probability density ## Hydrogen electron probability density
def psi(i, j, k, offset=(50,50,100)): def psi(i, j, k, offset=(50,50,100)):
x = i-offset[0] x = i-offset[0]

View File

@ -9,6 +9,7 @@ used to affect the appearance of a surface.
## Add path to library (just for examples; you do not need this) ## Add path to library (just for examples; you do not need this)
import initExample import initExample
import numpy as np
from pyqtgraph.Qt import QtCore, QtGui from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg import pyqtgraph as pg
import pyqtgraph.opengl as gl import pyqtgraph.opengl as gl
@ -23,9 +24,6 @@ g = gl.GLGridItem()
g.scale(2,2,1) g.scale(2,2,1)
w.addItem(g) w.addItem(g)
import numpy as np
md = gl.MeshData.sphere(rows=10, cols=20) md = gl.MeshData.sphere(rows=10, cols=20)
x = np.linspace(-8, 8, 6) x = np.linspace(-8, 8, 6)

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from math import atan2, asin, sin, cos, sqrt, pi
import pyqtgraph as pg import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore from pyqtgraph.Qt import QtGui, QtCore
import numpy as np import numpy as np
@ -49,7 +50,7 @@ class GlassDB:
B = list(map(float, [info['B1'], info['B2'], info['B3']])) B = list(map(float, [info['B1'], info['B2'], info['B3']]))
C = list(map(float, [info['C1'], info['C2'], info['C3']])) C = list(map(float, [info['C1'], info['C2'], info['C3']]))
w2 = (wl/1000.)**2 w2 = (wl/1000.)**2
n = np.sqrt(1.0 + (B[0]*w2 / (w2-C[0])) + (B[1]*w2 / (w2-C[1])) + (B[2]*w2 / (w2-C[2]))) n = sqrt(1.0 + (B[0]*w2 / (w2-C[0])) + (B[1]*w2 / (w2-C[1])) + (B[2]*w2 / (w2-C[2])))
cache[wl] = n cache[wl] = n
return cache[wl] return cache[wl]
@ -249,10 +250,14 @@ class Lens(Optic):
p1 = surface.mapToItem(ray, p1) p1 = surface.mapToItem(ray, p1)
rd = ray['dir'] rd = ray['dir']
a1 = np.arctan2(rd[1], rd[0])
ar = a1 - ai + np.arcsin((np.sin(ai) * ray['ior'] / ior)) a1 = atan2(rd[1], rd[0])
try:
ar = a1 - ai + asin((sin(ai) * ray['ior'] / ior))
except ValueError:
ar = np.nan
ray.setEnd(p1) ray.setEnd(p1)
dp = Point(np.cos(ar), np.sin(ar)) dp = Point(cos(ar), sin(ar))
ray = Ray(parent=ray, ior=ior, dir=dp) ray = Ray(parent=ray, ior=ior, dir=dp)
return [ray] return [ray]
@ -279,10 +284,10 @@ class Mirror(Optic):
if p1 is not None: if p1 is not None:
p1 = surface.mapToItem(ray, p1) p1 = surface.mapToItem(ray, p1)
rd = ray['dir'] rd = ray['dir']
a1 = np.arctan2(rd[1], rd[0]) a1 = atan2(rd[1], rd[0])
ar = a1 + np.pi - 2*ai ar = a1 + pi - 2*ai
ray.setEnd(p1) ray.setEnd(p1)
dp = Point(np.cos(ar), np.sin(ar)) dp = Point(cos(ar), sin(ar))
ray = Ray(parent=ray, dir=dp) ray = Ray(parent=ray, dir=dp)
else: else:
ray.setEnd(None) ray.setEnd(None)
@ -374,7 +379,7 @@ class CircleSurface(pg.GraphicsObject):
## half-height of surface can't be larger than radius ## half-height of surface can't be larger than radius
h2 = min(h2, abs(r)) h2 = min(h2, abs(r))
arc = QtCore.QRectF(0, -r, r*2, r*2) arc = QtCore.QRectF(0, -r, r*2, r*2)
a1 = np.arcsin(h2/r) * 180. / np.pi a1 = asin(h2/r) * 180. / pi
a2 = -2*a1 a2 = -2*a1
a1 += 180. a1 += 180.
self.path.arcMoveTo(arc, a1) self.path.arcMoveTo(arc, a1)
@ -406,7 +411,7 @@ class CircleSurface(pg.GraphicsObject):
if abs(y) > h: if abs(y) > h:
return None, None return None, None
else: else:
return (Point(0, y), np.arctan2(dir[1], dir[0])) return (Point(0, y), atan2(dir[1], dir[0]))
else: else:
#print " curve" #print " curve"
## find intersection of circle and line (quadratic formula) ## find intersection of circle and line (quadratic formula)
@ -436,19 +441,12 @@ class CircleSurface(pg.GraphicsObject):
pt = Point(x2, y2) pt = Point(x2, y2)
if not br.contains(x2+r, y2): if not br.contains(x2+r, y2):
return None, None return None, None
raise Exception("No intersection!")
norm = np.arctan2(pt[1], pt[0]) norm = atan2(pt[1], pt[0])
if r < 0: if r < 0:
norm += np.pi norm += pi
#print " norm:", norm*180/3.1415
dp = p - pt dp = p - pt
#print " dp:", dp ang = atan2(dp[1], dp[0])
ang = np.arctan2(dp[1], dp[0])
#print " ang:", ang*180/3.1415
#print " ai:", (ang-norm)*180/3.1415
#print " intersection:", pt
return pt + Point(r, 0), ang-norm return pt + Point(r, 0), ang-norm

View File

@ -6,7 +6,7 @@ Distributed under MIT/X11 license. See license.txt for more information.
""" """
from .Qt import QtCore from .Qt import QtCore
import numpy as np from math import sin, acos, atan2, inf, pi
def clip(x, mn, mx): def clip(x, mn, mx):
if x > mx: if x > mx:
@ -109,9 +109,9 @@ class Point(QtCore.QPointF):
return (self[0]**2 + self[1]**2) ** 0.5 return (self[0]**2 + self[1]**2) ** 0.5
except OverflowError: except OverflowError:
try: try:
return self[1] / np.sin(np.arctan2(self[1], self[0])) return self[1] / sin(atan2(self[1], self[0]))
except OverflowError: except OverflowError:
return np.inf return inf
def norm(self): def norm(self):
"""Returns a vector in the same direction with unit length.""" """Returns a vector in the same direction with unit length."""
@ -124,11 +124,11 @@ class Point(QtCore.QPointF):
if n1 == 0. or n2 == 0.: if n1 == 0. or n2 == 0.:
return None return None
## Probably this should be done with arctan2 instead.. ## Probably this should be done with arctan2 instead..
ang = np.arccos(clip(self.dot(a) / (n1 * n2), -1.0, 1.0)) ### in radians ang = acos(clip(self.dot(a) / (n1 * n2), -1.0, 1.0)) ### in radians
c = self.cross(a) c = self.cross(a)
if c > 0: if c > 0:
ang *= -1. ang *= -1.
return ang * 180. / np.pi return ang * 180. / pi
def dot(self, a): def dot(self, a):
"""Returns the dot product of a and this Point.""" """Returns the dot product of a and this Point."""

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from math import atan2, pi
from .Qt import QtCore, QtGui from .Qt import QtCore, QtGui
from .Point import Point from .Point import Point
import numpy as np import numpy as np
@ -76,7 +77,7 @@ class SRTTransform(QtGui.QTransform):
self._state = { self._state = {
'pos': Point(p1), 'pos': Point(p1),
'scale': Point(dp2.length(), dp3.length() * sy), 'scale': Point(dp2.length(), dp3.length() * sy),
'angle': (np.arctan2(dp2[1], dp2[0]) * 180. / np.pi) + da 'angle': (atan2(dp2[1], dp2[0]) * 180. / pi) + da
} }
self.update() self.update()

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from math import atan2, pi
from .Qt import QtCore, QtGui from .Qt import QtCore, QtGui
from .Vector import Vector from .Vector import Vector
from .Transform3D import Transform3D from .Transform3D import Transform3D
@ -164,7 +165,7 @@ class SRTTransform3D(Transform3D):
sin = (r-r.T)[rInd] / (2. * sign * axis[axisInd]) sin = (r-r.T)[rInd] / (2. * sign * axis[axisInd])
## finally, we get the complete angle from arctan(sin/cos) ## finally, we get the complete angle from arctan(sin/cos)
self._state['angle'] = np.arctan2(sin, cos) * 180 / np.pi self._state['angle'] = atan2(sin, cos) * 180 / pi
if self._state['angle'] == 0: if self._state['angle'] == 0:
self._state['axis'] = (0,0,1) self._state['axis'] = (0,0,1)

View File

@ -1,5 +1,7 @@
from math import atan2, pi
from ..Qt import QtGui, QtCore from ..Qt import QtGui, QtCore
from . import ArrowItem from . import ArrowItem
from ..functions import clip_scalar
import numpy as np import numpy as np
from ..Point import Point from ..Point import Point
import weakref import weakref
@ -65,22 +67,22 @@ class CurvePoint(GraphicsObject):
if index != int(index): ## interpolate floating-point values if index != int(index): ## interpolate floating-point values
i1 = int(index) i1 = int(index)
i2 = np.clip(i1+1, 0, len(x)-1) i2 = clip_scalar(i1+1, 0, len(x)-1)
s2 = index-i1 s2 = index-i1
s1 = 1.0-s2 s1 = 1.0-s2
newPos = (x[i1]*s1+x[i2]*s2, y[i1]*s1+y[i2]*s2) newPos = (x[i1]*s1+x[i2]*s2, y[i1]*s1+y[i2]*s2)
else: else:
index = int(index) index = int(index)
i1 = np.clip(index-1, 0, len(x)-1) i1 = clip_scalar(index-1, 0, len(x)-1)
i2 = np.clip(index+1, 0, len(x)-1) i2 = clip_scalar(index+1, 0, len(x)-1)
newPos = (x[index], y[index]) newPos = (x[index], y[index])
p1 = self.parentItem().mapToScene(QtCore.QPointF(x[i1], y[i1])) p1 = self.parentItem().mapToScene(QtCore.QPointF(x[i1], y[i1]))
p2 = self.parentItem().mapToScene(QtCore.QPointF(x[i2], y[i2])) p2 = self.parentItem().mapToScene(QtCore.QPointF(x[i2], y[i2]))
ang = np.arctan2(p2.y()-p1.y(), p2.x()-p1.x()) ## returns radians ang = atan2(p2.y()-p1.y(), p2.x()-p1.x()) ## returns radians
self.resetTransform() self.resetTransform()
if self._rotate: if self._rotate:
self.setRotation(180 + np.rad2deg(ang)) ## takes degrees self.setRotation(180 + ang * (180. / pi))
QtGui.QGraphicsItem.setPos(self, *newPos) QtGui.QGraphicsItem.setPos(self, *newPos)
return True return True

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from math import atan2, pi
from ..Qt import QtGui, QtCore from ..Qt import QtGui, QtCore
from ..Point import Point from ..Point import Point
from .GraphicsObject import GraphicsObject from .GraphicsObject import GraphicsObject
@ -359,7 +360,7 @@ class InfiniteLine(GraphicsObject):
up = tr.map(Point(left, 1)) up = tr.map(Point(left, 1))
dif = end - start dif = end - start
length = Point(dif).length() length = Point(dif).length()
angle = np.arctan2(dif.y(), dif.x()) * 180 / np.pi angle = atan2(dif.y(), dif.x()) * 180 / pi
p.translate(start) p.translate(start)
p.rotate(angle) p.rotate(angle)

View File

@ -17,7 +17,7 @@ import numpy as np
#from numpy.linalg import norm #from numpy.linalg import norm
from ..Point import * from ..Point import *
from ..SRTTransform import SRTTransform from ..SRTTransform import SRTTransform
from math import cos, sin from math import atan2, cos, sin, pi, sqrt
from .. import functions as fn from .. import functions as fn
from .GraphicsObject import GraphicsObject from .GraphicsObject import GraphicsObject
from .UIGraphicsItem import UIGraphicsItem from .UIGraphicsItem import UIGraphicsItem
@ -1247,8 +1247,8 @@ class ROI(GraphicsObject):
vx = img.mapToData(self.mapToItem(img, QtCore.QPointF(1, 0))) - origin vx = img.mapToData(self.mapToItem(img, QtCore.QPointF(1, 0))) - origin
vy = img.mapToData(self.mapToItem(img, QtCore.QPointF(0, 1))) - origin vy = img.mapToData(self.mapToItem(img, QtCore.QPointF(0, 1))) - origin
lvx = np.sqrt(vx.x()**2 + vx.y()**2) lvx = sqrt(vx.x()**2 + vx.y()**2)
lvy = np.sqrt(vy.x()**2 + vy.y()**2) lvy = sqrt(vy.x()**2 + vy.y()**2)
##img.width is number of pixels, not width of item. ##img.width is number of pixels, not width of item.
##need pxWidth and pxHeight instead of pxLen ? ##need pxWidth and pxHeight instead of pxLen ?
sx = 1.0 / lvx sx = 1.0 / lvx
@ -1332,8 +1332,8 @@ class Handle(UIGraphicsItem):
properties of the ROI they are attached to. properties of the ROI they are attached to.
""" """
types = { ## defines number of sides, start angle for each handle type types = { ## defines number of sides, start angle for each handle type
't': (4, np.pi/4), 't': (4, pi/4),
'f': (4, np.pi/4), 'f': (4, pi/4),
's': (4, 0), 's': (4, 0),
'r': (12, 0), 'r': (12, 0),
'sr': (12, 0), 'sr': (12, 0),
@ -1481,7 +1481,7 @@ class Handle(UIGraphicsItem):
size = self.radius size = self.radius
self.path = QtGui.QPainterPath() self.path = QtGui.QPainterPath()
ang = self.startAng ang = self.startAng
dt = 2*np.pi / self.sides dt = 2 * pi / self.sides
for i in range(0, self.sides+1): for i in range(0, self.sides+1):
x = size * cos(ang) x = size * cos(ang)
y = size * sin(ang) y = size * sin(ang)
@ -1518,13 +1518,13 @@ class Handle(UIGraphicsItem):
return None return None
v = dt.map(QtCore.QPointF(1, 0)) - dt.map(QtCore.QPointF(0, 0)) v = dt.map(QtCore.QPointF(1, 0)) - dt.map(QtCore.QPointF(0, 0))
va = np.arctan2(v.y(), v.x()) va = atan2(v.y(), v.x())
dti = fn.invertQTransform(dt) dti = fn.invertQTransform(dt)
devPos = dt.map(QtCore.QPointF(0,0)) devPos = dt.map(QtCore.QPointF(0,0))
tr = QtGui.QTransform() tr = QtGui.QTransform()
tr.translate(devPos.x(), devPos.y()) tr.translate(devPos.x(), devPos.y())
tr.rotate(va * 180. / 3.1415926) tr.rotate(va * 180. / pi)
return dti.map(tr.map(self.path)) return dti.map(tr.map(self.path))
@ -1663,7 +1663,7 @@ class LineROI(ROI):
d = pos2-pos1 d = pos2-pos1
l = d.length() l = d.length()
ang = Point(1, 0).angle(d) ang = Point(1, 0).angle(d)
ra = ang * np.pi / 180. ra = ang * pi / 180.
c = Point(-width/2. * sin(ra), -width/2. * cos(ra)) c = Point(-width/2. * sin(ra), -width/2. * cos(ra))
pos1 = pos1 + c pos1 = pos1 + c
@ -1914,7 +1914,7 @@ class EllipseROI(ROI):
center = br.center() center = br.center()
r1 = br.width() / 2. r1 = br.width() / 2.
r2 = br.height() / 2. r2 = br.height() / 2.
theta = np.linspace(0, 2*np.pi, 24) theta = np.linspace(0, 2 * pi, 24)
x = center.x() + r1 * np.cos(theta) x = center.x() + r1 * np.cos(theta)
y = center.y() + r2 * np.sin(theta) y = center.y() + r2 * np.sin(theta)
path.moveTo(x[0], y[0]) path.moveTo(x[0], y[0])
@ -2396,7 +2396,7 @@ class TriangleROI(ROI):
def __init__(self, pos, size, **args): def __init__(self, pos, size, **args):
ROI.__init__(self, pos, [size, size], **args) ROI.__init__(self, pos, [size, size], **args)
self.aspectLocked = True self.aspectLocked = True
angles = np.linspace(0, np.pi * 4 / 3, 3) angles = np.linspace(0, pi * 4 / 3, 3)
verticies = (np.array((np.sin(angles), np.cos(angles))).T + 1.0) / 2.0 verticies = (np.array((np.sin(angles), np.cos(angles))).T + 1.0) / 2.0
self.poly = QtGui.QPolygonF() self.poly = QtGui.QPolygonF()
for pt in verticies: for pt in verticies:

View File

@ -1,4 +1,4 @@
import numpy as np from math import pi, atan2
from ..Qt import QtCore, QtGui from ..Qt import QtCore, QtGui
from ..Point import Point from ..Point import Point
from .. import functions as fn from .. import functions as fn
@ -208,7 +208,7 @@ class TextItem(GraphicsObject):
angle = -self.angle angle = -self.angle
if self.rotateAxis is not None: if self.rotateAxis is not None:
d = pt.map(self.rotateAxis) - pt.map(Point(0, 0)) d = pt.map(self.rotateAxis) - pt.map(Point(0, 0))
a = np.arctan2(d.y(), d.x()) * 180 / np.pi a = atan2(d.y(), d.x()) * 180 / pi
angle += a angle += a
t.rotate(angle) t.rotate(angle)
self.setTransform(t) self.setTransform(t)