Skip to content

Commit

Permalink
clamp_errors options for Makie Errorbars and clamp_bincounts for …
Browse files Browse the repository at this point in the history
…histograms (#118)

* add error_function options

* update pluto examples

* add scatter example

* throw error on bad combination of clamping

---------

Co-authored-by: Franchellucci Stefano <[email protected]>
  • Loading branch information
Moelf and sfranchel authored May 30, 2024
1 parent 2f26e2c commit 30a4197
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 31 deletions.
52 changes: 45 additions & 7 deletions docs/src/notebooks/makie_plotting.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
### A Pluto.jl notebook ###
# v0.19.40
# v0.19.42

using Markdown
using InteractiveUtils
Expand All @@ -13,7 +13,7 @@ let
using Pkg: Pkg
Pkg.activate(docs_dir)
Pkg.develop(; path=pkg_dir)
Pkg.instantiate()
Pkg.update()
end;

# ╔═╡ 82a6fb18-e9c9-450d-9c93-e05bd6cf5859
Expand Down Expand Up @@ -52,7 +52,7 @@ end

# ╔═╡ 91a8b01a-54e7-4955-bb56-1803d3f2576a
begin
h1_log = Hist1D(rand(10^5);binedges = [0.001, 0.01, 0.1, 1])
h1_log = Hist1D(rand(10^5); binedges = [0.001, 0.01, 0.1, 1])
ax_log = plot(h1_log; axis=(;xscale=log10, yscale=log10), label = "log-log scale")
xlims!(0.0001, nothing)
ylims!(1, nothing)
Expand Down Expand Up @@ -83,9 +83,9 @@ md"""
begin
fig2d = Figure()
h2d = Hist2D((randn(10000), randn(10000)))
plot(fig2d[1,2], h2d)
_, _heatmap = plot(fig2d[1,2], h2d)
statbox!(fig2d, h2d; position=(1,1))
Colorbar(fig2d[1,3])
Colorbar(fig2d[1,3], _heatmap)
fig2d
end

Expand All @@ -100,7 +100,6 @@ begin
f2_uneven = Figure()
plot(f2_uneven[2,1], h2d_even; axis=(title="even x-binning", ))
plot(f2_uneven[1,1], h2d_uneven; axis=(title="uneven x-binning", ))
Colorbar(f2_uneven[:,2])
f2_uneven
end

Expand Down Expand Up @@ -171,6 +170,42 @@ begin
f_ratio
end

# ╔═╡ 877172c9-df03-4157-af80-a99f3bd5bd3f
md"""## Clamping/clipping bincounts and errorbars
| - | clamp_bincounts = false (default) | clamp_bincounts = true |
| --- | -------------------------------- | -------------------------------- |
| clamp_errors = false | ![image](https://github.com/Moelf/FHist.jl/assets/5306213/e8571535-0d5a-47f1-97a5-efd223f5973b) | Don't do this |
| clamp_errors = true (default) | ![image](https://github.com/Moelf/FHist.jl/assets/5306213/a29d9dee-481f-4604-bcc2-113125ede1e3) | ![image](https://github.com/Moelf/FHist.jl/assets/5306213/7004f258-5aa9-4d9c-b303-116fec79b17a) |
!!! note
`clamp_bincounts` only works with `stairs()` and `barplot()` directly (does not work with `stephist(), hist()` for the moment.
See Makie upstream github issue: [https://github.com/MakieOrg/Makie.jl/issues/3904](https://github.com/MakieOrg/Makie.jl/issues/3904)
"""

# ╔═╡ b9ae652e-75bf-454b-83c6-fa6b4ef74faa
let h = Hist1D(;binedges=0:2, bincounts=[-0.1, 0.1], sumw2=[0.1, 0.1])
fig = Figure()

scatter(fig[1,1], h;); errorbars!(h; clamp_errors=false);
scatter(fig[2,1], h;); errorbars!(h; clamp_errors=true);
scatter(fig[2,2], h; clamp_bincounts=true); errorbars!(h; clamp_bincounts=true, clamp_errors=true);

fig
end

# ╔═╡ f9255f7c-fd44-46cc-bccc-a8c4b5033502
let h = Hist1D(;binedges=0:2, bincounts=[-0.1, 0.1], sumw2=[0.1, 0.1])
fig = Figure()

stairs(fig[1,1], h;); errorbars!(h; clamp_errors=false);
stairs(fig[2,1], h;); errorbars!(h; clamp_errors=true);
stairs(fig[2,2], h; clamp_bincounts=true); errorbars!(h; clamp_bincounts=true, clamp_errors=true);

fig
end

# ╔═╡ 2f97d05b-9103-451e-8fce-bb7458acf2ba
md"""
# Shading/Hatching errorbar band
Expand All @@ -189,7 +224,7 @@ end

# ╔═╡ fae56f0f-bac4-4dea-b33c-d45e6f3b51fc
let
f, a, p = stackedhist([h1, h1 ]; error_color=Pattern('/'))
f, a, p = stackedhist([h1, h1]; error_color=Pattern('/'))
f
end

Expand All @@ -213,6 +248,9 @@ end
# ╠═089fb6a1-3f2a-45f4-b4bf-4013dee3a6da
# ╠═a3dd8f72-d292-4f85-be76-2647b9433b42
# ╠═b1188446-d16b-4e0c-93be-c5e3d0de379c
# ╟─877172c9-df03-4157-af80-a99f3bd5bd3f
# ╠═b9ae652e-75bf-454b-83c6-fa6b4ef74faa
# ╠═f9255f7c-fd44-46cc-bccc-a8c4b5033502
# ╟─2f97d05b-9103-451e-8fce-bb7458acf2ba
# ╠═b114c8a7-5f01-44fe-9660-b5021d359399
# ╠═fae56f0f-bac4-4dea-b33c-d45e6f3b51fc
92 changes: 68 additions & 24 deletions ext/FHistMakieExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ isdefined(Base, :get_extension) ? (using Makie) : (using ..Makie)

import FHist: stackedhist, stackedhist!

function _clamp_counts!(c_vec)
min_positive = eps()
@. c_vec = max(c_vec, min_positive)
return nothing
end

function _clamp_counts_errors!(c_vec, el_vec, eh_vec)
# Set the clipping, and make copy of starting counts
min_positive = eps()
c_vec_def = copy(c_vec)

_clamp_counts!(c_vec)

# clip lower errors
mask = c_vec - el_vec .< min_positive
@views el_vec[mask] = c_vec[mask] .- min_positive

# clip higher errors
@. eh_vec = max(eh_vec - (c_vec - c_vec_def), min_positive)

return nothing
end


"""
stackedhist(hs:AbstractVector{<:Hist1D}; errors=true|:bar|:shade, color=Makie.wong_colors())
Expand Down Expand Up @@ -107,37 +131,59 @@ function Makie.plot!(input::RatioHist{<:Tuple{<:Hist1D, <:Hist1D}})
ratiohist!(input, hratio)
end

Makie.used_attributes(::Type{<:Makie.Plot}, h::Hist1D) = (:clamp_bincounts, )
function Makie.convert_arguments(P::Type{<:Scatter}, h::Hist1D; clamp_bincounts=false)
ys = copy(bincounts(h))
if clamp_bincounts
_clamp_counts!(ys)
end
convert_arguments(P, bincenters(h), ys)
end
function Makie.convert_arguments(P::Type{<:BarPlot}, h::Hist1D; clamp_bincounts=false)
ys = copy(bincounts(h))
if clamp_bincounts
_clamp_counts!(ys)
end
convert_arguments(P, bincenters(h), ys)
end

Makie.MakieCore.plottype(::Hist1D) = Hist
function Makie.convert_arguments(P::Type{<:Stairs}, h::Hist1D)
function Makie.convert_arguments(P::Type{<:Stairs}, h::Hist1D; clamp_bincounts=false)
edges = binedges(h)
phantomedge = edges[end] # to bring step back to baseline
bot = eps()
bc = bincounts(h)
bc = copy(bincounts(h))
if clamp_bincounts
_clamp_counts!(bc)
end
z = zero(eltype(bc))
nonzero_bincounts = replace(bc, z => bot)
convert_arguments(P, vcat(edges, phantomedge), vcat(bot, nonzero_bincounts, bot))
end
Makie.convert_arguments(P::Type{<:Scatter}, h::Hist1D) = convert_arguments(P, bincenters(h), bincounts(h))
Makie.convert_arguments(P::Type{<:BarPlot}, h::Hist1D) = convert_arguments(P, bincenters(h), bincounts(h))

function Makie.convert_arguments(P::Type{<:Makie.Errorbars}, h::FHist.Hist1D)
se = FHist.binerrors(FHist.sqrt, h)
bincounts = FHist.bincounts(h)
if all(==(1.0), FHist.sumw2(h))
# no weights used in filling
convert_arguments(P, FHist.bincenters(h), bincounts, se)
Makie.used_attributes(::Type{<:Errorbars}, h::Hist1D) = (:clamp_bincounts, :clamp_errors, :error_function)
function Makie.convert_arguments(P::Type{<:Makie.Errorbars}, h::FHist.Hist1D; clamp_bincounts=false, clamp_errors=true, error_function=nothing)
xs = FHist.bincenters(h)
ys = copy(FHist.bincounts(h))
errs = if isnothing(error_function)
FHist.binerrors(FHist.sqrt, h)
else
# weights used, switch to pearson error if error bar dips below zero
pe = FHist.binerrors(FHist.pearson_err, h)
err_high, pe_low = first.(pe), last.(pe)
err_low = se
for i in eachindex(bincounts, se, pe_low)
if bincounts[i] - err_low[i] <= 0
err_low[i] = pe_low[i]
FHist.binerrors(error_function, h)
end
hi_errs, lo_errs = first.(errs), last.(errs)

if clamp_bincounts && clamp_errors
_clamp_counts_errors!(ys, lo_errs, hi_errs)
elseif !clamp_bincounts && clamp_errors
for i in eachindex(ys, lo_errs)
if ys[i] - lo_errs[i] <= 0
lo_errs[i] = ys[i] - eps()
end
end
convert_arguments(P, FHist.bincenters(h), bincounts, err_low, err_high)
end
elseif clamp_bincounts && !clamp_errors
error("Clamping bincounts without also clamping errors will produce incorrect visualization.")
end
convert_arguments(P, xs, ys, lo_errs, hi_errs)
end

function Makie.convert_arguments(P::Type{<:CrossBar}, h::Hist1D)
Expand All @@ -162,11 +208,8 @@ end

function Makie.plot!(plot::StepHist{<:Tuple{<:Hist1D}})
scene = Makie.parent_scene(plot)
attributes = Makie.default_theme(scene, Makie.Stairs)
for key in keys(attributes)
attributes[key] = get(plot.attributes, key, attributes[key])
end
stairs!(plot, attributes, plot[1])
valid_attributes = Makie.shared_attributes(plot, Makie.Stairs)
stairs!(plot, valid_attributes, plot[1])
plot
end

Expand Down Expand Up @@ -240,4 +283,5 @@ function FHist.collabtext!(axis, colabname = "ATLAS", stage = "Preliminary"; pos
font=[fill("TeX Gyre Heros Bold Italic Makie", length(colabname)); fill("TeX Gyre Heros Makie", length(stage)+1)]
)
end

end

0 comments on commit 30a4197

Please sign in to comment.