Skip to content

Commit b77aba2

Browse files
authored
Show make_constructor() a few times in extension vignette (#6542)
* use `make_constructor()` a few times * also apply to `geom_chull()`
1 parent a037084 commit b77aba2

File tree

1 file changed

+20
-60
lines changed

1 file changed

+20
-60
lines changed

vignettes/extending-ggplot2.Rmd

Lines changed: 20 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ The two most important components are the `compute_group()` method (which does t
7272

7373
Next we write a layer function. Unfortunately, due to an early design mistake I called these either `stat_()` or `geom_()`. A better decision would have been to call them `layer_()` functions: that's a more accurate description because every layer involves a stat _and_ a geom. Currently it is the convention to have `stat_()` wrappers with fixed `layer(stat)` arguments and `geom_()` wrappers with fixed `layer(geom)` arguments. The `stat_()` and `geom_()` functions both have the same ingredients and cook up new layers.
7474

75-
All layer functions follow the same form - you specify defaults in the function arguments and then call the `layer()` function, sending `...` into the `params` argument. The arguments in `...` will either be arguments for the geom (if you're making a stat wrapper), arguments for the stat (if you're making a geom wrapper), or aesthetics to be set. `layer()` takes care of teasing the different parameters apart and making sure they're stored in the right place:
75+
All layer functions follow the same form - you specify defaults in the function arguments and then call the `layer()` function, sending `...` into the `params` argument. The arguments in `...` will either be arguments for the geom (if you're making a stat wrapper), arguments for the stat (if you're making a geom wrapper), or aesthetics to be set. `layer()` takes care of teasing the different parameters apart and making sure they're stored in the right place.
7676

7777
```{r}
7878
stat_chull <- function(mapping = NULL, data = NULL, geom = "polygon",
@@ -88,6 +88,12 @@ stat_chull <- function(mapping = NULL, data = NULL, geom = "polygon",
8888

8989
(Note that if you're writing this in your own package, you'll either need to call `ggplot2::layer()` explicitly, or import the `layer()` function into your package namespace.)
9090

91+
If you have standard expectations of a constructor with no side effects (e.g. checking arguments), you can also use the `make_constructor()` function to build one for you. There is no sensible default geom for a stat, so you have to set the default one yourself.
92+
93+
```{r}
94+
stat_chull <- make_constructor(StatChull, geom = "polygon")
95+
print(stat_chull)
96+
```
9197
Once we have a layer function we can try our new stat:
9298

9399
```{r}
@@ -146,22 +152,14 @@ StatLm <- ggproto("StatLm", Stat,
146152
}
147153
)
148154
149-
stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
150-
position = "identity", na.rm = FALSE, show.legend = NA,
151-
inherit.aes = TRUE, ...) {
152-
layer(
153-
stat = StatLm, data = data, mapping = mapping, geom = geom,
154-
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
155-
params = list(na.rm = na.rm, ...)
156-
)
157-
}
155+
stat_lm <- make_constructor(StatLm, geom = "line")
158156
159157
ggplot(mpg, aes(displ, hwy)) +
160158
geom_point() +
161159
stat_lm()
162160
```
163161

164-
`StatLm` is inflexible because it has no parameters. We might want to allow the user to control the model formula and the number of points used to generate the grid. To do so, we add arguments to the `compute_group()` method and our wrapper function:
162+
`StatLm` is inflexible because it has no parameters. We might want to allow the user to control the model formula and the number of points used to generate the grid. To do so, we add arguments to the `compute_group()` method which will get picked up by `make_constructor()`.
165163

166164
```{r}
167165
#| fig.alt: "Scatterplot of engine displacement versus highway miles per
@@ -171,7 +169,7 @@ ggplot(mpg, aes(displ, hwy)) +
171169
StatLm <- ggproto("StatLm", Stat,
172170
required_aes = c("x", "y"),
173171
174-
compute_group = function(data, scales, params, n = 100, formula = y ~ x) {
172+
compute_group = function(data, scales, params = list(), n = 100, formula = y ~ x) {
175173
rng <- range(data$x, na.rm = TRUE)
176174
grid <- data.frame(x = seq(rng[1], rng[2], length = n))
177175
@@ -182,24 +180,16 @@ StatLm <- ggproto("StatLm", Stat,
182180
}
183181
)
184182
185-
stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
186-
position = "identity", na.rm = FALSE, show.legend = NA,
187-
inherit.aes = TRUE, n = 50, formula = y ~ x,
188-
...) {
189-
layer(
190-
stat = StatLm, data = data, mapping = mapping, geom = geom,
191-
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
192-
params = list(n = n, formula = formula, na.rm = na.rm, ...)
193-
)
194-
}
183+
stat_lm <- make_constructor(StatLm, geom = "line")
195184
196185
ggplot(mpg, aes(displ, hwy)) +
197186
geom_point() +
198187
stat_lm(formula = y ~ poly(x, 10)) +
199188
stat_lm(formula = y ~ poly(x, 10), geom = "point", colour = "red", n = 20)
200189
```
201190

202-
Note that we don't _have_ to explicitly include the new parameters in the arguments for the layer, `...` will get passed to the right place anyway. But you'll need to document them somewhere so the user knows about them. Here's a brief example. Note `@inheritParams ggplot2::stat_identity`: that will automatically inherit documentation for all the parameters also defined for `stat_identity()`.
191+
If you're defining a constructor function yourself, it is good practise to add the parameters as arguments.
192+
We don't _have_ to explicitly include the new parameters in the arguments for the layer, `...` will get passed to the right place anyway. But you'll need to document them somewhere so the user knows about them. Here's a brief example. Note `@inheritParams ggplot2::stat_identity`: that will automatically inherit documentation for all the parameters also defined for `stat_identity()`.
203193

204194
```{r}
205195
#' @export
@@ -257,16 +247,7 @@ StatDensityCommon <- ggproto("StatDensityCommon", Stat,
257247
}
258248
)
259249
260-
stat_density_common <- function(mapping = NULL, data = NULL, geom = "line",
261-
position = "identity", na.rm = FALSE, show.legend = NA,
262-
inherit.aes = TRUE, bandwidth = NULL,
263-
...) {
264-
layer(
265-
stat = StatDensityCommon, data = data, mapping = mapping, geom = geom,
266-
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
267-
params = list(bandwidth = bandwidth, na.rm = na.rm, ...)
268-
)
269-
}
250+
stat_density_common <- make_constructor(StatDensityCommon, geom = "line")
270251
271252
ggplot(mpg, aes(displ, colour = drv)) +
272253
stat_density_common()
@@ -400,15 +381,8 @@ GeomSimplePoint <- ggproto("GeomSimplePoint", Geom,
400381
}
401382
)
402383
403-
geom_simple_point <- function(mapping = NULL, data = NULL, stat = "identity",
404-
position = "identity", na.rm = FALSE, show.legend = NA,
405-
inherit.aes = TRUE, ...) {
406-
layer(
407-
geom = GeomSimplePoint, mapping = mapping, data = data, stat = stat,
408-
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
409-
params = list(na.rm = na.rm, ...)
410-
)
411-
}
384+
# Default stat is `stat_identity()`, no need to specify
385+
geom_simple_point <- make_constructor(GeomSimplePoint)
412386
413387
ggplot(mpg, aes(displ, hwy)) +
414388
geom_simple_point()
@@ -481,15 +455,8 @@ GeomSimplePolygon <- ggproto("GeomPolygon", Geom,
481455
)
482456
}
483457
)
484-
geom_simple_polygon <- function(mapping = NULL, data = NULL, stat = "chull",
485-
position = "identity", na.rm = FALSE, show.legend = NA,
486-
inherit.aes = TRUE, ...) {
487-
layer(
488-
geom = GeomSimplePolygon, mapping = mapping, data = data, stat = stat,
489-
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
490-
params = list(na.rm = na.rm, ...)
491-
)
492-
}
458+
459+
geom_simple_polygon <- make_constructor(GeomSimplePolygon, stat = "chull")
493460
494461
ggplot(mpg, aes(displ, hwy)) +
495462
geom_point() +
@@ -525,15 +492,8 @@ GeomPolygonHollow <- ggproto("GeomPolygonHollow", GeomPolygon,
525492
default_aes = aes(colour = "black", fill = NA, linewidth = 0.5, linetype = 1,
526493
alpha = NA)
527494
)
528-
geom_chull <- function(mapping = NULL, data = NULL,
529-
position = "identity", na.rm = FALSE, show.legend = NA,
530-
inherit.aes = TRUE, ...) {
531-
layer(
532-
stat = StatChull, geom = GeomPolygonHollow, data = data, mapping = mapping,
533-
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
534-
params = list(na.rm = na.rm, ...)
535-
)
536-
}
495+
496+
geom_chull <- make_constructor(GeomPolygonHollow, stat = "chull")
537497
538498
ggplot(mpg, aes(displ, hwy)) +
539499
geom_point() +

0 commit comments

Comments
 (0)