Skip to content

Commit a692ff5

Browse files
Implementation of histogram2d
1 parent 3b3a233 commit a692ff5

File tree

5 files changed

+395
-93
lines changed

5 files changed

+395
-93
lines changed

dpnp/dpnp_iface_histograms.py

Lines changed: 73 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
"digitize",
5858
"histogram",
5959
"histogram_bin_edges",
60-
"histogram2d"
60+
"histogram2d",
6161
"histogramdd",
6262
]
6363

@@ -139,6 +139,9 @@ def _is_finite(a):
139139
return numpy.isfinite(a)
140140

141141
if range is not None:
142+
if len(range) != 2:
143+
raise ValueError("range argument must consist of 2 elements.")
144+
142145
first_edge, last_edge = range
143146
if first_edge > last_edge:
144147
raise ValueError("max must be larger than min in range parameter.")
@@ -753,6 +756,7 @@ def histogram_bin_edges(a, bins=10, range=None, weights=None):
753756

754757

755758
def histogram2d(x, y, bins=10, range=None, density=None, weights=None):
759+
# pylint: disable=line-too-long
756760
"""
757761
Compute the bi-dimensional histogram of two data samples.
758762
@@ -764,8 +768,10 @@ def histogram2d(x, y, bins=10, range=None, density=None, weights=None):
764768
y : {dpnp.ndarray, usm_ndarray} of shape (N,)
765769
An array containing the y coordinates of the points to be
766770
histogrammed.
767-
bins : {int, list of dpnp.ndarray, list of usm_ndarray, sequence of scalars}, optional
768-
The bin specification:
771+
bins : {int, list of dpnp.ndarray or usm_ndarray, sequence of scalars}, optional
772+
Histogram bins.
773+
774+
The bins specification:
769775
770776
* If int, the number of bins for the two dimensions (nx=ny=bins).
771777
* If array, the bin edges for the two dimensions
@@ -822,94 +828,73 @@ def histogram2d(x, y, bins=10, range=None, density=None, weights=None):
822828
823829
Examples
824830
--------
825-
>>> import numpy as np
826-
>>> from matplotlib.image import NonUniformImage
827-
>>> import matplotlib.pyplot as plt
828-
829-
Construct a 2-D histogram with variable bin width. First define the bin
830-
edges:
831-
832-
>>> xedges = [0, 1, 3, 5]
833-
>>> yedges = [0, 2, 3, 4, 6]
834-
835-
Next we create a histogram H with random bin content:
836-
837-
>>> x = np.random.normal(2, 1, 100)
838-
>>> y = np.random.normal(1, 1, 100)
839-
>>> H, xedges, yedges = np.histogram2d(x, y, bins=(xedges, yedges))
840-
>>> # Histogram does not follow Cartesian convention (see Notes),
841-
>>> # therefore transpose H for visualization purposes.
842-
>>> H = H.T
843-
844-
:func:`imshow <matplotlib.pyplot.imshow>` can only display square bins:
845-
846-
>>> fig = plt.figure(figsize=(7, 3))
847-
>>> ax = fig.add_subplot(131, title='imshow: square bins')
848-
>>> plt.imshow(H, interpolation='nearest', origin='lower',
849-
... extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]])
850-
<matplotlib.image.AxesImage object at 0x...>
851-
852-
:func:`pcolormesh <matplotlib.pyplot.pcolormesh>` can display actual edges:
853-
854-
>>> ax = fig.add_subplot(132, title='pcolormesh: actual edges',
855-
... aspect='equal')
856-
>>> X, Y = np.meshgrid(xedges, yedges)
857-
>>> ax.pcolormesh(X, Y, H)
858-
<matplotlib.collections.QuadMesh object at 0x...>
859-
860-
:class:`NonUniformImage <matplotlib.image.NonUniformImage>` can be used to
861-
display actual bin edges with interpolation:
862-
863-
>>> ax = fig.add_subplot(133, title='NonUniformImage: interpolated',
864-
... aspect='equal', xlim=xedges[[0, -1]], ylim=yedges[[0, -1]])
865-
>>> im = NonUniformImage(ax, interpolation='bilinear')
866-
>>> xcenters = (xedges[:-1] + xedges[1:]) / 2
867-
>>> ycenters = (yedges[:-1] + yedges[1:]) / 2
868-
>>> im.set_data(xcenters, ycenters, H)
869-
>>> ax.add_image(im)
870-
>>> plt.show()
871-
872-
It is also possible to construct a 2-D histogram without specifying bin
873-
edges:
874-
875-
>>> # Generate non-symmetric test data
876-
>>> n = 10000
877-
>>> x = np.linspace(1, 100, n)
878-
>>> y = 2*np.log(x) + np.random.rand(n) - 0.5
879-
>>> # Compute 2d histogram. Note the order of x/y and xedges/yedges
880-
>>> H, yedges, xedges = np.histogram2d(y, x, bins=20)
881-
882-
Now we can plot the histogram using
883-
:func:`pcolormesh <matplotlib.pyplot.pcolormesh>`, and a
884-
:func:`hexbin <matplotlib.pyplot.hexbin>` for comparison.
885-
886-
>>> # Plot histogram using pcolormesh
887-
>>> fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True)
888-
>>> ax1.pcolormesh(xedges, yedges, H, cmap='rainbow')
889-
>>> ax1.plot(x, 2*np.log(x), 'k-')
890-
>>> ax1.set_xlim(x.min(), x.max())
891-
>>> ax1.set_ylim(y.min(), y.max())
892-
>>> ax1.set_xlabel('x')
893-
>>> ax1.set_ylabel('y')
894-
>>> ax1.set_title('histogram2d')
895-
>>> ax1.grid()
896-
897-
>>> # Create hexbin plot for comparison
898-
>>> ax2.hexbin(x, y, gridsize=20, cmap='rainbow')
899-
>>> ax2.plot(x, 2*np.log(x), 'k-')
900-
>>> ax2.set_title('hexbin')
901-
>>> ax2.set_xlim(x.min(), x.max())
902-
>>> ax2.set_xlabel('x')
903-
>>> ax2.grid()
904-
905-
>>> plt.show()
831+
>>> import dpnp as np
832+
>>> x = np.random.randn(20)
833+
>>> y = np.random.randn(20)
834+
>>> hist, edges_x, edges_y = np.histogram2d(x, y, bins=(4, 3))
835+
>>> hist
836+
[[1. 0. 0.]
837+
[0. 0. 0.]
838+
[5. 6. 4.]
839+
[1. 2. 1.]]
840+
>>> edges_x
841+
[-5.6575713 -3.5574734 -1.4573755 0.6427226 2.74282 ]
842+
>>> edges_y
843+
[-1.1889046 -0.07263839 1.0436279 2.159894 ]
906844
"""
845+
# pylint: enable=line-too-long
846+
847+
dpnp.check_supported_arrays_type(x, y)
848+
if weights is not None:
849+
dpnp.check_supported_arrays_type(weights)
850+
851+
if x.ndim != 1 or y.ndim != 1:
852+
raise ValueError(
853+
f"x and y must be 1-dimensional arrays."
854+
f"Got {x.ndim} and {y.ndim} respectively"
855+
)
907856

