Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions bindings/pyroot/pythonizations/test/uhi_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Tests to verify that TH1 and derived histograms conform to the UHI Indexing interfaces (setting, accessing and slicing).
"""

import numpy as np
import pytest
import ROOT
from ROOT._pythonization._uhi import _get_axis, _get_processed_slices, _overflow, _shape, _underflow
Expand Down Expand Up @@ -326,5 +327,35 @@ def test_list_iter(self, hist_setup):
assert list(hist_setup) == expected.flatten().tolist()


class TestInfiniteEdges:
def setup_method(self):
# create a 2D histogram with an infinite upper edge on the Y axis
xedges = np.array([0.0, 1.0, 2.0], dtype="float64")
yedges = np.array([0.0, 1.0, 2.0, np.inf], dtype="float64")
self.h_inf = ROOT.TH2D("h_inf", "h_inf", len(xedges) - 1, xedges, len(yedges) - 1, yedges)

for i in range(1, self.h_inf.GetNbinsX() + 1):
for j in range(1, self.h_inf.GetNbinsY() + 1):
self.h_inf.SetBinContent(i, j, 10 * i + j)

def test_uhi_projection_preserves_content(self):
"""check that UHI projection behaves like standard projection"""
# projection on X axis
proj_x_ref = self.h_inf.ProjectionX()
proj_x_uhi = self.h_inf[:, ROOT.uhi.sum]
ref_values = proj_x_ref.values()
uhi_values = proj_x_uhi.values()

assert np.allclose(uhi_values, ref_values)

# projection on Y axis
proj_y_ref = self.h_inf.ProjectionY()
proj_y_uhi = self.h_inf[ROOT.uhi.sum, :]
ref_values = proj_y_ref.values()
uhi_values = proj_y_uhi.values()

assert np.allclose(uhi_values, ref_values)


if __name__ == "__main__":
raise SystemExit(pytest.main(args=[__file__]))
19 changes: 9 additions & 10 deletions hist/hist/inc/TH1.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,17 +214,19 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker {

// Compute new bin counts and edges
std::array<Int_t, kMaxDim> nBins{}, totalBins{};
std::array<Double_t, kMaxDim> lowEdge{}, upEdge{};
std::array<std::vector<Double_t>, kMaxDim> edges;
for (decltype(ndim) d = 0; d < ndim; ++d) {
const auto &axis = (d == 0 ? fXaxis : d == 1 ? fYaxis : fZaxis);
auto start = std::max(1, args[d * 2]);
auto end = std::min(axis.GetNbins() + 1, args[d * 2 + 1]);
nBins[d] = end - start;
lowEdge[d] = axis.GetBinLowEdge(start);
upEdge[d] = axis.GetBinLowEdge(end);
totalBins[d] = axis.GetNbins() + 2;
args[2 * d] = start;
args[2 * d + 1] = end;
// Compute new edges
for (int b = start; b <= end; ++b)
edges[d].push_back(axis.GetBinLowEdge(b));
edges[d].push_back(axis.GetBinUpEdge(end));
}

// Compute layout sizes for slice
Expand Down Expand Up @@ -271,13 +273,10 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker {
dataArray = newArr;

// Reconfigure Axes
if (ndim == 1) {
this->SetBins(nBins[0], lowEdge[0], upEdge[0]);
} else if (ndim == 2) {
this->SetBins(nBins[0], lowEdge[0], upEdge[0], nBins[1], lowEdge[1], upEdge[1]);
} else if (ndim == 3) {
this->SetBins(nBins[0], lowEdge[0], upEdge[0], nBins[1], lowEdge[1], upEdge[1], nBins[2], lowEdge[2],
upEdge[2]);
switch (ndim) {
case 1: this->SetBins(nBins[0], edges[0].data()); break;
case 2: this->SetBins(nBins[0], edges[0].data(), nBins[1], edges[1].data()); break;
case 3: this->SetBins(nBins[0], edges[0].data(), nBins[1], edges[1].data(), nBins[2], edges[2].data()); break;
}

// Update the statistics
Expand Down
Loading