1212dots_grob = function (data , x , y , xscale = 1 ,
1313 name = NULL , gp = gpar(), vp = NULL ,
1414 dotsize = 1.07 , stackratio = 1 , binwidth = NA , layout = " bin" ,
15- overlaps = " nudge" , overflow = " warn" ,
15+ overlaps = " nudge" , overflow = " warn" , span = waiver(),
1616 subguide = " dots" ,
1717 verbose = FALSE ,
1818 orientation = " vertical" ,
@@ -29,7 +29,7 @@ dots_grob = function(data, x, y, xscale = 1,
2929 datas = datas ,
3030 xscale = xscale ,
3131 dotsize = dotsize , stackratio = stackratio , binwidth = binwidth , layout = layout ,
32- overlaps = overlaps , overflow = overflow ,
32+ overlaps = overlaps , overflow = overflow , span = span ,
3333 subguide = subguide ,
3434 verbose = verbose ,
3535 orientation = orientation ,
@@ -60,6 +60,7 @@ makeContent.dots_grob = function(x) {
6060 binwidth = grob_ $ binwidth
6161 layout = grob_ $ layout
6262 overlaps = grob_ $ overlaps
63+ span = grob_ $ span
6364 overflow = grob_ $ overflow
6465 subguide = grob_ $ subguide
6566 stackratio = grob_ $ stackratio
@@ -100,7 +101,15 @@ makeContent.dots_grob = function(x) {
100101 # find the best bin widths across all the dotplots we are going to draw
101102 binwidths = map_dbl_(datas , function (d ) {
102103 maxheight = max(d [[ymax ]] - d [[ymin ]])
103- find_dotplot_binwidth(d [[x ]], maxheight , heightratio , stackratio , layout = layout , side = d $ side [[1 ]])
104+ find_dotplot_binwidth(
105+ d [[x ]],
106+ maxheight ,
107+ heightratio ,
108+ stackratio ,
109+ layout = layout ,
110+ side = d $ side [[1 ]],
111+ span = span
112+ )
104113 })
105114
106115 binwidth = min(binwidths , user_max_binwidth )
@@ -151,7 +160,7 @@ makeContent.dots_grob = function(x) {
151160 dot_positions = bin_dots(
152161 d $ x , d $ y ,
153162 binwidth = binwidth , heightratio = heightratio , stackratio = stackratio ,
154- overlaps = overlaps ,
163+ overlaps = overlaps , span = span ,
155164 layout = layout , side = d $ side [[1 ]], orientation = orientation
156165 )
157166
@@ -274,7 +283,7 @@ draw_slabs_dots = function(
274283 ... ,
275284 fill_type , na.rm ,
276285 dotsize , stackratio , binwidth , layout ,
277- overlaps , overflow ,
286+ overlaps , overflow , span ,
278287 subguide ,
279288 verbose
280289) {
@@ -337,6 +346,7 @@ draw_slabs_dots = function(
337346 binwidth = binwidth ,
338347 layout = layout ,
339348 overlaps = overlaps ,
349+ span = span ,
340350 overflow = overflow ,
341351 subguide = subguide ,
342352 verbose = verbose ,
@@ -505,6 +515,12 @@ GeomDotsinterval = ggproto("GeomDotsinterval", GeomSlabinterval,
505515 ' ),
506516 smooth = glue_doc('
507517 <[function] | [string][character]> Smoother to apply to dot positions.
518+
519+ **Note:** in most cases, more reliable forms of smoothing can be achieved via
520+ changing layouts (e.g. using `layout = "bar"` instead of `smooth = "bar"`)
521+ or via other parameters (e.g. using `span = 1.25` for `"bin"`, `"hex"`,
522+ or `"weave"` layouts).
523+
508524 One of:
509525 - A function that takes a numeric vector of dot positions and returns a
510526 smoothed version of that vector, such as [smooth_bounded()],
@@ -536,27 +552,31 @@ GeomDotsinterval = ggproto("GeomDotsinterval", GeomSlabinterval,
536552 layout = glue_doc('
537553 <[string][character]> The layout method used for the dots. One of: \\ itemize{
538554 \\ item `"bin"` (default): places dots on the off-axis at the midpoint of
539- their bins as in the classic Wilkinson dotplot. This maintains the
555+ their bins as in the classic Wilkinson (1999) dotplot. This maintains the
540556 alignment of rows and columns in the dotplot. This layout is slightly
541- different from the classic Wilkinson algorithm in that: (1) it nudges
542- bins slightly to avoid overlapping bins and (2) if the input data are
543- symmetrical it will return a symmetrical layout.
557+ different from the Wilkinson algorithm: (1) it nudges bin positions
558+ slightly to avoid overlaps (see the `overlaps` parameter); (2) by default
559+ it does not apply a smoothing pass (but Wilkinson-style smoothing can be
560+ applied via passing `span = 1.25`); (3) it uses a backwards sweep to
561+ reduce right-edge binning effects; (4) if the input data are symmetrical,
562+ it bins out from the center to return a symmetrical layout.
544563 \\ item `"weave"`: uses the same basic binning approach of `"bin"`, but
545564 places dots in the off-axis at their actual positions (unless
546- `overlaps = "nudge"`, in which case overlaps may be nudged out of the
547- way). This maintains the alignment of rows but does not align dots
565+ `overlaps = "nudge"`, in which case overlaps within rows are nudged out
566+ of the way). This maintains the alignment of rows but does not align dots
548567 within columns.
549568 \\ item `"hex"`: uses the same basic binning approach of `"bin"`, but
550- alternates placing dots `+ binwidth/4` or `- binwidth/4` in the
551- off-axis from the bin center. This allows hexagonal packing by setting
552- a `stackratio` less than 1 (something like `0.9` tends to work).
569+ alternates placing dots at \\ eqn{\\ pm} `binwidth/4` in the
570+ off-axis from the bin center, giving a hexagonal layout. For
571+ an equilateral hexagonal packing, set `dotsize = k` and
572+ `stackratio = sqrt(3/4) / k` for some `k` (e.g. `0.9`).
553573 \\ item `"swarm"`: uses a version of the `"compactswarm"` layout from
554- [beeswarm::beeswarm()] ( with minor modifications to improve visual
555- symmetry when `side = "both"`). Does not maintain alignment of rows or
556- columns, but can be more compact and neat-looking, especially for
557- sample data (as opposed to quantile dotplots of theoretical
558- distributions, which may look better with `"bin"`, `"weave"`, or
559- `"hex"`).
574+ [beeswarm][beeswarm ::beeswarm()], with minor modifications to improve visual
575+ symmetry when `side = "both"`. Ensures dot are positioned exacty at their
576+ underlying data values. Does not maintain alignment of rows or
577+ columns, but can be more compact, especially for sample data (as opposed
578+ to quantile dotplots of theoretical distributions, which may look better
579+ with `"bin"`, `"weave"`, or `"hex"`).
560580 \\ item `"bar"`: for discrete distributions, lays out duplicate values in
561581 rectangular bars.
562582 }' ),
@@ -574,6 +594,29 @@ GeomDotsinterval = ggproto("GeomDotsinterval", GeomSlabinterval,
574594 dots to their desired positions, subject to the constraint that adjacent
575595 dots do not overlap.
576596 }' ),
597+ span = glue_doc('
598+ <scalar [numeric]> Non-negative smoothing/spacing parameter expressed as a
599+ fraction. The specific use and default value (`waiver()`) depend on the
600+ `layout`:
601+ \\ itemize{
602+ \\ item{For `layout = "bin"`, `"hex"`, or `"weave"`: A smoothing parameter
603+ expressed as a proportion of the `binwidth` (default: `0`, no smoothing).
604+ Use `span = 1.25` to apply moderate smoothing.
605+ A positive `span` applies a moving average to adjacent
606+ bins whose midpoints are within `span * binwidth` of each other,
607+ exchanging dots between bins using the method described
608+ by Wilkinson (1999). Specifically, for every bin \\ eqn{i} with midpoint
609+ \\ eqn{m_i} containing \\ eqn{f(i)} dots, the algorithm moves
610+ \\ eqn{\\ left\\ lfloor\\ frac{f(i + 1) - f(i)}{2}\\ right\\ rfloor} dots from bin
611+ \\ eqn{i + 1} to bin \\ eqn{i} if \\ eqn{m_{i + 1} - m_i \\ le} `span`.
612+ Good values for `span` are typically between `1` and `2`. `span = 1.25` is
613+ equivalent to Wilkinson\' s recommendation, which smooths bins that are at most
614+ `binwidth/4` apart.
615+ }
616+ \\ item For `layout = "bar"`: Width of bars expressed as a proportion of the data resolution
617+ (default: 0.9). Values are typically between `0` and `1`. Use smaller values to
618+ increase the spacing between bars.
619+ }' ),
577620 verbose = glue_doc('
578621 <scalar [logical]> If `TRUE`, print out the bin width of the dotplot. Can be useful
579622 if you want to start from an automatically-selected bin width and then adjust it
@@ -594,6 +637,7 @@ GeomDotsinterval = ggproto("GeomDotsinterval", GeomSlabinterval,
594637 stackratio = 1 ,
595638 layout = " bin" ,
596639 overlaps = " nudge" ,
640+ span = waiver(),
597641 smooth = " none" ,
598642 overflow = " warn" ,
599643 verbose = FALSE
0 commit comments