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

fix grouping of zero-height bar in barplot #3058

Merged
merged 11 commits into from
Oct 12, 2023
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# News

## master
- Fix grouping of a zero-height bar in `barplot`. Now a zero-height bar shares the same properties of the previous bar, and if the bar is the first one, its height is treated as positive if and only if there exists a bar of positive height or all bars are zero-height. [#3058](https://github.com/MakieOrg/Makie.jl/pull/3058)

- Fixed a bug where Axis still consumes scroll events when interactions are disabled [#3272](https://github.com/MakieOrg/Makie.jl/pull/3272)

Expand Down
15 changes: 9 additions & 6 deletions src/basic_recipes/barplot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,21 +141,24 @@ function stack_from_to(i_stack, y)
end

function stack_grouped_from_to(i_stack, y, grp)

from = Array{Float64}(undef, length(y))
to = Array{Float64}(undef, length(y))

groupby = StructArray((; grp..., is_pos = y .> 0))
Copy link
Collaborator

Choose a reason for hiding this comment

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

As far as I can tell just changing this to .>= works too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am afraid not. Given two stacked bars of heights [-6, 0], the second bar would stacked on the first one as expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh. You do remind me that we should determine the is_pos only based other bars inside of the same group, instead of globally. I will append a commit later. Thanks.

Copy link
Contributor Author

@ctarn ctarn Aug 24, 2023

Choose a reason for hiding this comment

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

Sorry for the delayed update. I have been too busy recently :(. A new commit has been added. You can test it using:

import Makie, CairoMakie

fig = Makie.Figure()

ax = Makie.Axis(fig[1, 1])
xs = [1, 1, 1, 1]
ys = [0, 1, -1, -1]
stack = [1, 2, 1, 2]
dodge = [1, 1, 2, 2]
color = Makie.cgrad(:Set2_8)[1:4]
Makie.barplot!(ax, xs, ys; stack, dodge, color, bar_labels=string.(ys))

display(fig)


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

(from = from, to = to)
Expand Down
130 changes: 130 additions & 0 deletions test/barplot.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
@testset "Barplot" begin
@testset "label align" begin
@testset "automatic" begin
# for more info see https://github.com/MakieOrg/Makie.jl/issues/3160
# below is the best square angles behavior for bar labels

al = Makie.automatic

y_dir, flip = false, false
@test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.0, 0.5)
@test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(1.0, 0.5)
@test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.5, 1.0)
@test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.5, 0.0)

y_dir, flip = true, false
@test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.5, 0.0)
@test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.5, 1.0)
@test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.0, 0.5)
@test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(1.0, 0.5)

y_dir, flip = false, true
@test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(1.0, 0.5)
@test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.0, 0.5)
@test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(0.5, 0.0)
@test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.5, 1.0)

y_dir, flip = true, true
@test Makie.calculate_bar_label_align(al, 0.0, y_dir, flip) ≈ Vec2f(0.5, 1.0)
@test Makie.calculate_bar_label_align(al, π, y_dir, flip) ≈ Vec2f(0.5, 0.0)
@test Makie.calculate_bar_label_align(al, π/2, y_dir, flip) ≈ Vec2f(1.0, 0.5)
@test Makie.calculate_bar_label_align(al, -π/2, y_dir, flip) ≈ Vec2f(0.0, 0.5)
end

@testset "manual" begin
input = 0.0, false, false
for align in (Vec2f(1.0, 0.5), Point2f(1.0, 0.5), (1.0, 0.5), (1, 0), (1.0, 0))
@test Makie.calculate_bar_label_align(align, input...) ≈ Vec2f(align)
end
end

@testset "symbols" begin
input = 0.0, false, false
@test Makie.calculate_bar_label_align((:center, :center), input...) ≈ Makie.calculate_bar_label_align((0.5, 0.5), input...)
end

@testset "error" begin
input = 0.0, false, false
for align in ("center", 0.5, ("center", "center"))
@test_throws ErrorException Makie.calculate_bar_label_align(align, input...)
end
end
end

@testset "stack" begin
x1 = [1, 1, 1, 1]
grp_dodge1 = [2, 2, 1, 1]
grp_stack1 = [1, 2, 1, 2]
y1 = [2, 3, -3, -2]

x2 = [2, 2, 2, 2]
grp_dodge2 = [3, 4, 3, 4]
grp_stack2 = [3, 4, 3, 4]
y2 = [2, 3, -3, -2]

from, to = Makie.stack_grouped_from_to(grp_stack1, y1, (; x1 = x1, grp_dodge1 = grp_dodge1))
from1 = [0.0, 2.0, 0.0, -3.0]
to1 = [2.0, 5.0, -3.0, -5.0]
@test from == from1
@test to == to1

from, to = Makie.stack_grouped_from_to(grp_stack2, y2, (; x2 = x2, grp_dodge2 = grp_dodge2))
from2 = [0.0, 0.0, 0.0, 0.0]
to2 = [2.0, 3.0, -3.0, -2.0]
@test from == from2
@test to == to2

perm = [1, 4, 2, 7, 5, 3, 8, 6]
x = [x1; x2][perm]
y = [y1; y2][perm]
grp_dodge = [grp_dodge1; grp_dodge2][perm]
grp_stack = [grp_stack1; grp_stack2][perm]

from_test = [from1; from2][perm]
to_test = [to1; to2][perm]

from, to = Makie.stack_grouped_from_to(grp_stack, y, (; x = x, grp_dodge = grp_dodge))
@test from == from_test
@test to == to_test
end

@testset "zero-height" begin
grp_stack = [1, 2, 1, 2]
x = [1, 1, 2, 2]

y = [1.0, 0.0, -1.0, -1.0]
from = [0.0, 1.0, 0.0, -1.0]
to = [1.0, 1.0, -1.0, -2.0]
from_, to_ = Makie.stack_grouped_from_to(grp_stack, y, (; x))
@test from == from_
@test to == to_

y = [-1.0, 0.0, -1.0, -1.0]
from = [0.0, -1.0, 0.0, -1.0]
to = [-1.0, -1.0, -1.0, -2.0]
from_, to_ = Makie.stack_grouped_from_to(grp_stack, y, (; x))
@test from == from_
@test to == to_

y = [0.0, 1.0, -1.0, -1.0]
from = [0.0, 0.0, 0.0, -1.0]
to = [0.0, 1.0, -1.0, -2.0]
from_, to_ = Makie.stack_grouped_from_to(grp_stack, y, (; x))
@test from == from_
@test to == to_

y = [0.0, -1.0, -1.0, -1.0]
from = [0.0, 0.0, 0.0, -1.0]
to = [0.0, -1.0, -1.0, -2.0]
from_, to_ = Makie.stack_grouped_from_to(grp_stack, y, (; x))
@test from == from_
@test to == to_

y = [0.0, 1.0, -1.0, -1.0]
from = [0.0, 0.0, 0.0, -1.0]
to = [0.0, 1.0, -1.0, -2.0]
from_, to_ = Makie.stack_grouped_from_to(1:4, y, (; x=ones(4)))
@test from == from_
@test to == to_
end
end
52 changes: 0 additions & 52 deletions test/barplot_labels.jl

This file was deleted.

3 changes: 1 addition & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ using Makie: volume
include("makielayout.jl")
include("figures.jl")
include("transformations.jl")
include("stack.jl")
include("events.jl")
include("text.jl")
include("boundingboxes.jl")
include("ray_casting.jl")
include("PolarAxis.jl")
include("barplot_labels.jl")
include("barplot.jl")
end
38 changes: 0 additions & 38 deletions test/stack.jl

This file was deleted.

Loading