예제 #1
0
def test_arrayToQPath(xs, ys, connect, expected):
    path = arrayToQPath(xs, ys, connect=connect)
    for i in range(path.elementCount()):
        with suppress(NameError):
            # nan elements add two line-segments, for simplicity of test config
            # we can ignore the second segment
            if (eq(element.x, np.nan) or eq(element.y, np.nan)):
                continue
        element = path.elementAt(i)
        assert eq(expected[i], (element.type, element.x, element.y))
예제 #2
0
def check_param_types(param, types, map_func, init, objs, keys):
    """Check that parameter setValue() accepts or rejects the correct types and
    that value() returns the correct type.
    
    Parameters
    ----------
        param : Parameter instance
        types : type or tuple of types
            The allowed types for this parameter to return from value().
        map_func : function
            Converts an input value to the expected output value.
        init : object
            The expected initial value of the parameter
        objs : dict
            Contains a variety of objects that will be tested as arguments to
            param.setValue().
        keys : list
            The list of keys indicating the valid objects in *objs*. When
            param.setValue() is teasted with each value from *objs*, we expect
            an exception to be raised if the associated key is not in *keys*.
    """
    val = param.value()
    if not isinstance(types, tuple):
        types = (types, )
    assert val == init and type(val) in types

    # test valid input types
    good_inputs = [objs[k] for k in keys if k in objs]
    good_outputs = map(map_func, good_inputs)
    for x, y in zip(good_inputs, good_outputs):
        param.setValue(x)
        val = param.value()
        if not (eq(val, y) and type(val) in types):
            raise Exception(
                "Setting parameter %s with value %r should have resulted in %r (types: %r), "
                "but resulted in %r (type: %r) instead." %
                (param, x, y, types, val, type(val)))

    # test invalid input types
    for k, v in objs.items():
        if k in keys:
            continue
        try:
            param.setValue(v)
        except (TypeError, ValueError, OverflowError):
            continue
        except Exception as exc:
            raise Exception("Setting %s parameter value to %r raised %r." %
                            (param, v, exc))

        raise Exception(
            "Setting %s parameter value to %r should have raised an exception."
            % (param, v))
예제 #3
0
def check_param_types(param, types, map_func, init, objs, keys):
    """Check that parameter setValue() accepts or rejects the correct types and
    that value() returns the correct type.
    
    Parameters
    ----------
        param : Parameter instance
        types : type or tuple of types
            The allowed types for this parameter to return from value().
        map_func : function
            Converts an input value to the expected output value.
        init : object
            The expected initial value of the parameter
        objs : dict
            Contains a variety of objects that will be tested as arguments to
            param.setValue().
        keys : list
            The list of keys indicating the valid objects in *objs*. When
            param.setValue() is teasted with each value from *objs*, we expect
            an exception to be raised if the associated key is not in *keys*.
    """
    val = param.value()
    if not isinstance(types, tuple):
        types = (types,)
    assert val == init and type(val) in types
    
    # test valid input types
    good_inputs = [objs[k] for k in keys if k in objs]
    good_outputs = map(map_func, good_inputs)
    for x,y in zip(good_inputs, good_outputs):
        param.setValue(x)
        val = param.value()
        if not (eq(val, y) and type(val) in types):
            raise Exception("Setting parameter %s with value %r should have resulted in %r (types: %r), "
                "but resulted in %r (type: %r) instead." % (param, x, y, types, val, type(val)))
        
    # test invalid input types
    for k,v in objs.items():
        if k in keys:
            continue
        try:
            param.setValue(v)
        except (TypeError, ValueError, OverflowError):
            continue
        except Exception as exc:
            raise Exception("Setting %s parameter value to %r raised %r." % (param, v, exc))
        
        raise Exception("Setting %s parameter value to %r should have raised an exception." % (param, v))
예제 #4
0
 def setLevels(self, levels, update=True):
     """
     Set image scaling levels. Can be one of:
     
     * [blackLevel, whiteLevel]
     * [[minRed, maxRed], [minGreen, maxGreen], [minBlue, maxBlue]]
         
     Only the first format is compatible with lookup tables. See :func:`makeARGB <pyqtgraph.makeARGB>`
     for more details on how levels are applied.
     """
     if levels is not None:
         levels = np.asarray(levels)
     if not fn.eq(levels, self.levels):
         self.levels = levels
         self._effectiveLut = None
         if update:
             self.updateImage()
