Skip to content

Commit

Permalink
Add rebinning hints (#100)
Browse files Browse the repository at this point in the history
* Add rebinning hints

* Improve error message

* Bump version number
  • Loading branch information
tamasgal authored Jan 15, 2024
1 parent b1a9b1c commit 98ad819
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FHist"
uuid = "68837c9b-b678-4cd5-9925-8a54edc8f695"
authors = ["Moelf <proton[at]jling.dev>", "Nick Amin <amin.nj[at]gmail.com>"]
version = "0.10.8"
version = "0.10.9"

[deps]
BayesHistogram = "000d9b38-65fe-4c81-bdb9-69f01f102479"
Expand Down
5 changes: 4 additions & 1 deletion src/hist1d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,10 @@ Merges `n` consecutive bins into one.
The returned histogram will have `nbins(h)/n` bins.
"""
function rebin(h::Hist1D, n::Int=1)
@assert nbins(h) % n == 0
if nbins(h) % n != 0
rebin_values = join(sort(collect(valid_rebin_values(h))), ", ", " or ")
error("Invalid rebin value ($n) for a 1D histogram with $(nbins(h)) bins. It has to be a multiple of $(rebin_values)")
end
p = x->Iterators.partition(x, n)
counts = sum.(p(bincounts(h)))
sumw2 = sum.(p(h.sumw2))
Expand Down
6 changes: 5 additions & 1 deletion src/hist2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,10 @@ Merges `nx` (`ny`) consecutive bins into one along the x (y) axis by summing.
"""
function rebin(h::Hist2D, nx::Int=1, ny::Int=nx)
sx, sy = nbins(h)
@assert sx % nx == sy % ny == 0
if !(sx % nx == sy % ny == 0)
rebin_values_x, rebin_values_y = map(x->join(sort(collect(x)), ", ", " or "), valid_rebin_values(h))
error("Invalid rebin values (nx: $nx, ny: $ny) for a 2D histogram with $(nbins(h)) bins. They have to be a multple of nx: $(rebin_values_x) and ny: $(rebin_values_y)")
end
p1d = (x,n)->Iterators.partition(x, n)
p2d = x->(x[i:i+(nx-1),j:j+(ny-1)] for i=1:nx:sx, j=1:ny:sy)
counts = sum.(p2d(bincounts(h)))
Expand All @@ -251,6 +254,7 @@ function rebin(h::Hist2D, nx::Int=1, ny::Int=nx)
end
rebin(nx::Int, ny::Int) = h::Hist2D -> rebin(h, nx, ny)


"""
project(h::Hist2D, axis::Symbol=:x)
project(axis::Symbol=:x) = h::Hist2D -> project(h, axis)
Expand Down
30 changes: 30 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,33 @@ end
function _is_uniform_bins(A::AbstractRange{T}) where T<:Real
true
end

"""
valid_rebin_values(h::Union{Hist1D, Hist2D, Hist3D})
Calculates the legal values for rebinning, essentially the prime factors of
the number of bins. For a 1D histogram, a `Set` of numbers is return, for higher
dimensional histograms a `Vector{Set}` for each dimension.
"""
valid_rebin_values(h::Hist1D) = _factor(nbins(h))
valid_rebin_values(h::Union{Hist2D, Hist3D}) = [_factor(x) for x in nbins(h)]

"""
function _factor(n::Integer)
Helper function to calculate the prime factors of a given integer.
"""
function _factor(n::Integer)
factors = Set{Int}()
limit = n
factor = 2
while n > 1 & factor < limit
while n % factor == 0
n /= factor
push!(factors, factor)
limit = sqrt(n)
end
factor += 1
end
factors
end
7 changes: 6 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -419,13 +419,15 @@ end
@test integral(h1) == integral(rebin(h1, 5))
@test sum(h1.sumw2) == sum(rebin(h1, 5).sumw2)
@test binedges(rebin(h1, 5)) == [0, 0.5, 1.0]
@test Set([2, 5]) == FHist.valid_rebin_values(h1)

h2 = Hist1D(rand(10^2), [0.0, 0.1, 0.7, 0.9, 1.0])
@test h2 == rebin(h2, 1)
@test integral(h2) == integral(rebin(h2, 2))
@test nentries(h2) == nentries(rebin(h2, 1))
@test sum(h2.sumw2) == sum(rebin(h2, 2).sumw2)
@test binedges(rebin(h2, 2)) == [0, 0.7, 1.0]
@test Set([2]) == FHist.valid_rebin_values(h2)

@test rebin(h1, 2) == (h1 |> rebin(2))

Expand All @@ -434,17 +436,20 @@ end
@test integral(h1) == integral(rebin(h1, 5))
@test sum(h1.sumw2) == sum(rebin(h1, 5).sumw2)
@test binedges(rebin(h1, 5)) == ([0, 0.5, 1.0], [0, 0.5, 1.0])
@test Set([2]) == FHist.valid_rebin_values(h2)

bins = [0.0, 0.1, 0.7, 0.9, 1.0]
h2 = Hist2D((rand(10^2),rand(10^2)), (bins,bins))
@test h2 == rebin(h2, 1) == (h2 |> rebin(1, 1))
@test integral(h2) == integral(rebin(h2, 2))
@test sum(h2.sumw2) == sum(rebin(h2, 2).sumw2)
@test binedges(rebin(h2, 2)) == ([0, 0.7, 1.0], [0, 0.7, 1.0])
@test [Set([2]), Set([2])] == FHist.valid_rebin_values(h2)

h2 = Hist2D((rand(10^2),rand(10^2)), (0:0.1:1,0:0.5:1))
@test nbins(rebin(h2, 10, 2)) == (1, 1)
@test_throws AssertionError rebin(h2, 2, 10)
@test_throws ErrorException rebin(h2, 2, 10)
@test [Set([5, 2]), Set([2])] == FHist.valid_rebin_values(h2)
end

@testset "Profile" begin
Expand Down

2 comments on commit 98ad819

@tamasgal
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/98928

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.10.9 -m "<description of version>" 98ad81986020d30bf8b3f83098291f8d489af249
git push origin v0.10.9

Please sign in to comment.