using FHist, CairoMakie

Let's generate three dummy histograms sampled from three different distributions:

  1. unit Gaussian with 1000 points

  2. unit Gaussian with 10000 points

  3. unit Gaussians with 1000 points and a mean of 0.5

begin
    h1 = Hist1D(randn(10^3); binedges = -2:0.3:2)
    h2 = Hist1D(randn(10^4); binedges = -2:0.3:2)
    h3 = Hist1D(randn(10^3) .+ 0.5; binedges = -2:0.3:2)
end
-2.01.9
  • edges: [-2.0, -1.7, -1.4, -1.1, -0.8, -0.5, -0.2, 0.1, 0.4, 0.7, 1.0, 1.3, 1.6, 1.9]
  • bin counts: [8.0, 18.0, 29.0, 28.0, 63.0, 80.0, 88.0, 108.0, 125.0, 114.0, 105.0, 89.0, 55.0]
  • maximum count: 125.0
  • total count: 910.0

To plot a single histogram, you can do any of the following:

begin
    fig = Figure()
    p1, ax1= plot(fig[1, 1],h1; label = "plot(h1)")
    p2, ax2 = stephist(fig[1, 2], h1, label = "stairs(h1)")
    p3, ax3 = hist(fig[2, 1], h1, label = "hist(h1)")
    p4, ax4 = errorbars(fig[2, 2], h1, color=:black, whiskerwidth=6, label = "errorbars(h1)")
    axislegend.([p1, p2, p3, p4])
    fig
end
begin
    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)
    axislegend()
    ax_log
end

When you're studying a single histogram, it's hepful to have statbox (CERN ROOT enjoyer?)

We provide a statbox!() function to add such box:

begin
    f_s = stephist(h1)
    statbox!(f_s, h1)
    f_s
end

statbox also works for 2D histogram as one'd expect:

begin
    fig2d = Figure()
    h2d = Hist2D((randn(10000), randn(10000)))
    _, _heatmap = plot(fig2d[1,2], h2d)
    statbox!(fig2d, h2d; position=(1,1))
    Colorbar(fig2d[1,3], _heatmap)
    fig2d
end
begin
    even_edges = 0:0.1:1
    uneven_edges = [0, 0.2, 0.5, 1]
    data = (randn(10000), randn(10000))
    h2d_even =   Hist2D(data; binedges = (even_edges, even_edges))
    h2d_uneven = Hist2D(data; binedges = (uneven_edges, even_edges))
    
    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", ))
    f2_uneven
end

You can freely combine these by using the bang ! version to plot things on top of each other, for example this is some plot you might see:

begin
    pos_h2 = restrict(h2, 0, Inf)
    hist(pos_h2;
         label = "fake bkg", 
         axis=(
           limits=(nothing, nothing, 0.1, nothing),
               yminorticks=IntervalsBetween(5),
               yminorticksvisible = true,
               yscale=log10
              )
        )

    errorbars!(pos_h2; whiskerwidth=7)
    stephist!(h3; color=:red, label = "fake sig")
    axislegend()
    current_figure()
end

But it's also pretty common to have multiple background components (processes), in such case, we often want a stacked histogram with error bar representing the sum of each component added up correctly.

We also have a recipe for that:

with_theme(ATLASTHEME) do
    f, a, p = stackedhist([h2, h2, h1]; )
    labels = ["proc1", "blah", "third one"]
    elements = [PolyElement(polycolor = p.attributes.color[][i]) for i in 1:length(labels)]
    title = "Legend title"
    Legend(f[1,2], elements, labels, title)
    f
end

Notice the with_theme(ATLASTHEME), you can apply a bunch of appearance tweaks for the entire plot.

Finally, we have a recipe for ratio plot which is argubaly useful for the bottom pannel in many plots:

begin
    f_ratio, a, p = stephist(h1; label="h1")
    errorbars!(a, h1)
    stephist!(a, h3; label="h3")
    errorbars!(a, h3)
    
    axislegend()
    ratioax = Axis(f_ratio[2, 1], aspect = 5.5, xlabel = "my x-axis", ylabel="h1 / h3")
    linkxaxes!(ratioax, a)
    hidexdecorations!(a)
    ratiohist!(ratioax, h1/h3; color=:black, errors=true)
    rowsize!(f_ratio.layout, 1, Aspect(1, 0.5))
    f_ratio
end

Clamping/clipping bincounts and errorbars

-clamp_bincounts = false (default)clamp_bincounts = true
clamp_errors = falseimageDon't do this
clamp_errors = true (default)imageimage
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

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
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

Shading/Hatching errorbar band

let
    f, a, p = stackedhist([h1, h1 ]; error_color=(:black, 0.5))
    labels = ["proc1", "blah"]
    elements = [PolyElement(polycolor = p.attributes.color[][i]) for i in 1:length(labels)]
    title = "Legend title"
    Legend(f[1,2], elements, labels, title)
    f
end
let
    f, a, p = stackedhist([h1, h1]; error_color=Pattern('/'))
    f
end