pyqtgraph/pyqtgraph/tests/test_functions.py

361 lines
13 KiB
Python
Raw Normal View History

2014-03-11 03:45:27 +00:00
import pyqtgraph as pg
import numpy as np
import sys
2014-03-11 03:45:27 +00:00
from numpy.testing import assert_array_almost_equal, assert_almost_equal
2015-02-16 16:23:52 +00:00
import pytest
2014-03-11 03:45:27 +00:00
np.random.seed(12345)
def testSolve3D():
p1 = np.array([[0,0,0,1],
[1,0,0,1],
[0,1,0,1],
[0,0,1,1]], dtype=float)
# transform points through random matrix
tr = np.random.normal(size=(4, 4))
tr[3] = (0,0,0,1)
p2 = np.dot(tr, p1.T).T[:,:3]
# solve to see if we can recover the transformation matrix.
tr2 = pg.solve3DTransform(p1, p2)
assert_array_almost_equal(tr[:3], tr2[:3])
def test_interpolateArray_order0():
check_interpolateArray(order=0)
def test_interpolateArray_order1():
check_interpolateArray(order=1)
def check_interpolateArray(order):
def interpolateArray(data, x):
result = pg.interpolateArray(data, x, order=order)
assert result.shape == x.shape[:-1] + data.shape[x.shape[-1]:]
return result
data = np.array([[ 1., 2., 4. ],
[ 10., 20., 40. ],
[ 100., 200., 400.]])
# test various x shapes
interpolateArray(data, np.ones((1,)))
interpolateArray(data, np.ones((2,)))
interpolateArray(data, np.ones((1, 1)))
interpolateArray(data, np.ones((1, 2)))
interpolateArray(data, np.ones((5, 1)))
interpolateArray(data, np.ones((5, 2)))
interpolateArray(data, np.ones((5, 5, 1)))
interpolateArray(data, np.ones((5, 5, 2)))
with pytest.raises(TypeError):
interpolateArray(data, np.ones((3,)))
with pytest.raises(TypeError):
interpolateArray(data, np.ones((1, 3,)))
with pytest.raises(TypeError):
interpolateArray(data, np.ones((5, 5, 3,)))
x = np.array([[ 0.3, 0.6],
[ 1. , 1. ],
2016-10-12 17:26:54 +00:00
[ 0.501, 1. ], # NOTE: testing at exactly 0.5 can yield different results from map_coordinates
[ 0.501, 2.501], # due to differences in rounding
[ 10. , 10. ]])
result = interpolateArray(data, x)
# make sure results match ndimage.map_coordinates
import scipy.ndimage
spresult = scipy.ndimage.map_coordinates(data, x.T, order=order)
#spresult = np.array([ 5.92, 20. , 11. , 0. , 0. ]) # generated with the above line
assert_array_almost_equal(result, spresult)
# test mapping when x.shape[-1] < data.ndim
x = np.array([[ 0.3, 0],
[ 0.3, 1],
[ 0.3, 2]])
r1 = interpolateArray(data, x)
x = np.array([0.3]) # should broadcast across axis 1
r2 = interpolateArray(data, x)
assert_array_almost_equal(r1, r2)
# test mapping 2D array of locations
2016-10-12 17:26:54 +00:00
x = np.array([[[0.501, 0.501], [0.501, 1.0], [0.501, 1.501]],
[[1.501, 0.501], [1.501, 1.0], [1.501, 1.501]]])
r1 = interpolateArray(data, x)
r2 = scipy.ndimage.map_coordinates(data, x.transpose(2,0,1), order=order)
#r2 = np.array([[ 8.25, 11. , 16.5 ], # generated with the above line
#[ 82.5 , 110. , 165. ]])
Added Travis CI support Fixed bugs / style issues to please Lord Travis Squashed commit of the following: commit f25048a1e1e9d0be355f33fbaff6ef74845f4782 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Sun Mar 30 02:40:47 2014 -0400 syntax commit cc8b69695a2698b75ff216dce27fabe46c79a325 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Sun Mar 30 02:36:49 2014 -0400 add size check, diff style check commit 5d5ea065a4d4cc714bfaf7c7e7624295164cd86c Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Sun Mar 30 02:16:05 2014 -0400 travis fix commit b154c6d9971d35c2a46e575a0a884880ec14c8b1 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Sun Mar 30 02:09:41 2014 -0400 travis, flake colored output commit 46921dcd878fdc08f05ef74d08be7953b1820a85 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Wed Mar 26 12:37:54 2014 -0400 fix pyside+py3 bugs to satisfy CI commit 1d30f3c5c7763876ccfff54e460b83cb7422a5b4 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Wed Mar 26 11:13:18 2014 -0400 fix py3 tests commit 426578fa4c5ec991d361c60005c32ca88c85e505 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Wed Mar 26 07:39:19 2014 -0400 fix pytest install commit 88a13c1a7158904af7d25c5ba5bfc8e63e6cf49d Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Wed Mar 26 00:29:29 2014 -0400 qt5 updates commit 51995488ccc9f286aeced3bd49c3213819529e57 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Wed Mar 26 00:16:04 2014 -0400 correct py.test command for py3 commit e2b02fbcbdbd95cbec5dd9307870f39337e6eb45 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 23:50:38 2014 -0400 fix 2nd install test commit 4b3e3ee04adee3a8d1aabdfb18a198cbd0e83a06 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 23:31:31 2014 -0400 syntax error commit 250eabdb34cac48d6f9622e6453235f0ec7f1151 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 23:13:42 2014 -0400 look for py.test3 commit 9f9bca47c1a0a5c35be21835a674058242aa5f48 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 22:54:19 2014 -0400 fix syntax commit 0a871c6f36ecddb7a1002b74d3b6d433e1648e8f Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 22:47:58 2014 -0400 output pip build log commit dbce58d8cd3f3a558202f8d7a149b5ec8fbfcf78 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 22:38:55 2014 -0400 no comments allowed between shall lines commit b79c06121d8e40d8b2d2db0a4dd0a60fbf48edba Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 20:56:35 2014 -0400 another pip try commit 09f4f5d82ab41f66e5c746985f09dfcbe36f2089 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 13:36:09 2014 -0400 pip correction commit 0eedb5c18e7242370f996c6b7481fbcdc8e6caf2 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 13:29:00 2014 -0400 correct py version output commit d9fd039be22cb297f4de83f7ab543de25e2969dd Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 11:55:43 2014 -0400 apt checks commit cf95ccef86bd26964d73bdc649de8f23f64d2575 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Tue Mar 25 10:23:10 2014 -0400 alternate pip install method commit bee0bcddfef44917a5ee425557ba6ff246edec87 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 23:51:45 2014 -0400 correct deps install commit 963a4211fcaa5ebbfe0e13a5d879635bd77334ac Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 23:47:30 2014 -0400 fixes commit 0c86cd1dc28e286f999f01b37beb3c3252a8c864 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 23:31:06 2014 -0400 permission fix commit 5d04ef53b80a83aa62452ff9a9f9152ca862f8d8 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 23:30:19 2014 -0400 Fix py.test version selection commit b0e6c7cb94c7fa85653e492f8817e79b1ca30426 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 23:25:34 2014 -0400 try another pyqt5 install method commit 422a7928665b5afb72861400672cc81b4bcd9779 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 23:12:36 2014 -0400 syntax error commit 533133905a8e4f2ba26bc6e8f0e4fe631fbd119e Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 23:04:37 2014 -0400 fixes commit 8d65211ba4e08e4f4b13b68f9778c3aee4b43cdc Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 22:40:18 2014 -0400 Add Qt5 test minor fixes commit 4484efaefe0c99516940812d0472e82998e801f6 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 22:31:56 2014 -0400 use correct py.test for python version commit 5d2441a29b98ed573e15580fc5efd533352ffb45 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 22:24:27 2014 -0400 add setup tests commit 9291db64f25afeb46ee46d92b3bd13aabb325cfe Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 21:48:43 2014 -0400 fix py3-pyqt install commit a7aa675c5a5a5c4a2fff69feefc9298bcc626641 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 21:31:33 2014 -0400 travis tests commit e71cd2b23ab09490c29c1c8ee18fc4db87ff0c01 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 21:17:15 2014 -0400 more corrections commit 527df3bca897ba6a02cb3fe4a5a6db34042600b5 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 20:56:01 2014 -0400 travis corrections commit 87d65cac4aa3bf815860030fac78e8e28069e29d Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 20:48:02 2014 -0400 Add flake tests Correct style in a few files to please Lord Travis commit 537028f88f17da59a6e8a09b9a3dee34282791cf Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 17:36:24 2014 -0400 minimize pyside package install correct line endings to satisfy Lord Travis commit 1e3cc95e37f03f70f50900dcb2e8a4dc4772208a Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 17:23:03 2014 -0400 enable pyside, line ending check fix test commit d7df4517f9004399703cb44237d27be313405e84 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 17:12:06 2014 -0400 syntax fix commit 1ad77a21551c38f7ff77bd537eb6c2a9e13a26ae Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 17:00:30 2014 -0400 alt. pytest install commit 5edcc020729b1ecd452555852652720b4c3285f5 Author: Luke Campagnola <luke.campagnola@gmail.com> Date: Mon Mar 24 16:52:33 2014 -0400 Added initial travis.yml
2014-03-30 06:51:32 +00:00
assert_array_almost_equal(r1, r2)
def test_subArray():
a = np.array([0, 0, 111, 112, 113, 0, 121, 122, 123, 0, 0, 0, 211, 212, 213, 0, 221, 222, 223, 0, 0, 0, 0])
b = pg.subArray(a, offset=2, shape=(2,2,3), stride=(10,4,1))
c = np.array([[[111,112,113], [121,122,123]], [[211,212,213], [221,222,223]]])
assert np.all(b == c)
# operate over first axis; broadcast over the rest
aa = np.vstack([a, a/100.]).T
cc = np.empty(c.shape + (2,))
cc[..., 0] = c
cc[..., 1] = c / 100.
bb = pg.subArray(aa, offset=2, shape=(2,2,3), stride=(10,4,1))
assert np.all(bb == cc)
def test_rescaleData():
dtypes = map(np.dtype, ('ubyte', 'uint16', 'byte', 'int16', 'int', 'float'))
for dtype1 in dtypes:
for dtype2 in dtypes:
data = (np.random.random(size=10) * 2**32 - 2**31).astype(dtype1)
for scale, offset in [(10, 0), (10., 0.), (1, -50), (0.2, 0.5), (0.001, 0)]:
if dtype2.kind in 'iu':
lim = np.iinfo(dtype2)
lim = lim.min, lim.max
else:
lim = (-np.inf, np.inf)
s1 = np.clip(float(scale) * (data-float(offset)), *lim).astype(dtype2)
s2 = pg.rescaleData(data, scale, offset, dtype2)
assert s1.dtype == s2.dtype
if dtype2.kind in 'iu':
assert np.all(s1 == s2)
else:
assert np.allclose(s1, s2)
def test_makeARGB():
# Many parameters to test here:
# * data dtype (ubyte, uint16, float, others)
# * data ndim (2 or 3)
# * levels (None, 1D, or 2D)
# * lut dtype
# * lut size
# * lut ndim (1 or 2)
# * useRGBA argument
# Need to check that all input values map to the correct output values, especially
# at and beyond the edges of the level range.
def checkArrays(a, b):
# because py.test output is difficult to read for arrays
if not np.all(a == b):
comp = []
for i in range(a.shape[0]):
if a.shape[1] > 1:
comp.append('[')
for j in range(a.shape[1]):
m = a[i,j] == b[i,j]
comp.append('%d,%d %s %s %s%s' %
(i, j, str(a[i,j]).ljust(15), str(b[i,j]).ljust(15),
m, ' ********' if not np.all(m) else ''))
if a.shape[1] > 1:
comp.append(']')
raise Exception("arrays do not match:\n%s" % '\n'.join(comp))
def checkImage(img, check, alpha, alphaCheck):
assert img.dtype == np.ubyte
assert alpha is alphaCheck
if alpha is False:
checkArrays(img[..., 3], 255)
if np.isscalar(check) or check.ndim == 3:
checkArrays(img[..., :3], check)
elif check.ndim == 2:
checkArrays(img[..., :3], check[..., np.newaxis])
elif check.ndim == 1:
checkArrays(img[..., :3], check[..., np.newaxis, np.newaxis])
else:
raise Exception('invalid check array ndim')
# uint8 data tests
im1 = np.arange(256).astype('ubyte').reshape(256, 1)
im2, alpha = pg.makeARGB(im1, levels=(0, 255))
checkImage(im2, im1, alpha, False)
im3, alpha = pg.makeARGB(im1, levels=(0.0, 255.0))
checkImage(im3, im1, alpha, False)
im4, alpha = pg.makeARGB(im1, levels=(255, 0))
checkImage(im4, 255-im1, alpha, False)
im5, alpha = pg.makeARGB(np.concatenate([im1]*3, axis=1), levels=[(0, 255), (0.0, 255.0), (255, 0)])
checkImage(im5, np.concatenate([im1, im1, 255-im1], axis=1), alpha, False)
im2, alpha = pg.makeARGB(im1, levels=(128,383))
checkImage(im2[:128], 0, alpha, False)
checkImage(im2[128:], im1[:128], alpha, False)
# uint8 data + uint8 LUT
lut = np.arange(256)[::-1].astype(np.uint8)
im2, alpha = pg.makeARGB(im1, lut=lut)
checkImage(im2, lut, alpha, False)
# lut larger than maxint
lut = np.arange(511).astype(np.uint8)
im2, alpha = pg.makeARGB(im1, lut=lut)
checkImage(im2, lut[::2], alpha, False)
# lut smaller than maxint
lut = np.arange(128).astype(np.uint8)
im2, alpha = pg.makeARGB(im1, lut=lut)
checkImage(im2, np.linspace(0, 127.5, 256, dtype='ubyte'), alpha, False)
# lut + levels
lut = np.arange(256)[::-1].astype(np.uint8)
im2, alpha = pg.makeARGB(im1, lut=lut, levels=[-128, 384])
checkImage(im2, np.linspace(191.5, 64.5, 256, dtype='ubyte'), alpha, False)
im2, alpha = pg.makeARGB(im1, lut=lut, levels=[64, 192])
checkImage(im2, np.clip(np.linspace(384.5, -127.5, 256), 0, 255).astype('ubyte'), alpha, False)
# uint8 data + uint16 LUT
lut = np.arange(4096)[::-1].astype(np.uint16) // 16
im2, alpha = pg.makeARGB(im1, lut=lut)
checkImage(im2, np.arange(256)[::-1].astype('ubyte'), alpha, False)
# uint8 data + float LUT
lut = np.linspace(10., 137., 256)
im2, alpha = pg.makeARGB(im1, lut=lut)
checkImage(im2, lut.astype('ubyte'), alpha, False)
# uint8 data + 2D LUT
lut = np.zeros((256, 3), dtype='ubyte')
lut[:,0] = np.arange(256)
lut[:,1] = np.arange(256)[::-1]
lut[:,2] = 7
im2, alpha = pg.makeARGB(im1, lut=lut)
checkImage(im2, lut[:,None,::-1], alpha, False)
# check useRGBA
im2, alpha = pg.makeARGB(im1, lut=lut, useRGBA=True)
checkImage(im2, lut[:,None,:], alpha, False)
# uint16 data tests
im1 = np.arange(0, 2**16, 256).astype('uint16')[:, None]
im2, alpha = pg.makeARGB(im1, levels=(512, 2**16))
checkImage(im2, np.clip(np.linspace(-2, 253, 256), 0, 255).astype('ubyte'), alpha, False)
lut = (np.arange(512, 2**16)[::-1] // 256).astype('ubyte')
im2, alpha = pg.makeARGB(im1, lut=lut, levels=(512, 2**16-256))
checkImage(im2, np.clip(np.linspace(257, 2, 256), 0, 255).astype('ubyte'), alpha, False)
2016-01-30 17:52:37 +00:00
lut = np.zeros(2**16, dtype='ubyte')
lut[1000:1256] = np.arange(256)
lut[1256:] = 255
im1 = np.arange(1000, 1256).astype('uint16')[:, None]
im2, alpha = pg.makeARGB(im1, lut=lut)
checkImage(im2, np.arange(256).astype('ubyte'), alpha, False)
# float data tests
im1 = np.linspace(1.0, 17.0, 256)[:, None]
im2, alpha = pg.makeARGB(im1, levels=(5.0, 13.0))
checkImage(im2, np.clip(np.linspace(-128, 383, 256), 0, 255).astype('ubyte'), alpha, False)
lut = (np.arange(1280)[::-1] // 10).astype('ubyte')
im2, alpha = pg.makeARGB(im1, lut=lut, levels=(1, 17))
checkImage(im2, np.linspace(127.5, 0, 256).astype('ubyte'), alpha, False)
# test sanity checks
class AssertExc(object):
def __init__(self, exc=Exception):
self.exc = exc
def __enter__(self):
return self
def __exit__(self, *args):
assert args[0] is self.exc, "Should have raised %s (got %s)" % (self.exc, args[0])
return True
with AssertExc(TypeError): # invalid image shape
pg.makeARGB(np.zeros((2,), dtype='float'))
with AssertExc(TypeError): # invalid image shape
pg.makeARGB(np.zeros((2,2,7), dtype='float'))
with AssertExc(): # float images require levels arg
pg.makeARGB(np.zeros((2,2), dtype='float'))
with AssertExc(): # bad levels arg
pg.makeARGB(np.zeros((2,2), dtype='float'), levels=[1])
with AssertExc(): # bad levels arg
pg.makeARGB(np.zeros((2,2), dtype='float'), levels=[1,2,3])
with AssertExc(): # can't mix 3-channel levels and LUT
pg.makeARGB(np.zeros((2,2)), lut=np.zeros((10,3), dtype='ubyte'), levels=[(0,1)]*3)
with AssertExc(): # multichannel levels must have same number of channels as image
pg.makeARGB(np.zeros((2,2,3), dtype='float'), levels=[(1,2)]*4)
with AssertExc(): # 3d levels not allowed
pg.makeARGB(np.zeros((2,2,3), dtype='float'), levels=np.zeros([3, 2, 2]))
def test_eq():
eq = pg.functions.eq
zeros = [0, 0.0, np.float(0), np.int(0)]
if sys.version[0] < '3':
zeros.append(long(0))
for i,x in enumerate(zeros):
for y in zeros[i:]:
assert eq(x, y)
assert eq(y, x)
assert eq(np.nan, np.nan)
# test
class NotEq(object):
def __eq__(self, x):
return False
noteq = NotEq()
assert eq(noteq, noteq) # passes because they are the same object
assert not eq(noteq, NotEq())
# Should be able to test for equivalence even if the test raises certain
# exceptions
class NoEq(object):
def __init__(self, err):
self.err = err
def __eq__(self, x):
raise self.err
noeq1 = NoEq(AttributeError())
noeq2 = NoEq(ValueError())
noeq3 = NoEq(Exception())
assert eq(noeq1, noeq1)
assert not eq(noeq1, noeq2)
assert not eq(noeq2, noeq1)
with pytest.raises(Exception):
eq(noeq3, noeq2)
# test array equivalence
# note that numpy has a weird behavior here--np.all() always returns True
# if one of the arrays has size=0; eq() will only return True if both arrays
# have the same shape.
a1 = np.zeros((10, 20)).astype('float')
a2 = a1 + 1
a3 = a2.astype('int')
a4 = np.empty((0, 20))
2017-10-04 16:35:57 +00:00
assert not eq(a1, a2) # same shape/dtype, different values
assert not eq(a1, a3) # same shape, different dtype and values
assert not eq(a1, a4) # different shape (note: np.all gives True if one array has size 0)
2017-10-04 16:35:57 +00:00
assert not eq(a2, a3) # same values, but different dtype
assert not eq(a2, a4) # different shape
2017-10-04 16:35:57 +00:00
assert not eq(a3, a4) # different shape and dtype
assert eq(a4, a4.copy())
assert not eq(a4, a4.T)
if __name__ == '__main__':
test_interpolateArray()