#' Construct aesthetic mappings
#'
#' Aesthetic mappings describe how variables in the data are mapped to visual
#' properties (aesthetics) of option.
#'
#' This function also standardises aesthetic names by converting `colour` to `color`.
#'
#' @section Quasiquotation:
#'
#' `ecaes()` is a [quoting function][rlang::quotation]. This means that
#' its inputs are quoted to be evaluated in the context of the
#' data. This makes it easy to work with variables from the data frame
#' because you can name those directly. The flip side is that you have
#' to use [quasiquotation][rlang::quasiquotation] to program with
#' `ecaes()`. See a tidy evaluation tutorial such as the [dplyr
#' programming vignette](http://dplyr.tidyverse.org/articles/programming.html)
#' to learn more about these techniques.
#'
#' @param x,y,... List of name-value pairs in the form `aesthetic = variable`
#' describing which variables in the data should be mapped to which
#' aesthetics used by the option. The expression `variable` is
#' evaluated within the data, so there is no need to refer to
#' the original dataset (i.e., use `ecaes(variable)`
#' instead of `ecaes(df$variable)`). The names for x and y aesthetics
#' are typically omitted because they are so common; all other aesthetics must be named.
#' @seealso [aes()] Construct aesthetic mappings for ggplot.
#' @return A list with class `uneval` and `ecaes`. Components of the list are either
#' quosures or constants.
#' @export
#' @examples
#' \dontrun{
#' ecaes(x = mpg, y = wt)
#' ecaes(mpg, wt)
#'
#' # You can also map aesthetics to functions of variables
#' ecaes(x = mpg ^ 2, y = wt / cyl)
#'
#' # Or to constants
#' ecaes(x = 1, color = "smooth")
#'
#' # Aesthetic names are automatically standardised
#' ecaes(col = x)
#' ecaes(fg = x)
#' ecaes(color = x)
#' ecaes(colour = x)
#' ecaes(shape = y)
#' ecaes(size = z)
#'
#' # Tidy evaluation ----------------------------------------------------
#' # ecaes() automatically quotes all its arguments.
#' scatter_by <- function(data, ...) {
#' echart() %>% ec_add_series(data, type = 'scatter', mapping = ecaes(...))
#' }
#' scatter_by(mtcars, disp, drat)
#'
#' # If your wrapper has a more specific interface with named arguments,
#' # you need "enquote and unquote":
#' scatter_by <- function(data, x, y) {
#' x <- enquo(x)
#' y <- enquo(y)
#'
#' echart() %>%
#' ec_add_series(data, type = 'scatter', mapping = ecaes(!!x, !!y))
#' }
#' scatter_by(mtcars, disp, drat)
#'
#' # Note that users of your wrapper can use their own functions in the
#' # quoted expressions and all will resolve as it should!
#' cut3 <- function(x) cut_number(x, 3)
#' scatter_by(mtcars, cut3(disp), drat)
#' }
ecaes <- function (x, y, ...) {
exprs <- rlang::enquos(x = x, y = y, ..., .ignore_empty = "all")
mapping <- ggplot2:::new_aes(exprs, env = parent.frame())
structure(rename_ecaes(mapping), class = c("uneval", "ecaes"))
}
#' @export
is.ecaes <- function(x) {
inherits(x, "ecaes")
}
#' @export
ecaes_ <- function (x, y, ...) {
mapping <- list(...)
if (!missing(x)) mapping["x"] <- list(x)
if (!missing(y)) mapping["y"] <- list(y)
caller_env <- parent.frame()
as_quosure_aes <- function(x) {
if (ggplot2:::is.formula(x) && length(x) == 2) {
rlang::as_quosure(x)
} else if (is.call(x) || is.name(x) || is.atomic(x)) {
ggplot2:::new_aesthetic(x, caller_env)
} else {
abort("Aesthetic must be a one-sided formula, call, name, or constant.")
}
}
mapping <- lapply(mapping, rlang::as_quosure_aes)
structure(rename_ecaes(mapping), class = c("uneval", "ecaes"))
}
#' @export
ecaes_string <- function (x, y, ...) {
mapping <- list(...)
if (!missing(x)) mapping["x"] <- list(x)
if (!missing(y)) mapping["y"] <- list(y)
caller_env <- parent.frame()
mapping <- lapply(mapping, function(x) {
if (is.character(x)) {
x <- parse_expr(x)
}
ggplot2:::new_aesthetic(x, env = caller_env)
})
structure(rename_ecaes(mapping), class = c("uneval", "ecaes"))
}
standardise_ecaes_names <- function(x) {
# convert UK to US spelling of color
x <- sub("colour", "color", x, fixed = TRUE)
# convert non-standard aesthetics names
ggplot2:::revalue(x, echarter_global$base_to_echarter)
}
# x is a list of aesthetic mappings, as generated by ecaes()
rename_ecaes <- function(x) {
names(x) <- standardise_ecaes_names(names(x))
duplicated_names <- names(x)[duplicated(names(x))]
if (length(duplicated_names) > 0L) {
duplicated_message <- paste0(unique(duplicated_names), collapse = ", ")
warn(glue("Duplicated aesthetics after name standardisation: {duplicated_message}"))
}
x
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.