position-beeswarm

Density-shaped per-row offset on x.

For every bucket of rows sharing an x value, each point is offset sideways by width × (2·v − 1) × d, where v walks the van der Corput base-2 sequence in y order and d is the point’s Gaussian kernel density estimate normalised to the bucket’s peak. Dense regions spread wide, sparse tails stay close to the spine, and the result is a violin-shaped swarm.

A discrete (categorical) x is swarmed directly on its level positions, keeping the axis labels. as-factor is only needed to force a numeric column onto a discrete axis.

Usage

position-beeswarm(
  width: 0.4,
  adjust: 1,
)

Parameters

Parameter Default Description
width 0.4 Maximum absolute offset applied to the x position, in x data units.
adjust 1 Bandwidth multiplier for the density estimate: adjust: 0.5 halves the smoothing.

Returns

Position dictionary with name: "beeswarm", consumed by plot.

Examples

Swarm overplotted points per group; a tighter width keeps the cloud close to its spine.

#let d = ()
#for grp in ("a", "b") {
  for i in range(0, 50) {
    d.push((grp: grp, y: calc.sin(i * 0.7) + calc.sin(i * 1.9) + (if grp == "b" { 4 } else { 0 })))
  }
}
#plot(
  data: d,
  mapping: aes(x: as-factor("grp"), y: "y"),
  layers: (geom-point(size: 2pt, position: position-beeswarm(width: 0.25)),),
  width: 10cm,
  height: 6cm,
)

Beeswarm chart with groups a, b on the x-axis and values on the y-axis; points spread sideways into narrow swarms that taper towards sparse values.

Beeswarm chart with groups a, b on the x-axis and values on the y-axis; points spread sideways into narrow swarms that taper towards sparse values.

See also

position-jitter, geom-beeswarm.

Back to top