예제 #5
0
    def arrayToQPath(x, y, connect='all'):
        """Convert an array of x,y coordinats to QPainterPath as efficiently as possible.
        The *connect* argument may be 'all', indicating that each point should be
        connected to the next; 'pairs', indicating that each pair of points
        should be connected, or an array of int32 values (0 or 1) indicating
        connections.
        """

        ## Create all vertices in path. The method used below creates a binary format so that all
        ## vertices can be read in at once. This binary format may change in future versions of Qt,
        ## so the original (slower) method is left here for emergencies:
        # path.moveTo(x[0], y[0])
        # if connect == 'all':
        # for i in range(1, y.shape[0]):
        # path.lineTo(x[i], y[i])
        # elif connect == 'pairs':
        # for i in range(1, y.shape[0]):
        # if i%2 == 0:
        # path.lineTo(x[i], y[i])
        # else:
        # path.moveTo(x[i], y[i])
        # elif isinstance(connect, np.ndarray):
        # for i in range(1, y.shape[0]):
        # if connect[i] == 1:
        # path.lineTo(x[i], y[i])
        # else:
        # path.moveTo(x[i], y[i])
        # else:
        # raise Exception('connect argument must be "all", "pairs", or array')

        ## Speed this up using >> operator
        ## Format is:
        ##    numVerts(i4)
        ##    0(i4)   x(f8)   y(f8)    <-- 0 means this vertex does not connect
        ##    1(i4)   x(f8)   y(f8)    <-- 1 means this vertex connects to the previous vertex
        ##    ...
        ##    cStart(i4)   fillRule(i4)
        ##
        ## see: https://github.com/qt/qtbase/blob/dev/src/gui/painting/qpainterpath.cpp

        ## All values are big endian--pack using struct.pack('>d') or struct.pack('>i')

        path = QtGui.QPainterPath()

        n = x.shape[0]

        # create empty array, pad with extra space on either end
        arr = np.empty(n + 2, dtype=[('c', '>i4'), ('x', '>f8'), ('y', '>f8')])

        # write first two integers
        byteview = arr.view(dtype=np.ubyte)
        byteview[:16] = 0
        byteview.data[16:20] = struct.pack('>i', n)

        # Fill array with vertex values
        arr[1:-1]['x'] = x
        arr[1:-1]['y'] = y

        # inf/nans completely prevent the plot from being displayed starting on
        # Qt version 5.12.3; these must now be manually cleaned out.
        isfinite = None
        qtver = [int(x) for x in QtVersion.split('.')]
        if qtver >= [5, 12, 3]:
            isfinite = np.isfinite(x) & np.isfinite(y)
            if not np.all(isfinite):
                # credit: Divakar https://stackoverflow.com/a/41191127/643629
                mask = ~isfinite
                idx = np.arange(len(x))
                idx[mask] = -1
                np.maximum.accumulate(idx, out=idx)
                first = np.searchsorted(idx, 0)
                if first < len(x):
                    # Replace all non-finite entries from beginning of arr with the first finite one
                    idx[:first] = first
                    arr[1:-1] = arr[1:-1][idx]

        # decide which points are connected by lines
        if eq(connect, 'all'):
            arr[1:-1]['c'] = 1
        elif eq(connect, 'pairs'):
            arr[1:-1]['c'][::2] = 0
            arr[1:-1]['c'][
                1::2] = 1  # connect every 2nd point to every 1st one
        elif eq(connect, 'finite'):
            # Let's call a point with either x or y being nan is an invalid point.
            # A point will anyway not connect to an invalid point regardless of the
            # 'c' value of the invalid point. Therefore, we should set 'c' to 0 for
            # the next point of an invalid point.
            if isfinite is None:
                isfinite = np.isfinite(x) & np.isfinite(y)
            arr[2:]['c'] = isfinite
        elif isinstance(connect, np.ndarray):
            arr[1:-1]['c'] = connect
        else:
            raise Exception(
                'connect argument must be "all", "pairs", "finite", or array')

        arr[1]['c'] = 0  # the first vertex has no previous vertex to connect

        byteview.data[-20:-16] = struct.pack('>i', 0)  # cStart
        byteview.data[-16:-12] = struct.pack('>i',
                                             0)  # fillRule (Qt.OddEvenFill)

        # create datastream object and stream into path

        ## Avoiding this method because QByteArray(str) leaks memory in PySide
        # buf = QtCore.QByteArray(arr.data[12:lastInd+4])  # I think one unnecessary copy happens here

        path.strn = byteview.data[16:-12]  # make sure data doesn't run away
        try:
            buf = QtCore.QByteArray.fromRawData(path.strn)
        except TypeError:
            buf = QtCore.QByteArray(bytes(path.strn))

        ds = QtCore.QDataStream(buf)
        ds >> path

        return path
예제 #6
0
def test_eq():
    eq = pg.functions.eq

    zeros = [0, 0.0, np.float64(0), np.float32(0), np.int32(0), np.int64(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))
    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)

    assert not eq(a2, a3)  # same values, but different dtype
    assert not eq(a2, a4)  # different shape

    assert not eq(a3, a4)  # different shape and dtype

    assert eq(a4, a4.copy())
    assert not eq(a4, a4.T)

    # test containers

    assert not eq({'a': 1}, {'a': 1, 'b': 2})
    assert not eq({'a': 1}, {'a': 2})
    d1 = {'x': 1, 'y': np.nan, 3: ['a', np.nan, a3, 7, 2.3], 4: a4}
    d2 = deepcopy(d1)
    assert eq(d1, d2)
    d1_ordered = OrderedDict(d1)
    d2_ordered = deepcopy(d1_ordered)
    assert eq(d1_ordered, d2_ordered)
    assert not eq(d1_ordered, d2)
    items = list(d1.items())
    assert not eq(OrderedDict(items), OrderedDict(reversed(items)))

    assert not eq([1, 2, 3], [1, 2, 3, 4])
    l1 = [d1, np.inf, -np.inf, np.nan]
    l2 = deepcopy(l1)
    t1 = tuple(l1)
    t2 = tuple(l2)
    assert eq(l1, l2)
    assert eq(t1, t2)

    assert eq(set(range(10)), set(range(10)))
    assert not eq(set(range(10)), set(range(9)))