===Report generated with Claude assistance===
Summary
The varwidth argument in geom_quasirandom() no longer works as of v0.7.1. All groups are rendered at the same width regardless of their relative sizes, making varwidth = TRUE effectively a no-op. This was working correctly in v0.6.0.
Reproducible Example
library(ggplot2)
library(ggbeeswarm)
library(patchwork)
N1 <- 10
N2 <- 100
set.seed(123)
distro <- data.frame(
variable = c(rep("runif", N1), rep("rnorm", N2)),
value = c(runif(N1, min = -3, max = 3), rnorm(N2))
)
pT <- ggplot(distro, aes(variable, value)) +
geom_quasirandom(varwidth = TRUE) +
ggtitle("varwidth = TRUE")
pF <- ggplot(distro, aes(variable, value)) +
geom_quasirandom(varwidth = FALSE) +
ggtitle("varwidth = FALSE")
pT + pF
Expected Behavior
The runif group (N = 10) should be rendered with a significantly narrower spread than the rnorm group (N = 100), scaled proportionally to sqrt(10 / 100) = 0.316. This is the behavior documented in the vignette and was working correctly in v0.6.0.
Actual Behavior
Both panels (varwidth = TRUE and varwidth = FALSE) look identical. The width of each group is not scaled by relative group size.
Root Cause Analysis
The regression was introduced in the v0.7.1 refactor of the position functions.
In v0.6.0, PositionQuasirandom used compute_panel, which receives all groups' data simultaneously. This allowed the varwidth scaling to compute max_n — the size of the largest group — across all groups, and then scale each group relative to it:
# v0.6.0 - compute_panel sees all groups at once
max_n <- max(table(data$x))
width_scale <- sqrt(nrow(group_data) / max_n) # correct relative scaling
In v0.7.x, the refactor switched to compute_group, which only receives one group's data at a time. As a result, max_n is now implicitly the current group's own size, so the scaling factor is always sqrt(n / n) = 1.0 for every group:
# v0.7.x - compute_group sees only the current group
max_n <- nrow(data) # always equals the current group size
width_scale <- sqrt(nrow(data) / max_n) # always 1.0 -> no effect
Suggested Fix
The fix requires access to all groups' sizes when computing the width scale for any individual group. Two approaches:
Option A — Switch varwidth logic back to compute_panel:
compute_panel = function(self, data, params, scales) {
if (self$varwidth) {
max_n <- max(table(data$x))
# pass max_n into each per-group call
}
# then call compute_group per group with max_n available
}
Option B — Pre-compute max_n across all groups and store it as a position parameter before compute_group is called, then use it inside compute_group.
Workaround
Until this is fixed, varwidth can be approximated manually:
n_per_group <- table(distro$variable)
max_n <- max(n_per_group)
distro$vw <- sqrt(n_per_group[distro$variable] / max_n)
ggplot(distro, aes(variable, value)) +
geom_quasirandom(aes(width = vw))
Version Information
packageVersion("ggbeeswarm") # 0.7.3 (affected)
packageVersion("ggplot2")
R.version$version.string
- Affected versions: v0.7.1, v0.7.2, v0.7.3
- Last tested working version: v0.6.0
===Report generated with Claude assistance===
Summary
The
varwidthargument ingeom_quasirandom()no longer works as of v0.7.1. All groups are rendered at the same width regardless of their relative sizes, makingvarwidth = TRUEeffectively a no-op. This was working correctly in v0.6.0.Reproducible Example
Expected Behavior
The
runifgroup (N = 10) should be rendered with a significantly narrower spread than thernormgroup (N = 100), scaled proportionally tosqrt(10 / 100) = 0.316. This is the behavior documented in the vignette and was working correctly in v0.6.0.Actual Behavior
Both panels (
varwidth = TRUEandvarwidth = FALSE) look identical. The width of each group is not scaled by relative group size.Root Cause Analysis
The regression was introduced in the v0.7.1 refactor of the position functions.
In v0.6.0,
PositionQuasirandomusedcompute_panel, which receives all groups' data simultaneously. This allowed the varwidth scaling to computemax_n— the size of the largest group — across all groups, and then scale each group relative to it:In v0.7.x, the refactor switched to
compute_group, which only receives one group's data at a time. As a result,max_nis now implicitly the current group's own size, so the scaling factor is alwayssqrt(n / n) = 1.0for every group:Suggested Fix
The fix requires access to all groups' sizes when computing the width scale for any individual group. Two approaches:
Option A — Switch
varwidthlogic back tocompute_panel:Option B — Pre-compute
max_nacross all groups and store it as a position parameter beforecompute_groupis called, then use it insidecompute_group.Workaround
Until this is fixed,
varwidthcan be approximated manually:Version Information