Skip to content

Quasirandom Noise #202

@bdeonovic

Description

@bdeonovic

I tried to figure out how to contribute a pull request but I quickly realized the internals are quite complicated so I was not sure how to contribute.

Describe how it works in R's ggplot2
The quasirandom geom is a convenient means to offset points within categories to reduce overplotting.

library(tidyverse)
library(ggbeeswarm)

tibble(
    x=rep(LETTERS[1:3], 100), 
    y=rnorm(300, mean=0, sd=c(0.5, 1, 1.5))
) |> ggplot(aes(x,y)) + geom_quasirandom()
Image

I had a basic MWE implementation in julia for Plots a couple of years ago that can be used as a jumping off point (see https://discourse.julialang.org/t/jitter-r-function-equivalent-in-julia/43457/23) The relevant code is:

using Plots
using KernelDensity
using StatsBase

vandercorput(num::Integer, base::Integer) = sum(d * Float64(base) ^ -ex for (ex, d) in enumerate(digits(num, base=base)))

N=100
y = randn(N*3)
x=repeat(1:3, inner=[N])
y[x.==1] .= randn(N).*0.25

barwidth = 0.75 
width= 0.4 * barwidth

ngroups = length(unique(x))

k = Array{UnivariateKDE}(undef, ngroups)
max_dens = zeros(ngroups)
q = zeros(length(x))
dens = zeros(length(y))
for i in 1:ngroups
	k[i] = kde(y[x .== i])
	dens[x .== i] .= pdf(k[i], y[ x .== i])
	max_dens[i] = maximum(dens[x .== i])
	
	q[x .== i] .= vandercorput.(1:N, 2)[competerank(y[x .== i])]
end

x_jitter = x .+ width./max_dens[x] .*  (q .- 0.5) .* 2 .* dens

# jittered x
scatter(x_jitter, y)

# jittering lines up with a violin plot
violin!(x,y, alpha=0.5)
Image

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions