You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1183 lines
32 KiB
1183 lines
32 KiB
""" Basic functions for manipulating 2d arrays
|
|
|
|
"""
|
|
import functools
|
|
import operator
|
|
|
|
from numpy.core.numeric import (
|
|
asanyarray, arange, zeros, greater_equal, multiply, ones,
|
|
asarray, where, int8, int16, int32, int64, intp, empty, promote_types,
|
|
diagonal, nonzero, indices
|
|
)
|
|
from numpy.core.overrides import set_array_function_like_doc, set_module
|
|
from numpy.core import overrides
|
|
from numpy.core import iinfo
|
|
from numpy.lib.stride_tricks import broadcast_to
|
|
|
|
|
|
__all__ = [
|
|
'diag', 'diagflat', 'eye', 'fliplr', 'flipud', 'tri', 'triu',
|
|
'tril', 'vander', 'histogram2d', 'mask_indices', 'tril_indices',
|
|
'tril_indices_from', 'triu_indices', 'triu_indices_from', ]
|
|
|
|
|
|
array_function_dispatch = functools.partial(
|
|
overrides.array_function_dispatch, module='numpy')
|
|
|
|
|
|
i1 = iinfo(int8)
|
|
i2 = iinfo(int16)
|
|
i4 = iinfo(int32)
|
|
|
|
|
|
def _min_int(low, high):
|
|
""" get small int that fits the range """
|
|
if high <= i1.max and low >= i1.min:
|
|
return int8
|
|
if high <= i2.max and low >= i2.min:
|
|
return int16
|
|
if high <= i4.max and low >= i4.min:
|
|
return int32
|
|
return int64
|
|
|
|
|
|
def _flip_dispatcher(m):
|
|
return (m,)
|
|
|
|
|
|
@array_function_dispatch(_flip_dispatcher)
|
|
def fliplr(m):
|
|
"""
|
|
Reverse the order of elements along axis 1 (left/right).
|
|
|
|
For a 2-D array, this flips the entries in each row in the left/right
|
|
direction. Columns are preserved, but appear in a different order than
|
|
before.
|
|
|
|
Parameters
|
|
----------
|
|
m : array_like
|
|
Input array, must be at least 2-D.
|
|
|
|
Returns
|
|
-------
|
|
f : ndarray
|
|
A view of `m` with the columns reversed. Since a view
|
|
is returned, this operation is :math:`\\mathcal O(1)`.
|
|
|
|
See Also
|
|
--------
|
|
flipud : Flip array in the up/down direction.
|
|
flip : Flip array in one or more dimensions.
|
|
rot90 : Rotate array counterclockwise.
|
|
|
|
Notes
|
|
-----
|
|
Equivalent to ``m[:,::-1]`` or ``np.flip(m, axis=1)``.
|
|
Requires the array to be at least 2-D.
|
|
|
|
Examples
|
|
--------
|
|
>>> A = np.diag([1.,2.,3.])
|
|
>>> A
|
|
array([[1., 0., 0.],
|
|
[0., 2., 0.],
|
|
[0., 0., 3.]])
|
|
>>> np.fliplr(A)
|
|
array([[0., 0., 1.],
|
|
[0., 2., 0.],
|
|
[3., 0., 0.]])
|
|
|
|
>>> A = np.random.randn(2,3,5)
|
|
>>> np.all(np.fliplr(A) == A[:,::-1,...])
|
|
True
|
|
|
|
"""
|
|
m = asanyarray(m)
|
|
if m.ndim < 2:
|
|
raise ValueError("Input must be >= 2-d.")
|
|
return m[:, ::-1]
|
|
|
|
|
|
@array_function_dispatch(_flip_dispatcher)
|
|
def flipud(m):
|
|
"""
|
|
Reverse the order of elements along axis 0 (up/down).
|
|
|
|
For a 2-D array, this flips the entries in each column in the up/down
|
|
direction. Rows are preserved, but appear in a different order than before.
|
|
|
|
Parameters
|
|
----------
|
|
m : array_like
|
|
Input array.
|
|
|
|
Returns
|
|
-------
|
|
out : array_like
|
|
A view of `m` with the rows reversed. Since a view is
|
|
returned, this operation is :math:`\\mathcal O(1)`.
|
|
|
|
See Also
|
|
--------
|
|
fliplr : Flip array in the left/right direction.
|
|
flip : Flip array in one or more dimensions.
|
|
rot90 : Rotate array counterclockwise.
|
|
|
|
Notes
|
|
-----
|
|
Equivalent to ``m[::-1, ...]`` or ``np.flip(m, axis=0)``.
|
|
Requires the array to be at least 1-D.
|
|
|
|
Examples
|
|
--------
|
|
>>> A = np.diag([1.0, 2, 3])
|
|
>>> A
|
|
array([[1., 0., 0.],
|
|
[0., 2., 0.],
|
|
[0., 0., 3.]])
|
|
>>> np.flipud(A)
|
|
array([[0., 0., 3.],
|
|
[0., 2., 0.],
|
|
[1., 0., 0.]])
|
|
|
|
>>> A = np.random.randn(2,3,5)
|
|
>>> np.all(np.flipud(A) == A[::-1,...])
|
|
True
|
|
|
|
>>> np.flipud([1,2])
|
|
array([2, 1])
|
|
|
|
"""
|
|
m = asanyarray(m)
|
|
if m.ndim < 1:
|
|
raise ValueError("Input must be >= 1-d.")
|
|
return m[::-1, ...]
|
|
|
|
|
|
@set_array_function_like_doc
|
|
@set_module('numpy')
|
|
def eye(N, M=None, k=0, dtype=float, order='C', *, like=None):
|
|
"""
|
|
Return a 2-D array with ones on the diagonal and zeros elsewhere.
|
|
|
|
Parameters
|
|
----------
|
|
N : int
|
|
Number of rows in the output.
|
|
M : int, optional
|
|
Number of columns in the output. If None, defaults to `N`.
|
|
k : int, optional
|
|
Index of the diagonal: 0 (the default) refers to the main diagonal,
|
|
a positive value refers to an upper diagonal, and a negative value
|
|
to a lower diagonal.
|
|
dtype : data-type, optional
|
|
Data-type of the returned array.
|
|
order : {'C', 'F'}, optional
|
|
Whether the output should be stored in row-major (C-style) or
|
|
column-major (Fortran-style) order in memory.
|
|
|
|
.. versionadded:: 1.14.0
|
|
${ARRAY_FUNCTION_LIKE}
|
|
|
|
.. versionadded:: 1.20.0
|
|
|
|
Returns
|
|
-------
|
|
I : ndarray of shape (N,M)
|
|
An array where all elements are equal to zero, except for the `k`-th
|
|
diagonal, whose values are equal to one.
|
|
|
|
See Also
|
|
--------
|
|
identity : (almost) equivalent function
|
|
diag : diagonal 2-D array from a 1-D array specified by the user.
|
|
|
|
Examples
|
|
--------
|
|
>>> np.eye(2, dtype=int)
|
|
array([[1, 0],
|
|
[0, 1]])
|
|
>>> np.eye(3, k=1)
|
|
array([[0., 1., 0.],
|
|
[0., 0., 1.],
|
|
[0., 0., 0.]])
|
|
|
|
"""
|
|
if like is not None:
|
|
return _eye_with_like(like, N, M=M, k=k, dtype=dtype, order=order)
|
|
if M is None:
|
|
M = N
|
|
m = zeros((N, M), dtype=dtype, order=order)
|
|
if k >= M:
|
|
return m
|
|
# Ensure M and k are integers, so we don't get any surprise casting
|
|
# results in the expressions `M-k` and `M+1` used below. This avoids
|
|
# a problem with inputs with type (for example) np.uint64.
|
|
M = operator.index(M)
|
|
k = operator.index(k)
|
|
if k >= 0:
|
|
i = k
|
|
else:
|
|
i = (-k) * M
|
|
m[:M-k].flat[i::M+1] = 1
|
|
return m
|
|
|
|
|
|
_eye_with_like = array_function_dispatch()(eye)
|
|
|
|
|
|
def _diag_dispatcher(v, k=None):
|
|
return (v,)
|
|
|
|
|
|
@array_function_dispatch(_diag_dispatcher)
|
|
def diag(v, k=0):
|
|
"""
|
|
Extract a diagonal or construct a diagonal array.
|
|
|
|
See the more detailed documentation for ``numpy.diagonal`` if you use this
|
|
function to extract a diagonal and wish to write to the resulting array;
|
|
whether it returns a copy or a view depends on what version of numpy you
|
|
are using.
|
|
|
|
Parameters
|
|
----------
|
|
v : array_like
|
|
If `v` is a 2-D array, return a copy of its `k`-th diagonal.
|
|
If `v` is a 1-D array, return a 2-D array with `v` on the `k`-th
|
|
diagonal.
|
|
k : int, optional
|
|
Diagonal in question. The default is 0. Use `k>0` for diagonals
|
|
above the main diagonal, and `k<0` for diagonals below the main
|
|
diagonal.
|
|
|
|
Returns
|
|
-------
|
|
out : ndarray
|
|
The extracted diagonal or constructed diagonal array.
|
|
|
|
See Also
|
|
--------
|
|
diagonal : Return specified diagonals.
|
|
diagflat : Create a 2-D array with the flattened input as a diagonal.
|
|
trace : Sum along diagonals.
|
|
triu : Upper triangle of an array.
|
|
tril : Lower triangle of an array.
|
|
|
|
Examples
|
|
--------
|
|
>>> x = np.arange(9).reshape((3,3))
|
|
>>> x
|
|
array([[0, 1, 2],
|
|
[3, 4, 5],
|
|
[6, 7, 8]])
|
|
|
|
>>> np.diag(x)
|
|
array([0, 4, 8])
|
|
>>> np.diag(x, k=1)
|
|
array([1, 5])
|
|
>>> np.diag(x, k=-1)
|
|
array([3, 7])
|
|
|
|
>>> np.diag(np.diag(x))
|
|
array([[0, 0, 0],
|
|
[0, 4, 0],
|
|
[0, 0, 8]])
|
|
|
|
"""
|
|
v = asanyarray(v)
|
|
s = v.shape
|
|
if len(s) == 1:
|
|
n = s[0]+abs(k)
|
|
res = zeros((n, n), v.dtype)
|
|
if k >= 0:
|
|
i = k
|
|
else:
|
|
i = (-k) * n
|
|
res[:n-k].flat[i::n+1] = v
|
|
return res
|
|
elif len(s) == 2:
|
|
return diagonal(v, k)
|
|
else:
|
|
raise ValueError("Input must be 1- or 2-d.")
|
|
|
|
|
|
@array_function_dispatch(_diag_dispatcher)
|
|
def diagflat(v, k=0):
|
|
"""
|
|
Create a two-dimensional array with the flattened input as a diagonal.
|
|
|
|
Parameters
|
|
----------
|
|
v : array_like
|
|
Input data, which is flattened and set as the `k`-th
|
|
diagonal of the output.
|
|
k : int, optional
|
|
Diagonal to set; 0, the default, corresponds to the "main" diagonal,
|
|
a positive (negative) `k` giving the number of the diagonal above
|
|
(below) the main.
|
|
|
|
Returns
|
|
-------
|
|
out : ndarray
|
|
The 2-D output array.
|
|
|
|
See Also
|
|
--------
|
|
diag : MATLAB work-alike for 1-D and 2-D arrays.
|
|
diagonal : Return specified diagonals.
|
|
trace : Sum along diagonals.
|
|
|
|
Examples
|
|
--------
|
|
>>> np.diagflat([[1,2], [3,4]])
|
|
array([[1, 0, 0, 0],
|
|
[0, 2, 0, 0],
|
|
[0, 0, 3, 0],
|
|
[0, 0, 0, 4]])
|
|
|
|
>>> np.diagflat([1,2], 1)
|
|
array([[0, 1, 0],
|
|
[0, 0, 2],
|
|
[0, 0, 0]])
|
|
|
|
"""
|
|
try:
|
|
wrap = v.__array_wrap__
|
|
except AttributeError:
|
|
wrap = None
|
|
v = asarray(v).ravel()
|
|
s = len(v)
|
|
n = s + abs(k)
|
|
res = zeros((n, n), v.dtype)
|
|
if (k >= 0):
|
|
i = arange(0, n-k, dtype=intp)
|
|
fi = i+k+i*n
|
|
else:
|
|
i = arange(0, n+k, dtype=intp)
|
|
fi = i+(i-k)*n
|
|
res.flat[fi] = v
|
|
if not wrap:
|
|
return res
|
|
return wrap(res)
|
|
|
|
|
|
@set_array_function_like_doc
|
|
@set_module('numpy')
|
|
def tri(N, M=None, k=0, dtype=float, *, like=None):
|
|
"""
|
|
An array with ones at and below the given diagonal and zeros elsewhere.
|
|
|
|
Parameters
|
|
----------
|
|
N : int
|
|
Number of rows in the array.
|
|
M : int, optional
|
|
Number of columns in the array.
|
|
By default, `M` is taken equal to `N`.
|
|
k : int, optional
|
|
The sub-diagonal at and below which the array is filled.
|
|
`k` = 0 is the main diagonal, while `k` < 0 is below it,
|
|
and `k` > 0 is above. The default is 0.
|
|
dtype : dtype, optional
|
|
Data type of the returned array. The default is float.
|
|
${ARRAY_FUNCTION_LIKE}
|
|
|
|
.. versionadded:: 1.20.0
|
|
|
|
Returns
|
|
-------
|
|
tri : ndarray of shape (N, M)
|
|
Array with its lower triangle filled with ones and zero elsewhere;
|
|
in other words ``T[i,j] == 1`` for ``j <= i + k``, 0 otherwise.
|
|
|
|
Examples
|
|
--------
|
|
>>> np.tri(3, 5, 2, dtype=int)
|
|
array([[1, 1, 1, 0, 0],
|
|
[1, 1, 1, 1, 0],
|
|
[1, 1, 1, 1, 1]])
|
|
|
|
>>> np.tri(3, 5, -1)
|
|
array([[0., 0., 0., 0., 0.],
|
|
[1., 0., 0., 0., 0.],
|
|
[1., 1., 0., 0., 0.]])
|
|
|
|
"""
|
|
if like is not None:
|
|
return _tri_with_like(like, N, M=M, k=k, dtype=dtype)
|
|
|
|
if M is None:
|
|
M = N
|
|
|
|
m = greater_equal.outer(arange(N, dtype=_min_int(0, N)),
|
|
arange(-k, M-k, dtype=_min_int(-k, M - k)))
|
|
|
|
# Avoid making a copy if the requested type is already bool
|
|
m = m.astype(dtype, copy=False)
|
|
|
|
return m
|
|
|
|
|
|
_tri_with_like = array_function_dispatch()(tri)
|
|
|
|
|
|
def _trilu_dispatcher(m, k=None):
|
|
return (m,)
|
|
|
|
|
|
@array_function_dispatch(_trilu_dispatcher)
|
|
def tril(m, k=0):
|
|
"""
|
|
Lower triangle of an array.
|
|
|
|
Return a copy of an array with elements above the `k`-th diagonal zeroed.
|
|
For arrays with ``ndim`` exceeding 2, `tril` will apply to the final two
|
|
axes.
|
|
|
|
Parameters
|
|
----------
|
|
m : array_like, shape (..., M, N)
|
|
Input array.
|
|
k : int, optional
|
|
Diagonal above which to zero elements. `k = 0` (the default) is the
|
|
main diagonal, `k < 0` is below it and `k > 0` is above.
|
|
|
|
Returns
|
|
-------
|
|
tril : ndarray, shape (..., M, N)
|
|
Lower triangle of `m`, of same shape and data-type as `m`.
|
|
|
|
See Also
|
|
--------
|
|
triu : same thing, only for the upper triangle
|
|
|
|
Examples
|
|
--------
|
|
>>> np.tril([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], -1)
|
|
array([[ 0, 0, 0],
|
|
[ 4, 0, 0],
|
|
[ 7, 8, 0],
|
|
[10, 11, 12]])
|
|
|
|
>>> np.tril(np.arange(3*4*5).reshape(3, 4, 5))
|
|
array([[[ 0, 0, 0, 0, 0],
|
|
[ 5, 6, 0, 0, 0],
|
|
[10, 11, 12, 0, 0],
|
|
[15, 16, 17, 18, 0]],
|
|
[[20, 0, 0, 0, 0],
|
|
[25, 26, 0, 0, 0],
|
|
[30, 31, 32, 0, 0],
|
|
[35, 36, 37, 38, 0]],
|
|
[[40, 0, 0, 0, 0],
|
|
[45, 46, 0, 0, 0],
|
|
[50, 51, 52, 0, 0],
|
|
[55, 56, 57, 58, 0]]])
|
|
|
|
"""
|
|
m = asanyarray(m)
|
|
mask = tri(*m.shape[-2:], k=k, dtype=bool)
|
|
|
|
return where(mask, m, zeros(1, m.dtype))
|
|
|
|
|
|
@array_function_dispatch(_trilu_dispatcher)
|
|
def triu(m, k=0):
|
|
"""
|
|
Upper triangle of an array.
|
|
|
|
Return a copy of an array with the elements below the `k`-th diagonal
|
|
zeroed. For arrays with ``ndim`` exceeding 2, `triu` will apply to the
|
|
final two axes.
|
|
|
|
Please refer to the documentation for `tril` for further details.
|
|
|
|
See Also
|
|
--------
|
|
tril : lower triangle of an array
|
|
|
|
Examples
|
|
--------
|
|
>>> np.triu([[1,2,3],[4,5,6],[7,8,9],[10,11,12]], -1)
|
|
array([[ 1, 2, 3],
|
|
[ 4, 5, 6],
|
|
[ 0, 8, 9],
|
|
[ 0, 0, 12]])
|
|
|
|
>>> np.triu(np.arange(3*4*5).reshape(3, 4, 5))
|
|
array([[[ 0, 1, 2, 3, 4],
|
|
[ 0, 6, 7, 8, 9],
|
|
[ 0, 0, 12, 13, 14],
|
|
[ 0, 0, 0, 18, 19]],
|
|
[[20, 21, 22, 23, 24],
|
|
[ 0, 26, 27, 28, 29],
|
|
[ 0, 0, 32, 33, 34],
|
|
[ 0, 0, 0, 38, 39]],
|
|
[[40, 41, 42, 43, 44],
|
|
[ 0, 46, 47, 48, 49],
|
|
[ 0, 0, 52, 53, 54],
|
|
[ 0, 0, 0, 58, 59]]])
|
|
|
|
"""
|
|
m = asanyarray(m)
|
|
mask = tri(*m.shape[-2:], k=k-1, dtype=bool)
|
|
|
|
return where(mask, zeros(1, m.dtype), m)
|
|
|
|
|
|
def _vander_dispatcher(x, N=None, increasing=None):
|
|
return (x,)
|
|
|
|
|
|
# Originally borrowed from John Hunter and matplotlib
|
|
@array_function_dispatch(_vander_dispatcher)
|
|
def vander(x, N=None, increasing=False):
|
|
"""
|
|
Generate a Vandermonde matrix.
|
|
|
|
The columns of the output matrix are powers of the input vector. The
|
|
order of the powers is determined by the `increasing` boolean argument.
|
|
Specifically, when `increasing` is False, the `i`-th output column is
|
|
the input vector raised element-wise to the power of ``N - i - 1``. Such
|
|
a matrix with a geometric progression in each row is named for Alexandre-
|
|
Theophile Vandermonde.
|
|
|
|
Parameters
|
|
----------
|
|
x : array_like
|
|
1-D input array.
|
|
N : int, optional
|
|
Number of columns in the output. If `N` is not specified, a square
|
|
array is returned (``N = len(x)``).
|
|
increasing : bool, optional
|
|
Order of the powers of the columns. If True, the powers increase
|
|
from left to right, if False (the default) they are reversed.
|
|
|
|
.. versionadded:: 1.9.0
|
|
|
|
Returns
|
|
-------
|
|
out : ndarray
|
|
Vandermonde matrix. If `increasing` is False, the first column is
|
|
``x^(N-1)``, the second ``x^(N-2)`` and so forth. If `increasing` is
|
|
True, the columns are ``x^0, x^1, ..., x^(N-1)``.
|
|
|
|
See Also
|
|
--------
|
|
polynomial.polynomial.polyvander
|
|
|
|
Examples
|
|
--------
|
|
>>> x = np.array([1, 2, 3, 5])
|
|
>>> N = 3
|
|
>>> np.vander(x, N)
|
|
array([[ 1, 1, 1],
|
|
[ 4, 2, 1],
|
|
[ 9, 3, 1],
|
|
[25, 5, 1]])
|
|
|
|
>>> np.column_stack([x**(N-1-i) for i in range(N)])
|
|
array([[ 1, 1, 1],
|
|
[ 4, 2, 1],
|
|
[ 9, 3, 1],
|
|
[25, 5, 1]])
|
|
|
|
>>> x = np.array([1, 2, 3, 5])
|
|
>>> np.vander(x)
|
|
array([[ 1, 1, 1, 1],
|
|
[ 8, 4, 2, 1],
|
|
[ 27, 9, 3, 1],
|
|
[125, 25, 5, 1]])
|
|
>>> np.vander(x, increasing=True)
|
|
array([[ 1, 1, 1, 1],
|
|
[ 1, 2, 4, 8],
|
|
[ 1, 3, 9, 27],
|
|
[ 1, 5, 25, 125]])
|
|
|
|
The determinant of a square Vandermonde matrix is the product
|
|
of the differences between the values of the input vector:
|
|
|
|
>>> np.linalg.det(np.vander(x))
|
|
48.000000000000043 # may vary
|
|
>>> (5-3)*(5-2)*(5-1)*(3-2)*(3-1)*(2-1)
|
|
48
|
|
|
|
"""
|
|
x = asarray(x)
|
|
if x.ndim != 1:
|
|
raise ValueError("x must be a one-dimensional array or sequence.")
|
|
if N is None:
|
|
N = len(x)
|
|
|
|
v = empty((len(x), N), dtype=promote_types(x.dtype, int))
|
|
tmp = v[:, ::-1] if not increasing else v
|
|
|
|
if N > 0:
|
|
tmp[:, 0] = 1
|
|
if N > 1:
|
|
tmp[:, 1:] = x[:, None]
|
|
multiply.accumulate(tmp[:, 1:], out=tmp[:, 1:], axis=1)
|
|
|
|
return v
|
|
|
|
|
|
def _histogram2d_dispatcher(x, y, bins=None, range=None, density=None,
|
|
weights=None):
|
|
yield x
|
|
yield y
|
|
|
|
# This terrible logic is adapted from the checks in histogram2d
|
|
try:
|
|
N = len(bins)
|
|
except TypeError:
|
|
N = 1
|
|
if N == 2:
|
|
yield from bins # bins=[x, y]
|
|
else:
|
|
yield bins
|
|
|
|
yield weights
|
|
|
|
|
|
@array_function_dispatch(_histogram2d_dispatcher)
|
|
def histogram2d(x, y, bins=10, range=None, density=None, weights=None):
|
|
"""
|
|
Compute the bi-dimensional histogram of two data samples.
|
|
|
|
Parameters
|
|
----------
|
|
x : array_like, shape (N,)
|
|
An array containing the x coordinates of the points to be
|
|
histogrammed.
|
|
y : array_like, shape (N,)
|
|
An array containing the y coordinates of the points to be
|
|
histogrammed.
|
|
bins : int or array_like or [int, int] or [array, array], optional
|
|
The bin specification:
|
|
|
|
* If int, the number of bins for the two dimensions (nx=ny=bins).
|
|
* If array_like, the bin edges for the two dimensions
|
|
(x_edges=y_edges=bins).
|
|
* If [int, int], the number of bins in each dimension
|
|
(nx, ny = bins).
|
|
* If [array, array], the bin edges in each dimension
|
|
(x_edges, y_edges = bins).
|
|
* A combination [int, array] or [array, int], where int
|
|
is the number of bins and array is the bin edges.
|
|
|
|
range : array_like, shape(2,2), optional
|
|
The leftmost and rightmost edges of the bins along each dimension
|
|
(if not specified explicitly in the `bins` parameters):
|
|
``[[xmin, xmax], [ymin, ymax]]``. All values outside of this range
|
|
will be considered outliers and not tallied in the histogram.
|
|
density : bool, optional
|
|
If False, the default, returns the number of samples in each bin.
|
|
If True, returns the probability *density* function at the bin,
|
|
``bin_count / sample_count / bin_area``.
|
|
weights : array_like, shape(N,), optional
|
|
An array of values ``w_i`` weighing each sample ``(x_i, y_i)``.
|
|
Weights are normalized to 1 if `density` is True. If `density` is
|
|
False, the values of the returned histogram are equal to the sum of
|
|
the weights belonging to the samples falling into each bin.
|
|
|
|
Returns
|
|
-------
|
|
H : ndarray, shape(nx, ny)
|
|
The bi-dimensional histogram of samples `x` and `y`. Values in `x`
|
|
are histogrammed along the first dimension and values in `y` are
|
|
histogrammed along the second dimension.
|
|
xedges : ndarray, shape(nx+1,)
|
|
The bin edges along the first dimension.
|
|
yedges : ndarray, shape(ny+1,)
|
|
The bin edges along the second dimension.
|
|
|
|
See Also
|
|
--------
|
|
histogram : 1D histogram
|
|
histogramdd : Multidimensional histogram
|
|
|
|
Notes
|
|
-----
|
|
When `density` is True, then the returned histogram is the sample
|
|
density, defined such that the sum over bins of the product
|
|
``bin_value * bin_area`` is 1.
|
|
|
|
Please note that the histogram does not follow the Cartesian convention
|
|
where `x` values are on the abscissa and `y` values on the ordinate
|
|
axis. Rather, `x` is histogrammed along the first dimension of the
|
|
array (vertical), and `y` along the second dimension of the array
|
|
(horizontal). This ensures compatibility with `histogramdd`.
|
|
|
|
Examples
|
|
--------
|
|
>>> from matplotlib.image import NonUniformImage
|
|
>>> import matplotlib.pyplot as plt
|
|
|
|
Construct a 2-D histogram with variable bin width. First define the bin
|
|
edges:
|
|
|
|
>>> xedges = [0, 1, 3, 5]
|
|
>>> yedges = [0, 2, 3, 4, 6]
|
|
|
|
Next we create a histogram H with random bin content:
|
|
|
|
>>> x = np.random.normal(2, 1, 100)
|
|
>>> y = np.random.normal(1, 1, 100)
|
|
>>> H, xedges, yedges = np.histogram2d(x, y, bins=(xedges, yedges))
|
|
>>> # Histogram does not follow Cartesian convention (see Notes),
|
|
>>> # therefore transpose H for visualization purposes.
|
|
>>> H = H.T
|
|
|
|
:func:`imshow <matplotlib.pyplot.imshow>` can only display square bins:
|
|
|
|
>>> fig = plt.figure(figsize=(7, 3))
|
|
>>> ax = fig.add_subplot(131, title='imshow: square bins')
|
|
>>> plt.imshow(H, interpolation='nearest', origin='lower',
|
|
... extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]])
|
|
<matplotlib.image.AxesImage object at 0x...>
|
|
|
|
:func:`pcolormesh <matplotlib.pyplot.pcolormesh>` can display actual edges:
|
|
|
|
>>> ax = fig.add_subplot(132, title='pcolormesh: actual edges',
|
|
... aspect='equal')
|
|
>>> X, Y = np.meshgrid(xedges, yedges)
|
|
>>> ax.pcolormesh(X, Y, H)
|
|
<matplotlib.collections.QuadMesh object at 0x...>
|
|
|
|
:class:`NonUniformImage <matplotlib.image.NonUniformImage>` can be used to
|
|
display actual bin edges with interpolation:
|
|
|
|
>>> ax = fig.add_subplot(133, title='NonUniformImage: interpolated',
|
|
... aspect='equal', xlim=xedges[[0, -1]], ylim=yedges[[0, -1]])
|
|
>>> im = NonUniformImage(ax, interpolation='bilinear')
|
|
>>> xcenters = (xedges[:-1] + xedges[1:]) / 2
|
|
>>> ycenters = (yedges[:-1] + yedges[1:]) / 2
|
|
>>> im.set_data(xcenters, ycenters, H)
|
|
>>> ax.add_image(im)
|
|
>>> plt.show()
|
|
|
|
It is also possible to construct a 2-D histogram without specifying bin
|
|
edges:
|
|
|
|
>>> # Generate non-symmetric test data
|
|
>>> n = 10000
|
|
>>> x = np.linspace(1, 100, n)
|
|
>>> y = 2*np.log(x) + np.random.rand(n) - 0.5
|
|
>>> # Compute 2d histogram. Note the order of x/y and xedges/yedges
|
|
>>> H, yedges, xedges = np.histogram2d(y, x, bins=20)
|
|
|
|
Now we can plot the histogram using
|
|
:func:`pcolormesh <matplotlib.pyplot.pcolormesh>`, and a
|
|
:func:`hexbin <matplotlib.pyplot.hexbin>` for comparison.
|
|
|
|
>>> # Plot histogram using pcolormesh
|
|
>>> fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True)
|
|
>>> ax1.pcolormesh(xedges, yedges, H, cmap='rainbow')
|
|
>>> ax1.plot(x, 2*np.log(x), 'k-')
|
|
>>> ax1.set_xlim(x.min(), x.max())
|
|
>>> ax1.set_ylim(y.min(), y.max())
|
|
>>> ax1.set_xlabel('x')
|
|
>>> ax1.set_ylabel('y')
|
|
>>> ax1.set_title('histogram2d')
|
|
>>> ax1.grid()
|
|
|
|
>>> # Create hexbin plot for comparison
|
|
>>> ax2.hexbin(x, y, gridsize=20, cmap='rainbow')
|
|
>>> ax2.plot(x, 2*np.log(x), 'k-')
|
|
>>> ax2.set_title('hexbin')
|
|
>>> ax2.set_xlim(x.min(), x.max())
|
|
>>> ax2.set_xlabel('x')
|
|
>>> ax2.grid()
|
|
|
|
>>> plt.show()
|
|
"""
|
|
from numpy import histogramdd
|
|
|
|
if len(x) != len(y):
|
|
raise ValueError('x and y must have the same length.')
|
|
|
|
try:
|
|
N = len(bins)
|
|
except TypeError:
|
|
N = 1
|
|
|
|
if N != 1 and N != 2:
|
|
xedges = yedges = asarray(bins)
|
|
bins = [xedges, yedges]
|
|
hist, edges = histogramdd([x, y], bins, range, density, weights)
|
|
return hist, edges[0], edges[1]
|
|
|
|
|
|
@set_module('numpy')
|
|
def mask_indices(n, mask_func, k=0):
|
|
"""
|
|
Return the indices to access (n, n) arrays, given a masking function.
|
|
|
|
Assume `mask_func` is a function that, for a square array a of size
|
|
``(n, n)`` with a possible offset argument `k`, when called as
|
|
``mask_func(a, k)`` returns a new array with zeros in certain locations
|
|
(functions like `triu` or `tril` do precisely this). Then this function
|
|
returns the indices where the non-zero values would be located.
|
|
|
|
Parameters
|
|
----------
|
|
n : int
|
|
The returned indices will be valid to access arrays of shape (n, n).
|
|
mask_func : callable
|
|
A function whose call signature is similar to that of `triu`, `tril`.
|
|
That is, ``mask_func(x, k)`` returns a boolean array, shaped like `x`.
|
|
`k` is an optional argument to the function.
|
|
k : scalar
|
|
An optional argument which is passed through to `mask_func`. Functions
|
|
like `triu`, `tril` take a second argument that is interpreted as an
|
|
offset.
|
|
|
|
Returns
|
|
-------
|
|
indices : tuple of arrays.
|
|
The `n` arrays of indices corresponding to the locations where
|
|
``mask_func(np.ones((n, n)), k)`` is True.
|
|
|
|
See Also
|
|
--------
|
|
triu, tril, triu_indices, tril_indices
|
|
|
|
Notes
|
|
-----
|
|
.. versionadded:: 1.4.0
|
|
|
|
Examples
|
|
--------
|
|
These are the indices that would allow you to access the upper triangular
|
|
part of any 3x3 array:
|
|
|
|
>>> iu = np.mask_indices(3, np.triu)
|
|
|
|
For example, if `a` is a 3x3 array:
|
|
|
|
>>> a = np.arange(9).reshape(3, 3)
|
|
>>> a
|
|
array([[0, 1, 2],
|
|
[3, 4, 5],
|
|
[6, 7, 8]])
|
|
>>> a[iu]
|
|
array([0, 1, 2, 4, 5, 8])
|
|
|
|
An offset can be passed also to the masking function. This gets us the
|
|
indices starting on the first diagonal right of the main one:
|
|
|
|
>>> iu1 = np.mask_indices(3, np.triu, 1)
|
|
|
|
with which we now extract only three elements:
|
|
|
|
>>> a[iu1]
|
|
array([1, 2, 5])
|
|
|
|
"""
|
|
m = ones((n, n), int)
|
|
a = mask_func(m, k)
|
|
return nonzero(a != 0)
|
|
|
|
|
|
@set_module('numpy')
|
|
def tril_indices(n, k=0, m=None):
|
|
"""
|
|
Return the indices for the lower-triangle of an (n, m) array.
|
|
|
|
Parameters
|
|
----------
|
|
n : int
|
|
The row dimension of the arrays for which the returned
|
|
indices will be valid.
|
|
k : int, optional
|
|
Diagonal offset (see `tril` for details).
|
|
m : int, optional
|
|
.. versionadded:: 1.9.0
|
|
|
|
The column dimension of the arrays for which the returned
|
|
arrays will be valid.
|
|
By default `m` is taken equal to `n`.
|
|
|
|
|
|
Returns
|
|
-------
|
|
inds : tuple of arrays
|
|
The indices for the triangle. The returned tuple contains two arrays,
|
|
each with the indices along one dimension of the array.
|
|
|
|
See also
|
|
--------
|
|
triu_indices : similar function, for upper-triangular.
|
|
mask_indices : generic function accepting an arbitrary mask function.
|
|
tril, triu
|
|
|
|
Notes
|
|
-----
|
|
.. versionadded:: 1.4.0
|
|
|
|
Examples
|
|
--------
|
|
Compute two different sets of indices to access 4x4 arrays, one for the
|
|
lower triangular part starting at the main diagonal, and one starting two
|
|
diagonals further right:
|
|
|
|
>>> il1 = np.tril_indices(4)
|
|
>>> il2 = np.tril_indices(4, 2)
|
|
|
|
Here is how they can be used with a sample array:
|
|
|
|
>>> a = np.arange(16).reshape(4, 4)
|
|
>>> a
|
|
array([[ 0, 1, 2, 3],
|
|
[ 4, 5, 6, 7],
|
|
[ 8, 9, 10, 11],
|
|
[12, 13, 14, 15]])
|
|
|
|
Both for indexing:
|
|
|
|
>>> a[il1]
|
|
array([ 0, 4, 5, ..., 13, 14, 15])
|
|
|
|
And for assigning values:
|
|
|
|
>>> a[il1] = -1
|
|
>>> a
|
|
array([[-1, 1, 2, 3],
|
|
[-1, -1, 6, 7],
|
|
[-1, -1, -1, 11],
|
|
[-1, -1, -1, -1]])
|
|
|
|
These cover almost the whole array (two diagonals right of the main one):
|
|
|
|
>>> a[il2] = -10
|
|
>>> a
|
|
array([[-10, -10, -10, 3],
|
|
[-10, -10, -10, -10],
|
|
[-10, -10, -10, -10],
|
|
[-10, -10, -10, -10]])
|
|
|
|
"""
|
|
tri_ = tri(n, m, k=k, dtype=bool)
|
|
|
|
return tuple(broadcast_to(inds, tri_.shape)[tri_]
|
|
for inds in indices(tri_.shape, sparse=True))
|
|
|
|
|
|
def _trilu_indices_form_dispatcher(arr, k=None):
|
|
return (arr,)
|
|
|
|
|
|
@array_function_dispatch(_trilu_indices_form_dispatcher)
|
|
def tril_indices_from(arr, k=0):
|
|
"""
|
|
Return the indices for the lower-triangle of arr.
|
|
|
|
See `tril_indices` for full details.
|
|
|
|
Parameters
|
|
----------
|
|
arr : array_like
|
|
The indices will be valid for square arrays whose dimensions are
|
|
the same as arr.
|
|
k : int, optional
|
|
Diagonal offset (see `tril` for details).
|
|
|
|
Examples
|
|
--------
|
|
|
|
Create a 4 by 4 array.
|
|
|
|
>>> a = np.arange(16).reshape(4, 4)
|
|
>>> a
|
|
array([[ 0, 1, 2, 3],
|
|
[ 4, 5, 6, 7],
|
|
[ 8, 9, 10, 11],
|
|
[12, 13, 14, 15]])
|
|
|
|
Pass the array to get the indices of the lower triangular elements.
|
|
|
|
>>> trili = np.tril_indices_from(a)
|
|
>>> trili
|
|
(array([0, 1, 1, 2, 2, 2, 3, 3, 3, 3]), array([0, 0, 1, 0, 1, 2, 0, 1, 2, 3]))
|
|
|
|
>>> a[trili]
|
|
array([ 0, 4, 5, 8, 9, 10, 12, 13, 14, 15])
|
|
|
|
This is syntactic sugar for tril_indices().
|
|
|
|
>>> np.tril_indices(a.shape[0])
|
|
(array([0, 1, 1, 2, 2, 2, 3, 3, 3, 3]), array([0, 0, 1, 0, 1, 2, 0, 1, 2, 3]))
|
|
|
|
Use the `k` parameter to return the indices for the lower triangular array
|
|
up to the k-th diagonal.
|
|
|
|
>>> trili1 = np.tril_indices_from(a, k=1)
|
|
>>> a[trili1]
|
|
array([ 0, 1, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15])
|
|
|
|
See Also
|
|
--------
|
|
tril_indices, tril, triu_indices_from
|
|
|
|
Notes
|
|
-----
|
|
.. versionadded:: 1.4.0
|
|
|
|
"""
|
|
if arr.ndim != 2:
|
|
raise ValueError("input array must be 2-d")
|
|
return tril_indices(arr.shape[-2], k=k, m=arr.shape[-1])
|
|
|
|
|
|
@set_module('numpy')
|
|
def triu_indices(n, k=0, m=None):
|
|
"""
|
|
Return the indices for the upper-triangle of an (n, m) array.
|
|
|
|
Parameters
|
|
----------
|
|
n : int
|
|
The size of the arrays for which the returned indices will
|
|
be valid.
|
|
k : int, optional
|
|
Diagonal offset (see `triu` for details).
|
|
m : int, optional
|
|
.. versionadded:: 1.9.0
|
|
|
|
The column dimension of the arrays for which the returned
|
|
arrays will be valid.
|
|
By default `m` is taken equal to `n`.
|
|
|
|
|
|
Returns
|
|
-------
|
|
inds : tuple, shape(2) of ndarrays, shape(`n`)
|
|
The indices for the triangle. The returned tuple contains two arrays,
|
|
each with the indices along one dimension of the array. Can be used
|
|
to slice a ndarray of shape(`n`, `n`).
|
|
|
|
See also
|
|
--------
|
|
tril_indices : similar function, for lower-triangular.
|
|
mask_indices : generic function accepting an arbitrary mask function.
|
|
triu, tril
|
|
|
|
Notes
|
|
-----
|
|
.. versionadded:: 1.4.0
|
|
|
|
Examples
|
|
--------
|
|
Compute two different sets of indices to access 4x4 arrays, one for the
|
|
upper triangular part starting at the main diagonal, and one starting two
|
|
diagonals further right:
|
|
|
|
>>> iu1 = np.triu_indices(4)
|
|
>>> iu2 = np.triu_indices(4, 2)
|
|
|
|
Here is how they can be used with a sample array:
|
|
|
|
>>> a = np.arange(16).reshape(4, 4)
|
|
>>> a
|
|
array([[ 0, 1, 2, 3],
|
|
[ 4, 5, 6, 7],
|
|
[ 8, 9, 10, 11],
|
|
[12, 13, 14, 15]])
|
|
|
|
Both for indexing:
|
|
|
|
>>> a[iu1]
|
|
array([ 0, 1, 2, ..., 10, 11, 15])
|
|
|
|
And for assigning values:
|
|
|
|
>>> a[iu1] = -1
|
|
>>> a
|
|
array([[-1, -1, -1, -1],
|
|
[ 4, -1, -1, -1],
|
|
[ 8, 9, -1, -1],
|
|
[12, 13, 14, -1]])
|
|
|
|
These cover only a small part of the whole array (two diagonals right
|
|
of the main one):
|
|
|
|
>>> a[iu2] = -10
|
|
>>> a
|
|
array([[ -1, -1, -10, -10],
|
|
[ 4, -1, -1, -10],
|
|
[ 8, 9, -1, -1],
|
|
[ 12, 13, 14, -1]])
|
|
|
|
"""
|
|
tri_ = ~tri(n, m, k=k - 1, dtype=bool)
|
|
|
|
return tuple(broadcast_to(inds, tri_.shape)[tri_]
|
|
for inds in indices(tri_.shape, sparse=True))
|
|
|
|
|
|
@array_function_dispatch(_trilu_indices_form_dispatcher)
|
|
def triu_indices_from(arr, k=0):
|
|
"""
|
|
Return the indices for the upper-triangle of arr.
|
|
|
|
See `triu_indices` for full details.
|
|
|
|
Parameters
|
|
----------
|
|
arr : ndarray, shape(N, N)
|
|
The indices will be valid for square arrays.
|
|
k : int, optional
|
|
Diagonal offset (see `triu` for details).
|
|
|
|
Returns
|
|
-------
|
|
triu_indices_from : tuple, shape(2) of ndarray, shape(N)
|
|
Indices for the upper-triangle of `arr`.
|
|
|
|
Examples
|
|
--------
|
|
|
|
Create a 4 by 4 array.
|
|
|
|
>>> a = np.arange(16).reshape(4, 4)
|
|
>>> a
|
|
array([[ 0, 1, 2, 3],
|
|
[ 4, 5, 6, 7],
|
|
[ 8, 9, 10, 11],
|
|
[12, 13, 14, 15]])
|
|
|
|
Pass the array to get the indices of the upper triangular elements.
|
|
|
|
>>> triui = np.triu_indices_from(a)
|
|
>>> triui
|
|
(array([0, 0, 0, 0, 1, 1, 1, 2, 2, 3]), array([0, 1, 2, 3, 1, 2, 3, 2, 3, 3]))
|
|
|
|
>>> a[triui]
|
|
array([ 0, 1, 2, 3, 5, 6, 7, 10, 11, 15])
|
|
|
|
This is syntactic sugar for triu_indices().
|
|
|
|
>>> np.triu_indices(a.shape[0])
|
|
(array([0, 0, 0, 0, 1, 1, 1, 2, 2, 3]), array([0, 1, 2, 3, 1, 2, 3, 2, 3, 3]))
|
|
|
|
Use the `k` parameter to return the indices for the upper triangular array
|
|
from the k-th diagonal.
|
|
|
|
>>> triuim1 = np.triu_indices_from(a, k=1)
|
|
>>> a[triuim1]
|
|
array([ 1, 2, 3, 6, 7, 11])
|
|
|
|
|
|
See Also
|
|
--------
|
|
triu_indices, triu, tril_indices_from
|
|
|
|
Notes
|
|
-----
|
|
.. versionadded:: 1.4.0
|
|
|
|
"""
|
|
if arr.ndim != 2:
|
|
raise ValueError("input array must be 2-d")
|
|
return triu_indices(arr.shape[-2], k=k, m=arr.shape[-1])
|
|
|