diff --git a/src/boost_histogram/_internal/hist.py b/src/boost_histogram/_internal/hist.py index 09cd8c3ba..45b8cd6c7 100644 --- a/src/boost_histogram/_internal/hist.py +++ b/src/boost_histogram/_internal/hist.py @@ -552,18 +552,25 @@ def _compute_commonindex(self, index): return indexes - @inject_signature("self, flow=False, *, dd=False") + @inject_signature("self, flow=False, *, dd=False, view=False") def to_numpy(self, flow=False, **kwargs): """ - Convert to a Numpy style tuple of return arrays. + Convert to a Numpy style tuple of return arrays. Edges are converted to + match NumPy standards, with upper edge inclusive, unlike + boost-histogram, where upper edge is exclusive. Parameters ---------- - flow : bool = False Include the flow bins. dd : bool = False - Use the histogramdd return syntax, where the edges are in a tuple + Use the histogramdd return syntax, where the edges are in a tuple. + Otherwise, this is the histogram/histogram2d return style. + view : bool = False + The behavior for the return value. By default, this will return + array of the values only regardless of the storage (which is all + NumPy's histogram function can do). view=True will return the + boost-histogram view of the storage. Return ------ @@ -575,13 +582,21 @@ def to_numpy(self, flow=False, **kwargs): with KWArgs(kwargs) as kw: dd = kw.optional("dd", False) + view = kw.optional("view", False) + # Python 3+ would be simpler return_tuple = self._hist.to_numpy(flow) + hist = return_tuple[0] + + if view: + hist = self.view(flow=flow) + else: + hist = self.values(flow=flow) if dd: - return return_tuple[0], return_tuple[1:] + return hist, return_tuple[1:] else: - return return_tuple + return (hist,) + return_tuple[1:] @inject_signature("self, *, deep=True") def copy(self, **kwargs): diff --git a/src/boost_histogram/numpy.py b/src/boost_histogram/numpy.py index 8cd465abe..05285f9d0 100644 --- a/src/boost_histogram/numpy.py +++ b/src/boost_histogram/numpy.py @@ -79,7 +79,10 @@ def histogramdd( density = hist.view() / hist.sum() / areas return (density, hist.to_numpy()[1:]) - return hist if bh_cls is not None else hist.to_numpy(dd=True) + # Note: this is view=True since users have to ask explicitly for special + # storages, so view=False would throw away part of what they are asking + # for. Users can use a histogram return type if they need view=False. + return hist if bh_cls is not None else hist.to_numpy(view=True, dd=True) @_inject_signature( diff --git a/tests/test_internal_histogram.py b/tests/test_internal_histogram.py index 1a1d65493..a72783dd9 100644 --- a/tests/test_internal_histogram.py +++ b/tests/test_internal_histogram.py @@ -135,6 +135,31 @@ def test_numpy_dd(): assert_array_equal(x1, x2) assert_array_equal(y1, y2) +def test_numpy_weights(): + h = bh.Histogram( + bh.axis.Regular(10, 0, 1), bh.axis.Regular(5, 0, 1), storage=bh.storage.Weight() + ) + + for i in range(10): + for j in range(5): + x, y = h.axes[0].centers[i], h.axes[1].centers[j] + v = i + j * 10 + 1 + h.fill([x] * v, [y] * v) + + h2, x2, y2 = h.to_numpy(view=False) + h1, (x1, y1) = h.to_numpy(dd=True, view=False) + + assert_array_equal(h1, h2) + assert_array_equal(x1, x2) + assert_array_equal(y1, y2) + + h1, (x1, y1) = h.to_numpy(dd=True, view=False) + h2, x2, y2 = h.to_numpy(view=True) + + assert_array_equal(h1, h2.value) + assert_array_equal(x1, x2) + assert_array_equal(y1, y2) + def test_numpy_flow(): h = bh.Histogram(