diff --git a/src/algorithms/jitter.jl b/src/algorithms/jitter.jl index 269a38f..10cc54e 100644 --- a/src/algorithms/jitter.jl +++ b/src/algorithms/jitter.jl @@ -61,8 +61,16 @@ function calculate!(buffer::AbstractVector{<: Point2}, alg::JitterAlgorithm, pos xs = first.(positions) ys = last.(positions) for x_val in unique(xs) + # Isolate the indices of this particular group group = xs .== x_val - @views buffer[group] .= Point2f.(xs[group] .+ create_jitter_array(ys[group], alg) .* markersize, ys[group]) + # Extract the marker size + ms = if markersize isa Number + markersize + else + view(markersize, group) + end + # Assign the jittered values to the buffer + @views buffer[group] .= Point2f.(xs[group] .+ create_jitter_array(ys[group], alg) .* ms, ys[group]) end end @@ -121,4 +129,4 @@ function create_jitter_array(data_array, jitter_type = UniformJitter()) jitter = jitter * (0.5jitter_width / clamp_max) return jitter -end \ No newline at end of file +end diff --git a/src/algorithms/simple.jl b/src/algorithms/simple.jl index 93e6a69..ca333f7 100644 --- a/src/algorithms/simple.jl +++ b/src/algorithms/simple.jl @@ -24,14 +24,19 @@ function calculate!(buffer::AbstractVector{<: Point2}, alg::SimpleBeeswarm, posi @debug "Calculating..." ys = last.(positions) xs = first.(positions) - for x_val in unique(xs) group = findall(==(x_val), xs) view_ys = view(ys, group) if isempty(view_ys) continue else - xs[group] .= simple_xs(view_ys, markersize, side) + ms = if markersize isa Number + markersize + else + view_ms = view(markersize, group) + maximum(view_ms) + end + xs[group] .= simple_xs(view_ys, ms, side) end end @@ -99,4 +104,4 @@ function simple_xs(ys, markersize, side) end end return xs -end \ No newline at end of file +end diff --git a/src/algorithms/simple2.jl b/src/algorithms/simple2.jl index 37c6c07..165ffdc 100644 --- a/src/algorithms/simple2.jl +++ b/src/algorithms/simple2.jl @@ -23,10 +23,21 @@ function calculate!(buffer::AbstractVector{<: Point2}, alg::SimpleBeeswarm2, pos view_ys = view(ys, group) perm = sortperm(view_ys) ys_sorted = view_ys[perm] + + ms = if markersize isa Number + markersize + else + if length(unique(markersize[group])) == 1 + markersize[group][1] + else # this should error + markersize[group] + end + end + if isempty(ys_sorted) continue else - xs[group] .= simple_beeswarm2(ys_sorted, markersize)[invperm(perm)] + xs[group] .= simple_beeswarm2(ys_sorted, ms)[invperm(perm)] end end diff --git a/src/algorithms/wilkinson.jl b/src/algorithms/wilkinson.jl index 7c94cf3..574f462 100644 --- a/src/algorithms/wilkinson.jl +++ b/src/algorithms/wilkinson.jl @@ -52,7 +52,13 @@ function calculate!(buffer::AbstractVector{<: Point2}, alg::WilkinsonBeeswarm, p ## the beeswarm for each group. for x_val in unique(xs) group = findall(==(x_val), xs) - wilkinson_kernel!(view(buffer, group), view(positions, group), markersize, side) + ms = if markersize isa Number + markersize + else + view_ms = view(markersize, group) + maximum(view_ms) + end + wilkinson_kernel!(view(buffer, group), view(positions, group), ms, side) end end @@ -144,4 +150,4 @@ We force the points to dodge each other by `markersize`. buffer[idxs_by_position] .= Point2f.(((1:length(idxs_by_position))) .* (-markersize) .+ markersize/2 .+ first.(view(positions, idxs_by_position)), current_y) end end -end \ No newline at end of file +end diff --git a/test/runtests.jl b/test/runtests.jl index 4fb8410..c797654 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,9 +2,11 @@ using SwarmMakie, Makie, CairoMakie using Makie.Colors using Test using Random - Random.seed!(123) + +const ALL_ALGORITHMS = [NoBeeswarm(), SimpleBeeswarm(), SimpleBeeswarm2(), WilkinsonBeeswarm(), UniformJitter(), PseudorandomJitter(), QuasirandomJitter()] + colors = RGBf.(LinRange(0, 1, 1000), 0, 0) fig, ax, plt = scatter(ones(1000), randn(1000); color = colors) @@ -15,14 +17,14 @@ buffer = deepcopy(pixel_points) @testset "SwarmMakie.jl" begin @testset "Algorithms run without error" begin - for algorithm in [NoBeeswarm(), SimpleBeeswarm(), WilkinsonBeeswarm(), UniformJitter(), PseudorandomJitter(), QuasirandomJitter()] + for algorithm in ALL_ALGORITHMS @test_nowarn begin SwarmMakie.calculate!(buffer, algorithm, pixel_points, 10, :left) end end end @testset "Overlaps" begin - for algorithm in [SimpleBeeswarm(), WilkinsonBeeswarm()] + for algorithm in [SimpleBeeswarm(), SimpleBeeswarm2(), WilkinsonBeeswarm()] # We test how many points are overlapping, proportionately. f, a, p = beeswarm(original_points; alpha = 0.5, algorithm, color = :red) hidedecorations!(a) @@ -49,18 +51,26 @@ buffer = deepcopy(pixel_points) end @testset "Gutters" begin # First, we test the regular gutter with multiple categories. - f, a, p = beeswarm(rand(1:3, 300), randn(300); color = rand(RGBAf, 300), markersize = 20, algorithm = SimpleBeeswarm()) + f, a, p = beeswarm(rand(1:3, 300), randn(300); color = rand(RGBAf, 300), markersize = 20, algorithm = SimpleBeeswarm2()) Makie.update_state_before_display!(f) @test_warn "Gutter threshold exceeded" p.gutter = 0.2 # Next, we test it in direction y - f, a, p = beeswarm(rand(1:3, 300), randn(300); direction = :x, color = rand(RGBAf, 300), markersize = 20, algorithm = SimpleBeeswarm()) + f, a, p = beeswarm(rand(1:3, 300), randn(300); direction = :x, color = rand(RGBAf, 300), markersize = 20, algorithm = SimpleBeeswarm2()) Makie.update_state_before_display!(f) @test_warn "Gutter threshold exceeded" p.gutter = 0.2 # and it shouldn't warn if, when using a lower markersize, the gutter is not reached. - f, a, p = beeswarm(rand(1:3, 300), randn(300); direction = :y, color = rand(RGBAf, 300), markersize = 9, algorithm = SimpleBeeswarm()) + f, a, p = beeswarm(rand(1:3, 300), randn(300); direction = :y, color = rand(RGBAf, 300), markersize = 9, algorithm = SimpleBeeswarm2()) Makie.update_state_before_display!(f) @test_nowarn p.gutter = 0.5 end + @testset "Vector markersizes" begin + # First, we test the regular gutter with multiple categories. + xs = rand(1:3, 300) + for algorithm in ALL_ALGORITHMS + f, a, p = beeswarm(xs, randn(300); color = rand(RGBAf, 300), markersize = xs*2, algorithm) + Makie.update_state_before_display!(f) + end + end end # TODO: