Skip to content

Update docs related to tidyeval #4827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 14 additions & 25 deletions R/aes.r
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,9 @@ NULL
#' scatter_by(mtcars, disp, drat)
#'
#' # If your wrapper has a more specific interface with named arguments,
#' # you need "enquote and unquote":
#' # you need the "embrace operator":
#' scatter_by <- function(data, x, y) {
#' x <- enquo(x)
#' y <- enquo(y)
#'
#' ggplot(data) + geom_point(aes(!!x, !!y))
#' ggplot(data) + geom_point(aes({{ x }}, {{ y }}))
#' }
#' scatter_by(mtcars, disp, drat)
#'
Expand Down Expand Up @@ -248,9 +245,18 @@ is_position_aes <- function(vars) {
#'
#' @section Life cycle:
#'
#' All these functions are soft-deprecated. Please use tidy evaluation
#' idioms instead (see the quasiquotation section in
#' [aes()] documentation).
#' All these functions are soft-deprecated. Please use tidy evaluation idioms
#' instead. Regarding `aes_string()`, you can replace it with `.data` pronoun.
#' For example, the following code can achieve the same mapping as
#' `aes_string(x_var, y_var)`.
#'
#' ``` r
#' x_var <- "foo"
#' y_var <- "bar"
#' aes(.data[[x_var]], .data[[y_var]])
#' ````
#'
#' For more details, please see `vignette("ggplot2-in-packages")`.
#'
#' @param x,y,... List of name value pairs. Elements must be either
#' quoted calls, strings, one-sided formulas or constants.
Expand All @@ -259,23 +265,6 @@ is_position_aes <- function(vars) {
#' @keywords internal
#'
#' @export
#' @examples
#' # Three ways of generating the same aesthetics
#' aes(mpg, wt, col = cyl)
#' aes_(quote(mpg), quote(wt), col = quote(cyl))
#' aes_(~mpg, ~wt, col = ~cyl)
#' aes_string("mpg", "wt", col = "cyl")
#'
#' # You can't easily mimic these calls with aes_string
#' aes(`$100`, colour = "smooth")
#' aes_(~ `$100`, colour = "smooth")
#' # Ok, you can, but it requires a _lot_ of quotes
#' aes_string("`$100`", colour = '"smooth"')
#'
#' # Convert strings to names with as.name
#' var <- "cyl"
#' aes(col = x)
#' aes_(col = as.name(var))
aes_ <- function(x, y, ...) {
lifecycle::deprecate_soft(
"3.0.0",
Expand Down
130 changes: 95 additions & 35 deletions R/utilities-tidy-eval.R
Original file line number Diff line number Diff line change
@@ -1,42 +1,102 @@
#' Tidy eval helpers
#'
#' @description
#' This page lists the tidy eval tools reexported in this package from
#' rlang. To learn about using tidy eval in scripts and packages at a
#' high level, see the [dplyr programming
#' vignette](https://dplyr.tidyverse.org/articles/programming.html)
#' and the [ggplot2 in packages
#' vignette](https://ggplot2.tidyverse.org/articles/ggplot2-in-packages.html).
#' The [Metaprogramming
#' section](https://adv-r.hadley.nz/metaprogramming.html) of [Advanced
#' R](https://adv-r.hadley.nz) may also be useful for a deeper dive.
#'
#' * \code{\link[rlang]{sym}()} creates a symbol from a string and
#' \code{\link[rlang:sym]{syms}()} creates a list of symbols from a
#' character vector.
#'
#' * \code{\link[rlang:nse-defuse]{enquo}()} and
#' \code{\link[rlang:nse-defuse]{enquos}()} delay the execution of one or
#' several function arguments. \code{enquo()} returns a single quoted
#' expression, which is like a blueprint for the delayed computation.
#' \code{enquos()} returns a list of such quoted expressions.
#'
#' * \code{\link[rlang:nse-defuse]{expr}()} quotes a new expression _locally_. It
#' is mostly useful to build new expressions around arguments
#' captured with [enquo()] or [enquos()]:
#' \code{expr(mean(!!enquo(arg), na.rm = TRUE))}.
#'
#' * \code{\link[rlang]{as_name}()} transforms a quoted variable name
#' into a string. Supplying something else than a quoted variable
#' name is an error.
#'
#' That's unlike \code{\link[rlang]{as_label}()} which also returns
#' a single string but supports any kind of R object as input,
#' including quoted function calls and vectors. Its purpose is to
#' summarise that object into a single label. That label is often
#' suitable as a default name.
#'
#' If you don't know what a quoted expression contains (for instance
#' expressions captured with \code{enquo()} could be a variable
#' name, a call to a function, or an unquoted constant), then use
#' \code{as_label()}. If you know you have quoted a simple variable
#' name, or would like to enforce this, use \code{as_name()}.
#'
#' To learn more about tidy eval and how to use these tools, visit
#' \url{https://tidyeval.tidyverse.org} and the
#' \href{https://adv-r.hadley.nz/metaprogramming.html}{Metaprogramming
#' section} of \href{https://adv-r.hadley.nz}{Advanced R}.
#' * The tidy eval operators `{{`, `!!`, and `!!!` are syntactic
#' constructs which are specially interpreted by tidy eval functions.
#' You will mostly need `{{`, as `!!` and `!!!` are more advanced
#' operators which you should not have to use in simple cases.
#'
#' The curly-curly operator `{{` allows you to tunnel data-variables
#' passed from function arguments inside other tidy eval functions.
#' `{{` is designed for individual arguments. To pass multiple
#' arguments contained in dots, use `...` in the normal way.
#'
#' ```
#' my_function <- function(data, var, ...) {
#' data %>%
#' group_by(...) %>%
#' summarise(mean = mean({{ var }}))
#' }
#' ```
#'
#' * [enquo()] and [enquos()] delay the execution of one or several
#' function arguments. The former returns a single expression, the
#' latter returns a list of expressions. Once defused, expressions
#' will no longer evaluate on their own. They must be injected back
#' into an evaluation context with `!!` (for a single expression) and
#' `!!!` (for a list of expressions).
#'
#' ```
#' my_function <- function(data, var, ...) {
#' # Defuse
#' var <- enquo(var)
#' dots <- enquos(...)
#'
#' # Inject
#' data %>%
#' group_by(!!!dots) %>%
#' summarise(mean = mean(!!var))
#' }
#' ```
#'
#' In this simple case, the code is equivalent to the usage of `{{`
#' and `...` above. Defusing with `enquo()` or `enquos()` is only
#' needed in more complex cases, for instance if you need to inspect
#' or modify the expressions in some way.
#'
#' * The `.data` pronoun is an object that represents the current
#' slice of data. If you have a variable name in a string, use the
#' `.data` pronoun to subset that variable with `[[`.
#'
#' ```
#' my_var <- "disp"
#' mtcars %>% summarise(mean = mean(.data[[my_var]]))
#' ```
#'
#' * Another tidy eval operator is `:=`. It makes it possible to use
#' glue and curly-curly syntax on the LHS of `=`. For technical
#' reasons, the R language doesn't support complex expressions on
#' the left of `=`, so we use `:=` as a workaround.
#'
#' ```
#' my_function <- function(data, var, suffix = "foo") {
#' # Use `{{` to tunnel function arguments and the usual glue
#' # operator `{` to interpolate plain strings.
#' data %>%
#' summarise("{{ var }}_mean_{suffix}" := mean({{ var }}))
#' }
#' ```
#'
#' * Many tidy eval functions like `dplyr::mutate()` or
#' `dplyr::summarise()` give an automatic name to unnamed inputs. If
#' you need to create the same sort of automatic names by yourself,
#' use `as_label()`. For instance, the glue-tunnelling syntax above
#' can be reproduced manually with:
#'
#' ```
#' my_function <- function(data, var, suffix = "foo") {
#' var <- enquo(var)
#' prefix <- as_label(var)
#' data %>%
#' summarise("{prefix}_mean_{suffix}" := mean(!!var))
#' }
#' ```
#'
#' Expressions defused with `enquo()` (or tunnelled with `{{`) need
#' not be simple column names, they can be arbitrarily complex.
#' `as_label()` handles those cases gracefully. If your code assumes
#' a simple column name, use `as_name()` instead. This is safer
#' because it throws an error if the input is not a name as expected.
#'
#' @md
#' @name tidyeval
Expand Down
7 changes: 2 additions & 5 deletions man/aes.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 9 additions & 21 deletions man/aes_.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 69 additions & 29 deletions man/tidyeval.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.