Skip to content
Open
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
8 changes: 5 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
name = "FHist"
uuid = "68837c9b-b678-4cd5-9925-8a54edc8f695"
authors = ["Moelf <proton[at]jling.dev>", "Nick Amin <amin.nj[at]gmail.com>"]
version = "0.11.17"
authors = ["Moelf <proton[at]jling.dev>", "Nick Amin <amin.nj[at]gmail.com>"]

[deps]
BayesHistogram = "000d9b38-65fe-4c81-bdb9-69f01f102479"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"

[weakdeps]
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
Expand All @@ -34,17 +35,18 @@ Plots = "1.40"
RecipesBase = "^1"
Statistics = "1"
StatsBase = "^0.33, 0.34"
StructArrays = "0.7.2"
Test = "1"
julia = "^1.10"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"

[targets]
test = ["Test", "HDF5", "Aqua"]
docs = ["Test", "HDF5", "CairoMakie", "Plots"]
test = ["Test", "HDF5", "Aqua"]
78 changes: 76 additions & 2 deletions ext/FHistMakieExt.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module FHistMakieExt
using FHist, FHist.Measurements
using Statistics
using StructArrays
isdefined(Base, :get_extension) ? (using Makie) : (using ..Makie)

import FHist: stackedhist, stackedhist!
Expand Down Expand Up @@ -81,10 +82,66 @@ fig
color=Makie.wong_colors(),
labels=nothing,
whiskerwidth=10,
gap=-0.01
gap=-0.01,
direction=:y
)
end

function _smart_log_clamp(ys, ref=ys)
# x-scale log and !(in_y_direction) is equiavlent to y-scale log in_y_direction
# use the minimal non-zero y divided by 2 as lower bound for log scale
smart_fillto = minimum(y -> y<=0 ? oftype(y, Inf) : y, ref) / 2
return clamp.(ys, smart_fillto, Inf), smart_fillto
end


function stack_from_to_sorted(y)
to = cumsum(y)
from = [0.0; to[firstindex(to):end-1]]

(from = from, to = to)
end

function stack_from_to(i_stack, y)
# save current order
order = 1:length(y)
# sort by i_stack
perm = sortperm(i_stack)
# restore original order
inv_perm = sortperm(order[perm])

from, to = stack_from_to_sorted(view(y, perm))

(from = view(from, inv_perm), to = view(to, inv_perm))
end

function stack_grouped_from_to(i_stack, y, grp; log_clamp=false)
from = Array{Float64}(undef, length(y))
to = Array{Float64}(undef, length(y))

groupby = StructArray((; grp...))
grps = StructArrays.finduniquesorted(groupby)
last_pos = map(grps) do (g, inds)
g => any(y[inds] .> 0) || all(y[inds] .== 0)
end |> Dict
is_pos = map(y, groupby) do v, g
last_pos[g] = iszero(v) ? last_pos[g] : v > 0
end

groupby = StructArray((; grp..., is_pos))
grps = StructArrays.finduniquesorted(groupby)
for (grp, inds) in grps
fromto = stack_from_to(i_stack[inds], y[inds])
from[inds] .= fromto.from
to[inds] .= fromto.to
end

if log_clamp
from, _ = _smart_log_clamp(from, to)
end
(from = from, to = to)
end

function Makie.plot!(input::StackedHist{<:Tuple{AbstractVector{<:Hist1D}}})
hs = input[1][]
Nhist = length(hs)
Expand All @@ -100,12 +157,29 @@ function Makie.plot!(input::StackedHist{<:Tuple{AbstractVector{<:Hist1D}}})
totals = Measurements.value.(mes)
errs = Measurements.uncertainty.(mes)

dir = input.direction[]
in_y_direction = get((y=true, x=false), dir) do
error("Invalid direction $dir. Options are :x and :y.")
end

transformation = input.transformation.transform_func[]
_logT = Union{typeof(log), typeof(log2), typeof(log10), Base.Fix1{typeof(log), <: Real}}
log_clamp = transformation isa Tuple && in_y_direction&& transformation[2] isa _logT || (!in_y_direction && transformation[1] isa _logT)

if log_clamp
ys, fillto = _smart_log_clamp(ys)
end

if length(hs) > 1
ys, fillto = stack_grouped_from_to(grp, ys, (x=xs,); log_clamp)
end

c = input[:color][]
length(c) < Nhist && throw("provided $(length(c)) colors, not enough for $Nhist histograms")
Makie.barplot!(input, xs, ys;
stack=grp,
color=c[grp],
gap=input[:gap],
fillto
)

error_color = input[:error_color]
Expand Down