1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
find_scale <- function(aes, x, env = parent.frame()) {
# Inf is ambiguous; it can be used either with continuous scales or with
# discrete scales, so just skip in the hope that we will have a better guess
# with the other layers
if (is.null(x) || (is_atomic(x) && all(is.infinite(x)))) {
return(NULL)
}
type <- scale_type(x)
candidates <- paste("scale", aes, type, sep = "_")
for (scale in candidates) {
scale_f <- find_global(scale, env, mode = "function")
if (!is.null(scale_f))
return(scale_f())
}
# Failure to find a scale is not an error because some "aesthetics" don't
# need scales (e.g. group), and it allows others to extend ggplot2 with
# their own aesthetics
return(NULL)
}
# Look for object first in parent environment and if not found, then in
# ggplot2 namespace environment. This makes it possible to override default
# scales by setting them in the parent environment.
find_global <- function(name, env, mode = "any") {
if (exists(name, envir = env, mode = mode)) {
return(get(name, envir = env, mode = mode))
}
nsenv <- asNamespace("ggplot2")
if (exists(name, envir = nsenv, mode = mode)) {
return(get(name, envir = nsenv, mode = mode))
}
NULL
}
#' Determine default scale type
#'
#' You will need to define a method for this method if you want to extend
#' ggplot2 to handle new types of data. If you simply want to pass the vector
#' through as an additional aesthetic, return `"identity"`.
#'
#' @param x A vector
#' @return A character vector of scale types. These will be tried in turn
#' to find a default scale. For example, if `scale_type()` returns
#' `c("foo", "bar")` and the vector is used with the colour aesthetic,
#' ggplot2 will first look for `scale_colour_foo` then
#' `scale_colour_bar`.
#' @export
#' @keywords internal
#' @examples
#' scale_type(1:5)
#' scale_type("test")
#' scale_type(Sys.Date())
scale_type <- function(x) UseMethod("scale_type")
#' @export
scale_type.default <- function(x) {
cli::cli_inform("Don't know how to automatically pick scale for object of type {.cls {class(x)}}. Defaulting to continuous.")
"continuous"
}
#' @export
scale_type.list <- function(x) "identity"
#' @export
scale_type.AsIs <- function(x) "identity"
#' @export
scale_type.logical <- function(x) "discrete"
#' @export
scale_type.character <- function(x) "discrete"
#' @export
scale_type.ordered <- function(x) c("ordinal", "discrete")
#' @export
scale_type.factor <- function(x) "discrete"
#' @export
scale_type.POSIXt <- function(x) c("datetime", "continuous")
#' @export
scale_type.Date <- function(x) c("date", "continuous")
#' @export
scale_type.numeric <- function(x) "continuous"
#' @export
scale_type.hms <- function(x) "time"
|