From 37edadeada2e6dd94f84a96538b8f51f2cdc6c70 Mon Sep 17 00:00:00 2001 From: Tarn Yeong Ching Date: Thu, 2 Nov 2023 22:41:46 +0800 Subject: [PATCH 1/5] scale violin area by amount --- src/stats/violin.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stats/violin.jl b/src/stats/violin.jl index ef6e6f5ff99..da4d156a3ca 100644 --- a/src/stats/violin.jl +++ b/src/stats/violin.jl @@ -81,12 +81,12 @@ function plot!(plot::Violin) i1, i2 = searchsortedfirst(k.x, l1), searchsortedlast(k.x, l2) kde = (x = view(k.x, i1:i2), density = view(k.density, i1:i2)) c = getuniquevalue(color, idxs) - return (x = key.x, side = key.side, color = to_color(c), kde = kde, median = median(v)) + return (x = key.x, side = key.side, color = to_color(c), kde = kde, median = median(v), amount = length(idxs)) end max = if max_density === automatic maximum(specs) do spec - _, max = extrema_nan(spec.kde.density) + _, max = extrema_nan(spec.kde.density .* spec.amount) return max end else @@ -98,7 +98,7 @@ function plot!(plot::Violin) colors = RGBA{Float32}[] for spec in specs - scale = 0.5*violinwidth/max + scale = 0.5 * violinwidth * spec.amount / max xl = reverse(spec.x .- spec.kde.density .* scale) xr = spec.x .+ spec.kde.density .* scale yl = reverse(spec.kde.x) From 8fb6a19fb6ebe406d0679bab316f8f43198765fb Mon Sep 17 00:00:00 2001 From: Tarn Yeong Ching Date: Sat, 4 Nov 2023 20:46:02 +0800 Subject: [PATCH 2/5] add `scale` to `violin` --- src/stats/violin.jl | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/stats/violin.jl b/src/stats/violin.jl index da4d156a3ca..9fb9e4704c0 100644 --- a/src/stats/violin.jl +++ b/src/stats/violin.jl @@ -11,6 +11,7 @@ Draw a violin plot. - `gap=0.2`: shrinking factor, `width -> width * (1 - gap)` - `show_median=false`: show median as midline - `side=:both`: specify `:left` or `:right` to only plot the violin on one side +- `scale=:width`: scale density by area (`:area`), count (`:count`), or width (`:width`). - `datalimits`: specify values to trim the `violin`. Can be a `Tuple` or a `Function` (e.g. `datalimits=extrema`) """ @recipe(Violin, x, y) do scene @@ -21,6 +22,7 @@ Draw a violin plot. bandwidth = automatic, weights = automatic, side = :both, + scale = :area, orientation = :vertical, width = automatic, dodge = automatic, @@ -49,10 +51,10 @@ end function plot!(plot::Violin) x, y = plot[1], plot[2] - args = @extract plot (width, side, color, show_median, npoints, boundary, bandwidth, weights, + args = @extract plot (width, side, scale, color, show_median, npoints, boundary, bandwidth, weights, datalimits, max_density, dodge, n_dodge, gap, dodge_gap, orientation) signals = lift(plot, x, y, - args...) do x, y, width, vside, color, show_median, n, bound, bw, w, limits, max_density, + args...) do x, y, width, vside, scale_type, color, show_median, n, bound, bw, w, limits, max_density, dodge, n_dodge, gap, dodge_gap, orientation x̂, violinwidth = compute_x_and_width(x, width, gap, dodge, n_dodge, dodge_gap) @@ -84,10 +86,17 @@ function plot!(plot::Violin) return (x = key.x, side = key.side, color = to_color(c), kde = kde, median = median(v), amount = length(idxs)) end + (scale_type ∈ [:area, :count, :width]) || error("Invalid scale type: $(scale_type)") + max = if max_density === automatic maximum(specs) do spec - _, max = extrema_nan(spec.kde.density .* spec.amount) - return max + if scale_type === :area + return extrema_nan(spec.kde.density) |> last + elseif scale_type === :count + return extrema_nan(spec.kde.density .* spec.amount) |> last + elseif scale_type === :width + return NaN + end end else max_density @@ -98,7 +107,14 @@ function plot!(plot::Violin) colors = RGBA{Float32}[] for spec in specs - scale = 0.5 * violinwidth * spec.amount / max + scale = 0.5 * violinwidth + if scale_type === :area + scale = scale / max + elseif scale_type === :count + scale = scale / max * spec.amount + elseif scale_type === :width + scale = scale / (extrema_nan(spec.kde.density) |> last) + end xl = reverse(spec.x .- spec.kde.density .* scale) xr = spec.x .+ spec.kde.density .* scale yl = reverse(spec.kde.x) From 31aba1888b427d4b8849fcd1ec7e518c30cad2fe Mon Sep 17 00:00:00 2001 From: Tarn Yeong Ching Date: Sat, 4 Nov 2023 21:12:10 +0800 Subject: [PATCH 3/5] doc: add `scale` of `violin` --- docs/reference/plots/violin.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/reference/plots/violin.md b/docs/reference/plots/violin.md index 0491924a529..cb384cb7094 100644 --- a/docs/reference/plots/violin.md +++ b/docs/reference/plots/violin.md @@ -17,6 +17,25 @@ violin(xs, ys) ``` \end{examplefigure} +\begin{examplefigure}{} +```julia +using Makie, CairoMakie +CairoMakie.activate!() # hide + + +fig = Figure() +xs = vcat([fill(i, i * 1000) for i in 1:4]...) +ys = vcat(randn(6000), randn(4000) * 2) +for (i, scale) in enumerate([:area, :count, :width]) + ax = Axis(fig[i, 1]) + violin!(ax, xs, ys; scale, show_median=true) + Makie.xlims!(0.2, 4.8) + ax.title = "scale=:$(scale)" +end +fig +``` +\end{examplefigure} + \begin{examplefigure}{} ```julia using CairoMakie From 2f3d173a97f6ebbdbd9481fc6f026120a82d91a6 Mon Sep 17 00:00:00 2001 From: Tarn Yeong Ching Date: Sun, 25 Feb 2024 17:12:41 +0800 Subject: [PATCH 4/5] add reference test --- ReferenceTests/src/tests/examples2d.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index 72a8cb6a595..f1d0a4608b4 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -1392,3 +1392,16 @@ end ylims!(ax, 0, 1) fig end + +@reference_test "Violin plots differently scaled" begin + fig = Figure() + xs = vcat([fill(i, i * 1000) for i in 1:4]...) + ys = vcat(randn(6000), randn(4000) * 2) + for (i, scale) in enumerate([:area, :count, :width]) + ax = Axis(fig[i, 1]) + violin!(ax, xs, ys; scale, show_median=true) + Makie.xlims!(0.2, 4.8) + ax.title = "scale=:$(scale)" + end + fig +end From 54efcc359f4bb9522f9228b442ece3a2044e104b Mon Sep 17 00:00:00 2001 From: Tarn Yeong Ching Date: Sun, 25 Feb 2024 17:16:28 +0800 Subject: [PATCH 5/5] add change log --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11f298005b1..b1690be935e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## [Unreleased] +- Added `scale` attribute to `violin` [#3352](https://github.com/MakieOrg/Makie.jl/pull/3352). ## [0.20.8] - 2024-02-22