Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add smart fillto to enable logscale y-axis stacked barplot #4849

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Changelog

## [Unreleased]

- Use the `bar_default_fillto` method from [#3004](https://github.com/MakieOrg/Makie.jl/pull/3004) in stacked barplots as well, to stop the first member of the stack from disappearing in log scale [#4670](https://github.com/MakieOrg/Makie.jl/pull/4849).

## [0.22.2] - 2025-02-26

Expand Down
8 changes: 7 additions & 1 deletion ReferenceTests/src/tests/examples2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,12 @@ end
f
end

@reference_test "Log scale stacked barplot" begin
f = Figure()
barplot(f[1,1], [1,2,3,1,2,3], [1,2,3,1,2,3], stack=[1,1,1,2,2,2], color=[1,1,1,2,2,2], gap=0; axis=(; yscale=log))
f
end

@reference_test "Log scale histogram (barplot)" begin
f = Figure()
hist(
Expand Down Expand Up @@ -1925,4 +1931,4 @@ end
translate!(a.scene, 0.1, 0.05) # test that pattern are anchored to the plot
Makie.step!(st)
st
end
end
36 changes: 23 additions & 13 deletions src/basic_recipes/barplot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,28 @@ Returns a Tuple of new y positions and offset arrays.
- `ys`: The y-values passed to `barplot`.
- `offset`: The `offset` parameter passed to `barplot`.
"""
function bar_default_fillto(tf, ys, offset, in_y_direction)
return ys, offset
end

# `fillto` is related to `y-axis` transformation only, thus we expect `tf::Tuple`
function bar_default_fillto(tf::Tuple, ys, offset, in_y_direction)
_logT = Union{typeof(log), typeof(log2), typeof(log10), Base.Fix1{typeof(log), <: Real}}
if in_y_direction && tf[2] isa _logT || (!in_y_direction && tf[1] isa _logT)
function bar_default_fillto(tf, ys, offset, in_y_direction; log_clamp=false)
if log_clamp
# 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, ys) / 2
return clamp.(ys, smart_fillto, Inf), smart_fillto
_smart_log_clamp(ys)
else
return ys, offset
end
end

"""
_smart_log_clamp(ys, ref=ys)::(ys_clamped, min_ref/2)

Clamps the values of `ys` to a minimum value that is half the minimum non-zero value in `ref`.
"""
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

"""
barplot(positions, heights; kwargs...)

Expand Down Expand Up @@ -141,7 +146,7 @@ function stack_from_to(i_stack, y)
(from = view(from, inv_perm), to = view(to, inv_perm))
end

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

Expand All @@ -162,6 +167,9 @@ function stack_grouped_from_to(i_stack, y, grp)
to[inds] .= fromto.to
end

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

Expand Down Expand Up @@ -291,9 +299,11 @@ function Makie.plot!(p::BarPlot)
# ----------- Stacking -----------
# --------------------------------

_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 stack === automatic
if fillto === automatic
y, fillto = bar_default_fillto(transformation, y, offset, in_y_direction)
y, fillto = bar_default_fillto(transformation, y, offset, in_y_direction; log_clamp = log_clamp)
end
elseif eltype(stack) <: Integer
fillto === automatic || @warn "Ignore keyword fillto when keyword stack is provided"
Expand All @@ -303,7 +313,7 @@ function Makie.plot!(p::BarPlot)
end
i_stack = stack

from, to = stack_grouped_from_to(i_stack, y, (x = x̂,))
from, to = stack_grouped_from_to(i_stack, y, (x = x̂,); log_clamp = log_clamp)
y, fillto = to, from
else
ArgumentError("The keyword argument `stack` currently supports only `AbstractVector{<: Integer}`") |> throw
Expand Down
Loading