Skip to content

Commit 1986a39

Browse files
committed
Expand delayed evaluation docs
1 parent d8f27d4 commit 1986a39

File tree

2 files changed

+271
-58
lines changed

2 files changed

+271
-58
lines changed

R/aes-evaluation.r

Lines changed: 133 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,106 @@
22
#'
33
#' Most aesthetics are mapped from variables found in the data. Sometimes,
44
#' however, you want to delay the mapping until later in the rendering process.
5-
#' ggplot2 has three stages of the data that you can map aesthetics from. The
6-
#' default is to map at the beginning, using the layer data provided by the
7-
#' user. The second stage is after the data has been transformed by the layer
8-
#' stat. The third and last stage is after the data has been transformed and
9-
#' mapped by the plot scales. The most common example of mapping from stat
10-
#' transformed data is the height of bars in [geom_histogram()]:
11-
#' the height does not come from a variable in the underlying data, but
12-
#' is instead mapped to the `count` computed by [stat_bin()]. An example of
13-
#' mapping from scaled data could be to use a desaturated version of the stroke
14-
#' colour for fill. If you want to map directly from the layer data you should
15-
#' not do anything special. In order to map from stat transformed data you
16-
#' should use the `after_stat()` function to flag that evaluation of the
17-
#' aesthetic mapping should be postponed until after stat transformation.
18-
#' Similarly, you should use `after_scale()` to flag evaluation of mapping for
19-
#' after data has been scaled. If you want to map the same aesthetic multiple
20-
#' times, e.g. map `x` to a data column for the stat, but remap it for the geom,
21-
#' you can use the `stage()` function to collect multiple mappings.
5+
#' ggplot2 has three stages of the data that you can map aesthetics from, and
6+
#' three functions to control at which stage aesthetics should be evaluated.
227
#'
8+
#' @usage # These functions can be used inside the `aes()` function
9+
#' # used as the `mapping` argument in layers.
10+
#'
11+
#' @param x <[`data-masking`][rlang::topic-data-mask]> An aesthetic expression
12+
#' using variables calculated by the stat (`after_stat()`) or layer aesthetics
13+
#' (`after_scale()`).
14+
#' @param start <[`data-masking`][rlang::topic-data-mask]> An aesthetic
15+
#' expression using variables from the layer data.
16+
#' @param after_stat <[`data-masking`][rlang::topic-data-mask]> An aesthetic
17+
#' expression using variables calculated by the stat.
18+
#' @param after_scale <[`data-masking`][rlang::topic-data-mask]> An aesthetic
19+
#' expression using layer aesthetics.
20+
#'
21+
#' @note
2322
#' `after_stat()` replaces the old approaches of using either `stat()` or
2423
#' surrounding the variable names with `..`.
2524
#'
26-
#' @note Evaluation after stat transformation will have access to the
27-
#' variables calculated by the stat, not the original mapped values. Evaluation
28-
#' after scaling will only have access to the final aesthetics of the layer
29-
#' (including non-mapped, default aesthetics). The original layer data can only
30-
#' be accessed at the first stage.
25+
#' @section Staging:
26+
#' Below follows an overview of the three stages of evaluation and how aesthetic
27+
#' evaluation can be controlled.
28+
#'
29+
#' ## Stage 1: direct input
30+
#' The default is to map at the beginning, using the layer data provided by
31+
#' the user. If you want to map directly from the layer data you should not do
32+
#' anything special. This is the only stage where the original layer data can
33+
#' be accessed.
34+
#'
35+
#' ```{r direct_input, eval = FALSE}
36+
#' # 'x' and 'y' are mapped directly
37+
#' ggplot(mtcars) + geom_point(aes(x = mpg, y = disp))
38+
#' ```
39+
#'
40+
#' ## Stage 2: after stat transformation
41+
#' The second stage is after the data has been transformed by the layer
42+
#' stat. The most common example of mapping from stat transformed data is the
43+
#' height of bars in [geom_histogram()]: the height does not come from a
44+
#' variable in the underlying data, but is instead mapped to the `count`
45+
#' computed by [stat_bin()]. In order to map from stat transformed data you
46+
#' should use the `after_stat()` function to flag that evaluation of the
47+
#' aesthetic mapping should be postponed until after stat transformation.
48+
#' Evaluation after stat transformation will have access to the variables
49+
#' calculated by the stat, not the original mapped values. The 'computed
50+
#' variables' section in each stat lists which variables are available to
51+
#' access.
52+
#'
53+
#' ```{r after_stat_transformation, eval = FALSE}
54+
#' # The 'y' values for the histogram are computed by the stat
55+
#' ggplot(faithful, aes(x = waiting)) +
56+
#' geom_histogram()
57+
#'
58+
#' # Choosing a different computed variable to display, matching up the
59+
#' # histogram with the density plot
60+
#' ggplot(faithful, aes(x = waiting)) +
61+
#' geom_histogram(aes(y = after_stat(density))) +
62+
#' geom_density()
63+
#' ```
64+
#'
65+
#' ## Stage 3: after scale transformation
66+
#' The third and last stage is after the data has been transformed and
67+
#' mapped by the plot scales. An example of mapping from scaled data could
68+
#' be to use a desaturated version of the stroke colour for fill. You should
69+
#' use `after_scale()` to flag evaluation of mapping for after data has been
70+
#' scaled. Evaluation after scaling will only have access to the final
71+
#' aesthetics of the layer (including non-mapped, default aesthetics).
72+
#'
73+
#' ```{r after_scale_transformation, eval = FALSE}
74+
#' # The exact colour is known after scale transformation
75+
#' ggplot(mpg, aes(cty, colour = factor(cyl))) +
76+
#' geom_density()
77+
#'
78+
#' # We re-use colour properties for the fill without a separate fill scale
79+
#' ggplot(mpg, aes(cty, colour = factor(cyl))) +
80+
#' geom_density(aes(fill = after_scale(alpha(colour, 0.3))))
81+
#' ```
3182
#'
32-
#' @param x An aesthetic expression using variables calculated by the stat
33-
#' (`after_stat()`) or layer aesthetics (`after_scale()`).
34-
#' @param start An aesthetic expression using variables from the layer data.
35-
#' @param after_stat An aesthetic expression using variables calculated by the
36-
#' stat.
37-
#' @param after_scale An aesthetic expression using layer aesthetics.
83+
#' ## Complex staging
84+
#' If you want to map the same aesthetic multiple times, e.g. map `x` to a
85+
#' data column for the stat, but remap it for the geom, you can use the
86+
#' `stage()` function to collect multiple mappings.
87+
#'
88+
#' ```{r complex_staging, eval = FALSE}
89+
#' # Use stage to modify the scaled fill
90+
#' ggplot(mpg, aes(class, hwy)) +
91+
#' geom_boxplot(aes(fill = stage(class, after_scale = alpha(fill, 0.4))))
92+
#'
93+
#' # Using data for computing summary, but placing label elsewhere, as well as
94+
#' # using the computed 'y' as part of the label.
95+
#' ggplot(mpg, aes(class, displ)) +
96+
#' geom_violin() +
97+
#' stat_summary(
98+
#' aes(y = stage(displ, after_stat = 8),
99+
#' label = after_stat(paste(y, ymax, sep = " ± "))),
100+
#' geom = "text",
101+
#' fun = ~ round(mean(.x), 2),
102+
#' fun.max = ~ round(sd(.x), 2)
103+
#' )
104+
#' ```
38105
#'
39106
#' @rdname aes_eval
40107
#' @name aes_eval
@@ -55,6 +122,44 @@
55122
#' # Use stage to modify the scaled fill
56123
#' ggplot(mpg, aes(class, hwy)) +
57124
#' geom_boxplot(aes(fill = stage(class, after_scale = alpha(fill, 0.4))))
125+
#'
126+
#' # Making a proportional stacked density plot
127+
#' ggplot(mpg, aes(cty)) +
128+
#' geom_density(
129+
#' aes(colour = factor(cyl),
130+
#' fill = after_scale(alpha(colour, 0.3)),
131+
#' y = after_stat(count / sum(n[!duplicated(group)]))),
132+
#' position = "stack", bw = 1
133+
#' ) +
134+
#' geom_density(bw = 1)
135+
#'
136+
#' # Imitating a ridgeline plot
137+
#' ggplot(mpg, aes(cty, colour = factor(cyl))) +
138+
#' geom_ribbon(
139+
#' stat = "density", outline.type = "upper",
140+
#' aes(fill = after_scale(alpha(colour, 0.3)),
141+
#' ymin = after_stat(group),
142+
#' ymax = after_stat(group + ndensity))
143+
#' )
144+
#'
145+
#' # Labelling a bar plot
146+
#' ggplot(mpg, aes(class)) +
147+
#' geom_bar() +
148+
#' geom_text(
149+
#' aes(y = after_stat(count + 2),
150+
#' label = after_stat(count)),
151+
#' stat = "count"
152+
#' )
153+
#'
154+
#' # Labelling the upper hinge of a boxplot,
155+
#' # inspired by June Choe
156+
#' ggplot(mpg, aes(displ, class)) +
157+
#' geom_boxplot(outlier.shape = NA) +
158+
#' geom_text(
159+
#' aes(label = after_stat(xmax),
160+
#' x = stage(displ, after_stat = xmax)),
161+
#' stat = "boxplot", hjust = -0.5
162+
#' )
58163
NULL
59164

60165
#' @rdname aes_eval

man/aes_eval.Rd

Lines changed: 138 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)