Skip to content

Commit 9afbcd5

Browse files
authored
fix: categorical axes need special flow handling (#564)
1 parent 5fa891b commit 9afbcd5

File tree

4 files changed

+42
-5
lines changed

4 files changed

+42
-5
lines changed

docs/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
## UPCOMING
44

55
* Fix scaling a weighted storage [#559][]
6+
* Fix partial summation over a Categorical axis [#564][]
67
* Support running type checking from Python < 3.8 [#542][]
78

89
[#542]: https://github.com/scikit-hep/boost-histogram/pull/542
910
[#559]: https://github.com/scikit-hep/boost-histogram/pull/559
11+
[#564]: https://github.com/scikit-hep/boost-histogram/pull/564
1012

1113
## Version 1.0
1214

src/boost_histogram/_internal/axis.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,23 @@ def _process_loc(
165165
Compute start and stop into actual start and stop values in Boost.Histogram.
166166
None -> -1 or 0 for start, -> len or len+1 for stop. If start or stop are
167167
callable, then call them with the axes.
168+
169+
For a non-ordered axes, flow is all or nothing, so this will ensure overflow
170+
is turned off if underflow is not None.
168171
"""
169172

170173
def _process_internal(item: Optional[AxCallOrInt], default: int) -> int:
171174
return default if item is None else item(self) if callable(item) else item
172175

173-
begin = _process_internal(start, -1 if self._ax.traits_underflow else 0)
174-
end = _process_internal(
175-
stop, len(self) + (1 if self._ax.traits_overflow else 0)
176-
)
176+
underflow = -1 if self._ax.traits_underflow else 0
177+
overflow = 1 if self._ax.traits_overflow else 0
178+
179+
# Non-ordered axes only use flow if integrating from None to None
180+
if not self._ax.traits_ordered and not (start is None and stop is None):
181+
overflow = 0
182+
183+
begin = _process_internal(start, underflow)
184+
end = _process_internal(stop, len(self) + overflow)
177185

178186
return begin, end
179187

src/register_algorithm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void register_algorithms(py::module& algorithm) {
3131
self.begin.index,
3232
self.end.index,
3333
merge,
34-
self.crop);
34+
self.crop ? "slice_mode.crop" : "slice_mode.shrink");
3535
} else {
3636
return py::
3737
str("reduce_command(shrink{0}({1}, lower={2}, upper={3}{4}))")

tests/test_histogram_indexing.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,30 @@ def test_axes_tuple_Nd():
377377

378378
assert b1.ndim == 3
379379
assert a1.ndim == 2
380+
381+
382+
# issue 556
383+
def test_single_flow_bin():
384+
# Flow is removed for category axes unless full sum is used
385+
h = bh.Histogram(bh.axis.IntCategory([0, 1, 2]))
386+
h.view(True)[:] = 1
387+
388+
assert h[::sum] == 4
389+
assert h[0::sum] == 3
390+
assert h[1::sum] == 2
391+
assert h[2::sum] == 1
392+
with pytest.raises(ValueError):
393+
h[3::sum]
394+
395+
assert h[1:2][sum] == 4
396+
397+
h = bh.Histogram(bh.axis.Integer(0, 3))
398+
h.view(True)[:] = 1
399+
400+
assert h[::sum] == 5
401+
assert h[0::sum] == 4
402+
assert h[1::sum] == 3
403+
assert h[2::sum] == 2
404+
assert h[3::sum] == 1
405+
406+
assert h[1:2][sum] == 5

0 commit comments

Comments
 (0)