908857
if len(x) != len(y):
909-
raise ValueError(f'x and y must have the same length. Got {len(x)} and {len(y)} respectively')
858+
raise ValueError(
859+
f"x and y must have the same length."
860+
f"Got {len(x)} and {len(y)} respectively"
861+
)
862+
863+
usm_type, exec_q = get_usm_allocations([x, y, bins, range, weights])
864+
device = exec_q.sycl_device
865+
866+
sample_dtype = _result_type_for_device([x.dtype, y.dtype], device)
867+
868+
# Unlike histogramdd histogram2d accepts 1d bins and
869+
# apply it to both dimensions
870+
# at the same moment two elements bins should be interpreted as
871+
# number of bins in each dimension and array-like bins with one element
872+
# is not allowed
873+
if isinstance(bins, Iterable) and len(bins) > 2:
874+
bins = [bins] * 2
875+
876+
bins = _histdd_normalize_bins(bins, 2)
877+
bins_dtypes = [sample_dtype]
878+
bins_dtypes += [b.dtype for b in bins if hasattr(b, "dtype")]
879+
880+
bins_dtype = _result_type_for_device(bins_dtypes, device)
881+
hist_dtype = _histdd_hist_dtype(exec_q, weights)
910882

883+
supported_types = statistics_ext.histogramdd_dtypes()
884+
885+
sample_dtype, _ = _align_dtypes(
886+
sample_dtype, bins_dtype, hist_dtype, supported_types, device
887+
)
911888

912-
hist, edges = histogramdd([x, y], bins, range, density, weights)
889+
sample = dpnp.empty_like(
890+
x, shape=x.shape + (2,), dtype=sample_dtype, usm_type=usm_type
891+
)
892+
sample[:, 0] = x
893+
sample[:, 1] = y
894+
895+
hist, edges = histogramdd(
896+
sample, bins=bins, range=range, density=density, weights=weights
897+
)
913898
return hist, edges[0], edges[1]
914899

915900

@@ -1080,7 +1065,7 @@ def _histdd_extract_arrays(sample, weights, bins):
10801065
return all_arrays
10811066

10821067

1083-
def histogramdd(sample, bins=10, range=None, weights=None, density=False):
1068+
def histogramdd(sample, bins=10, range=None, density=False, weights=None):
10841069
"""
10851070
Compute the multidimensional histogram of some data.
10861071
@@ -1155,7 +1140,7 @@ def histogramdd(sample, bins=10, range=None, weights=None, density=False):
11551140
elif sample.ndim > 2:
11561141
raise ValueError("sample must have no more than 2 dimensions")
11571142

1158-
ndim = sample.shape[1] if sample.size > 0 else 1
1143+
ndim = sample.shape[1]
11591144

11601145
_arrays = _histdd_extract_arrays(sample, weights, bins)
11611146
usm_type, queue = get_usm_allocations(_arrays)

0 commit comments

Comments
 (0)