Skip to content

fix: TProfile2D/3D weighted and counts() were broken for N-D profiles#1651

Open
henryiii wants to merge 2 commits into
mainfrom
fix-tprofile-nd
Open

fix: TProfile2D/3D weighted and counts() were broken for N-D profiles#1651
henryiii wants to merge 2 commits into
mainfrom
fix-tprofile-nd

Conversation

@henryiii

Copy link
Copy Markdown
Member

🤖 AI text below 🤖

Part of #1646

Summary

  • TProfile2D/3D weighted property (TProfile2D.py:36-39, TProfile3D.py:40-43): fNcells is an int, so len(self.member("fNcells")) raised TypeError whenever fBinSumw2 existed. Additionally the logic was inverted relative to the correct 1-D version in TProfile.py:237-240. Both files now match the 1-D version: fBinSumw2 is not None and len(fBinSumw2) == self.member("fNcells").

  • TProfile2D/3D counts() shape (TProfile2D.py:41-52, TProfile3D.py:45-56): out.reshape(fBinEntries.shape) was a no-op because fBinEntries is stored flat (shape (fNcells,)). The subsequent out[1:-1, 1:-1] / out[1:-1, 1:-1, 1:-1] slices then raised IndexError. The fix applies the same reshape + numpy.transpose pattern already used by values() in both classes, ensuring counts(flow=…).shape == values(flow=…).shape.

  • ⚠️ BEHAVIOR CHANGE — TProfile.counts() default flow (TProfile.py:242): Changed default from flow=True to flow=False. Every other counts() in the codebase defaults to flow=False (the abstract Profile.counts at TProfile.py:142, TProfile2D.counts, TProfile3D.counts, TH1.Histogram.counts). The flow=True default was an inconsistency. Maintainer: please confirm this behavior change is acceptable — any downstream code calling h.counts() on a 1-D TProfile without an explicit flow= argument will now receive the no-flow array (length fNbins) instead of the with-flow array (length fNbins + 2).

  • Python-2 __ne__ cleanup (TH1.py:85-89, TAxis.py:122-126): Removed explicit __ne__ methods with the comment "Some versions of Python don't automatically negate __eq__". Python 3 auto-derives __ne__ from __eq__, so these are dead code.

Test plan

  • weighted property no longer raises TypeError on uproot-issue-227a.root (TProfile2D) and uproot-issue-227b.root (TProfile3D)
  • counts(flow=True).shape == values(flow=True).shape for both TProfile2D and TProfile3D
  • counts(flow=False).shape == values(flow=False).shape for both TProfile2D and TProfile3D
  • Existing TProfile tests still pass (tests/test_0228_read_TProfiles.py, tests/test_1609_tprofiles.py)
  • Regression tests added for all fixed behaviors

🤖 Generated with Claude Code

henryiii added 2 commits June 10, 2026 14:57
- Fix `weighted` property in TProfile2D/3D: `fNcells` is an int so
  `len(self.member("fNcells"))` raised TypeError; also the logic was
  inverted vs the correct 1-D version in TProfile.py
- Fix `counts()` in TProfile2D/3D: flat `fBinEntries` was never reshaped
  and transposed before slicing, causing IndexError on flow=False; now
  matches the reshape+transpose pattern used by `values()`
- Change `TProfile.counts()` default from `flow=True` to `flow=False` to
  match every other `counts()` in the codebase (behavior change)
- Remove Python-2-era `__ne__` methods from TH1 and TAxis (Python 3
  auto-derives `__ne__` from `__eq__`)

Fixes #1646

Assisted-by: ClaudeCode:claude-sonnet-4-6
Add 16 tests covering:
- weighted property not raising TypeError for TProfile2D and TProfile3D
- counts(flow=True/False) shape matching values(flow=True/False) shape
- counts() inner region consistent with counts(flow=True) slice

Assisted-by: ClaudeCode:claude-sonnet-4-6
@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.85%. Comparing base (1c06db0) to head (51d2e73).
⚠️ Report is 16 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
Files with missing lines Coverage Δ
src/uproot/behaviors/TAxis.py 87.28% <ø> (+0.62%) ⬆️
src/uproot/behaviors/TH1.py 83.10% <ø> (+0.44%) ⬆️
src/uproot/behaviors/TProfile.py 85.87% <100.00%> (ø)
src/uproot/behaviors/TProfile2D.py 64.06% <100.00%> (+13.26%) ⬆️
src/uproot/behaviors/TProfile3D.py 65.21% <100.00%> (+12.97%) ⬆️

... and 1 file with indirect coverage changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant