diff --git a/R/coord-radial.R b/R/coord-radial.R index 1b4da20a23..ba0146954f 100644 --- a/R/coord-radial.R +++ b/R/coord-radial.R @@ -191,7 +191,7 @@ CoordRadial <- ggproto("CoordRadial", Coord, # Validate appropriateness of guides drop_guides <- character(0) for (type in aesthetics) { - drop_guides <- check_polar_guide(drop_guides, guides, type) + drop_guides <- validate_polar_guide(drop_guides, guides, type) } guide_params <- guides$get_params(aesthetics) @@ -603,7 +603,7 @@ theta_grid <- function(theta, element, inner_radius = c(0, 0.4), ) } -check_polar_guide <- function(drop_list, guides, type = "theta") { +validate_polar_guide <- function(drop_list, guides, type = "theta") { guide <- guides$get_guide(type) primary <- gsub("\\.sec$", "", type) if (inherits(guide, "GuideNone") || primary %in% guide$available_aes) { diff --git a/R/facet-.R b/R/facet-.R index b124b54872..0c120beba3 100644 --- a/R/facet-.R +++ b/R/facet-.R @@ -443,7 +443,7 @@ df.grid <- function(a, b) { # facetting variables. as_facets_list <- function(x) { - x <- validate_facets(x) + check_vars(x) if (is_quosures(x)) { x <- quos_auto_name(x) return(list(x)) @@ -487,7 +487,7 @@ as_facets_list <- function(x) { x } -validate_facets <- function(x) { +check_vars <- function(x) { if (is.mapping(x)) { cli::cli_abort("Please use {.fn vars} to supply facet variables.") } @@ -499,7 +499,7 @@ validate_facets <- function(x) { "i" = "Did you use {.code %>%} or {.code |>} instead of {.code +}?" )) } - x + invisible() } # Flatten a list of quosures objects to a quosures object, and compact it diff --git a/R/facet-grid-.R b/R/facet-grid-.R index 784e394885..be11524541 100644 --- a/R/facet-grid-.R +++ b/R/facet-grid-.R @@ -177,7 +177,7 @@ facet_grid <- function(rows = NULL, cols = NULL, scales = "fixed", facets_list <- grid_as_facets_list(rows, cols) # Check for deprecated labellers - labeller <- check_labeller(labeller) + labeller <- fix_labeller(labeller) ggproto(NULL, FacetGrid, shrink = shrink, diff --git a/R/facet-wrap.R b/R/facet-wrap.R index 114b3332d9..6bc72f8af4 100644 --- a/R/facet-wrap.R +++ b/R/facet-wrap.R @@ -174,7 +174,7 @@ facet_wrap <- function(facets, nrow = NULL, ncol = NULL, scales = "fixed", ) # Check for deprecated labellers - labeller <- check_labeller(labeller) + labeller <- fix_labeller(labeller) # Flatten all facets dimensions into a single one facets <- compact_facets(facets) diff --git a/R/fortify.R b/R/fortify.R index da4bcf7892..17d6e37b12 100644 --- a/R/fortify.R +++ b/R/fortify.R @@ -44,34 +44,46 @@ fortify.grouped_df <- function(model, data, ...) { # There are a lot of ways that dim(), colnames(), or as.data.frame() could # do non-sensical things (they are not even guaranteed to work!) hence the # paranoid mode. -.prevalidate_data_frame_like_object <- function(data) { +check_data_frame_like <- function(data) { orig_dims <- dim(data) - if (!vec_is(orig_dims, integer(), size=2)) - cli::cli_abort(paste0("{.code dim(data)} must return ", - "an {.cls integer} of length 2.")) - if (anyNA(orig_dims) || any(orig_dims < 0)) # extra-paranoid mode - cli::cli_abort(paste0("{.code dim(data)} can't have {.code NA}s ", - "or negative values.")) + if (!vec_is(orig_dims, integer(), size = 2)) { + cli::cli_abort( + "{.code dim(data)} must return an {.cls integer} of length 2." + ) + } + if (anyNA(orig_dims) || any(orig_dims < 0)) { # extra-paranoid mode + cli::cli_abort( + "{.code dim(data)} can't have {.code NA}s or negative values." + ) + } orig_colnames <- colnames(data) - if (!vec_is(orig_colnames, character(), size = ncol(data))) - cli::cli_abort(paste0("{.code colnames(data)} must return a ", - "{.cls character} of length {.code ncol(data)}.")) + if (!vec_is(orig_colnames, character(), size = ncol(data))) { + cli::cli_abort( + "{.code colnames(data)} must return a {.cls character} of length {.code ncol(data)}." + ) + } + invisible() } -.postvalidate_data_frame_like_object <- function(df, data) { +check_data_frame_conversion <- function(new, old) { msg0 <- "{.code as.data.frame(data)} must " - if (!is.data.frame(df)) + if (!is.data.frame(new)) { cli::cli_abort(paste0(msg0, "return a {.cls data.frame}.")) - if (!identical(dim(df), dim(data))) + } + if (!identical(dim(new), dim(old))) { cli::cli_abort(paste0(msg0, "preserve dimensions.")) - if (!identical(colnames(df), colnames(data))) + } + if (!identical(colnames(new), colnames(old))) { cli::cli_abort(paste0(msg0, "preserve column names.")) + } + invisible() } validate_as_data_frame <- function(data) { - if (is.data.frame(data)) + if (is.data.frame(data)) { return(data) - .prevalidate_data_frame_like_object(data) + } + check_data_frame_like(data) df <- as.data.frame(data) - .postvalidate_data_frame_like_object(df, data) + check_data_frame_conversion(df, data) df } diff --git a/R/geom-.R b/R/geom-.R index 50bdeb66a6..f8b5027438 100644 --- a/R/geom-.R +++ b/R/geom-.R @@ -170,17 +170,11 @@ Geom <- ggproto("Geom", ) # Check that all output are valid data - nondata_modified <- check_nondata_cols(modified_aes) - if (length(nondata_modified) > 0) { - issues <- paste0("{.code ", nondata_modified, " = ", as_label(modifiers[[nondata_modified]]), "}") - names(issues) <- rep("x", length(issues)) - cli::cli_abort(c( - "Aesthetic modifiers returned invalid values", - "x" = "The following mappings are invalid", - issues, - "i" = "Did you map the modifier in the wrong layer?" - )) - } + check_nondata_cols( + modified_aes, modifiers, + problem = "Aesthetic modifiers returned invalid values.", + hint = "Did you map the modifier in the wrong layer?" + ) modified_aes <- cleanup_mismatched_data(modified_aes, nrow(data), "after_scale") @@ -283,7 +277,7 @@ check_aesthetics <- function(x, n) { )) } -check_linewidth <- function(data, name) { +fix_linewidth <- function(data, name) { if (is.null(data$linewidth) && !is.null(data$size)) { deprecate_soft0("3.4.0", I(paste0("Using the `size` aesthetic with ", name)), I("the `linewidth` aesthetic")) data$linewidth <- data$size diff --git a/R/geom-boxplot.R b/R/geom-boxplot.R index efb6dd14bd..76b09900e1 100644 --- a/R/geom-boxplot.R +++ b/R/geom-boxplot.R @@ -286,7 +286,7 @@ GeomBoxplot <- ggproto("GeomBoxplot", Geom, whisker_gp = NULL, staple_gp = NULL, median_gp = NULL, box_gp = NULL, notch = FALSE, notchwidth = 0.5, staplewidth = 0, varwidth = FALSE, flipped_aes = FALSE) { - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) data <- flip_data(data, flipped_aes) # this may occur when using geom_boxplot(stat = "identity") if (nrow(data) != 1) { diff --git a/R/geom-crossbar.R b/R/geom-crossbar.R index be7ce1f658..7316033de6 100644 --- a/R/geom-crossbar.R +++ b/R/geom-crossbar.R @@ -84,8 +84,7 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, draw_panel = function(self, data, panel_params, coord, lineend = "butt", linejoin = "mitre", fatten = 2.5, width = NULL, flipped_aes = FALSE, middle_gp = NULL, box_gp = NULL) { - - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) data <- flip_data(data, flipped_aes) middle <- transform(data, x = xmin, xend = xmax, yend = y, linewidth = linewidth * fatten, alpha = NA) diff --git a/R/geom-defaults.R b/R/geom-defaults.R index 732f5ddb32..c1bc8a782f 100644 --- a/R/geom-defaults.R +++ b/R/geom-defaults.R @@ -106,7 +106,7 @@ get_geom_defaults <- function(geom, theme = theme_get()) { return(data) } if (is.character(geom)) { - geom <- check_subclass(geom, "Geom") + geom <- validate_subclass(geom, "Geom") } if (is.geom(geom)) { out <- geom$use_defaults(data = NULL, theme = theme) @@ -126,7 +126,7 @@ reset_stat_defaults <- function() reset_defaults("stat") cache_defaults <- new_environment() update_defaults <- function(name, subclass, new, env = parent.frame()) { - obj <- check_subclass(name, subclass, env = env) + obj <- validate_subclass(name, subclass, env = env) index <- snake_class(obj) if (is.null(new)) { # Reset from cache diff --git a/R/geom-errorbar.R b/R/geom-errorbar.R index 7551f0be59..cd87edc652 100644 --- a/R/geom-errorbar.R +++ b/R/geom-errorbar.R @@ -89,7 +89,7 @@ GeomErrorbar <- ggproto("GeomErrorbar", Geom, draw_panel = function(self, data, panel_params, coord, lineend = "butt", width = NULL, flipped_aes = FALSE) { - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) data <- flip_data(data, flipped_aes) x <- vec_interleave(data$xmin, data$xmax, NA, data$x, data$x, NA, data$xmin, data$xmax) y <- vec_interleave(data$ymax, data$ymax, NA, data$ymax, data$ymin, NA, data$ymin, data$ymin) diff --git a/R/geom-hex.R b/R/geom-hex.R index 152227a40b..5add9250c8 100644 --- a/R/geom-hex.R +++ b/R/geom-hex.R @@ -58,7 +58,7 @@ geom_hex <- function(mapping = NULL, data = NULL, GeomHex <- ggproto("GeomHex", Geom, draw_group = function(self, data, panel_params, coord, lineend = "butt", linejoin = "mitre", linemitre = 10) { - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) if (empty(data)) { return(zeroGrob()) } diff --git a/R/geom-path.R b/R/geom-path.R index 72c4f7154e..fe930363a6 100644 --- a/R/geom-path.R +++ b/R/geom-path.R @@ -165,7 +165,7 @@ GeomPath <- ggproto("GeomPath", Geom, draw_panel = function(self, data, panel_params, coord, arrow = NULL, arrow.fill = NULL, lineend = "butt", linejoin = "round", linemitre = 10, na.rm = FALSE) { - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) if (!anyDuplicated(data$group)) { cli::cli_inform(c( "{.fn {snake_class(self)}}: Each group consists of only one observation.", diff --git a/R/geom-polygon.R b/R/geom-polygon.R index a271ef5011..a97d3c2194 100644 --- a/R/geom-polygon.R +++ b/R/geom-polygon.R @@ -109,7 +109,7 @@ geom_polygon <- function(mapping = NULL, data = NULL, GeomPolygon <- ggproto("GeomPolygon", Geom, draw_panel = function(self, data, panel_params, coord, rule = "evenodd", lineend = "butt", linejoin = "round", linemitre = 10) { - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) n <- nrow(data) if (n == 1) return(zeroGrob()) diff --git a/R/geom-rect.R b/R/geom-rect.R index 8473474525..1765a2506a 100644 --- a/R/geom-rect.R +++ b/R/geom-rect.R @@ -69,7 +69,7 @@ GeomRect <- ggproto("GeomRect", Geom, }, draw_panel = function(self, data, panel_params, coord, lineend = "butt", linejoin = "mitre") { - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) if (!coord$is_linear()) { aesthetics <- setdiff( names(data), c("x", "y", "xmin", "xmax", "ymin", "ymax") diff --git a/R/geom-ribbon.R b/R/geom-ribbon.R index a8f6b1be42..ee5a43b20e 100644 --- a/R/geom-ribbon.R +++ b/R/geom-ribbon.R @@ -133,7 +133,7 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, draw_group = function(self, data, panel_params, coord, lineend = "butt", linejoin = "round", linemitre = 10, na.rm = FALSE, flipped_aes = FALSE, outline.type = "both") { - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) data <- flip_data(data, flipped_aes) if (na.rm) data <- data[stats::complete.cases(data[c("x", "ymin", "ymax")]), ] data <- data[order(data$group), ] diff --git a/R/geom-rug.R b/R/geom-rug.R index ffc761b91c..8992f1069d 100644 --- a/R/geom-rug.R +++ b/R/geom-rug.R @@ -90,7 +90,7 @@ GeomRug <- ggproto("GeomRug", Geom, draw_panel = function(self, data, panel_params, coord, lineend = "butt", sides = "bl", outside = FALSE, length = unit(0.03, "npc")) { - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) check_inherits(length, "unit") rugs <- list() data <- coord$transform(data, panel_params) diff --git a/R/geom-segment.R b/R/geom-segment.R index 00d9eff87a..51de135b53 100644 --- a/R/geom-segment.R +++ b/R/geom-segment.R @@ -116,7 +116,7 @@ GeomSegment <- ggproto("GeomSegment", Geom, lineend = "butt", linejoin = "round", na.rm = FALSE) { data$xend <- data$xend %||% data$x data$yend <- data$yend %||% data$y - data <- check_linewidth(data, snake_class(self)) + data <- fix_linewidth(data, snake_class(self)) data <- remove_missing(data, na.rm = na.rm, c("x", "y", "xend", "yend", "linetype", "linewidth"), name = "geom_segment" diff --git a/R/guide-.R b/R/guide-.R index c700329cb3..54cae7c873 100644 --- a/R/guide-.R +++ b/R/guide-.R @@ -19,7 +19,7 @@ NULL new_guide <- function(..., available_aes = "any", super) { pf <- parent.frame() - super <- check_subclass(super, "Guide", env = pf) + super <- validate_subclass(super, "Guide", env = pf) args <- list2(...) @@ -51,7 +51,7 @@ new_guide <- function(..., available_aes = "any", super) { # Validate theme settings if (!is.null(params$theme)) { check_object(params$theme, is.theme, what = "a {.cls theme} object") - validate_theme(params$theme, call = caller_env()) + check_theme(params$theme, call = caller_env()) params$direction <- params$direction %||% params$theme$legend.direction } diff --git a/R/labeller.R b/R/labeller.R index 4ca220c2b4..a9ba883a79 100644 --- a/R/labeller.R +++ b/R/labeller.R @@ -577,21 +577,21 @@ assemble_strips <- function(grobs, theme, horizontal = TRUE, clip) { }) } -# Check for old school labeller -check_labeller <- function(labeller) { +# Repair old school labeller +fix_labeller <- function(labeller) { labeller <- match.fun(labeller) is_deprecated <- all(c("variable", "value") %in% names(formals(labeller))) if (is_deprecated) { + deprecate_warn0( + "2.0.0", what = "facet_(labeller)", + details = + "Modern labellers do not take `variable` and `value` arguments anymore." + ) old_labeller <- labeller labeller <- function(labels) { Map(old_labeller, names(labels), labels) } - # TODO Update to lifecycle after next lifecycle release - cli::cli_warn(c( - "The {.arg labeller} API has been updated. Labellers taking {.arg variable} and {.arg value} arguments are now deprecated.", - "i" = "See labellers documentation." - )) } labeller diff --git a/R/layer.R b/R/layer.R index d2355a46ba..a915763e3c 100644 --- a/R/layer.R +++ b/R/layer.R @@ -101,12 +101,6 @@ layer <- function(geom = NULL, stat = NULL, show.legend = NA, key_glyph = NULL, layer_class = Layer) { call_env <- caller_env() user_env <- caller_env(2) - if (is.null(geom)) - cli::cli_abort("Can't create layer without a geom.", call = call_env) - if (is.null(stat)) - cli::cli_abort("Can't create layer without a stat.", call = call_env) - if (is.null(position)) - cli::cli_abort("Can't create layer without a position.", call = call_env) # Handle show_guide/show.legend if (!is.null(params$show_guide)) { @@ -125,9 +119,9 @@ layer <- function(geom = NULL, stat = NULL, data <- fortify(data) - geom <- check_subclass(geom, "Geom", env = parent.frame(), call = call_env) - stat <- check_subclass(stat, "Stat", env = parent.frame(), call = call_env) - position <- check_subclass(position, "Position", env = parent.frame(), call = call_env) + geom <- validate_subclass(geom, "Geom", env = parent.frame(), call = call_env) + stat <- validate_subclass(stat, "Stat", env = parent.frame(), call = call_env) + position <- validate_subclass(position, "Position", env = parent.frame(), call = call_env) # Special case for na.rm parameter needed by all layers params$na.rm <- params$na.rm %||% FALSE @@ -314,17 +308,11 @@ Layer <- ggproto("Layer", NULL, warn_for_aes_extract_usage(aesthetics, data[setdiff(names(data), "PANEL")]) # Check aesthetic values - nondata_cols <- check_nondata_cols(evaled) - if (length(nondata_cols) > 0) { - issues <- paste0("{.code ", nondata_cols, " = ", as_label(aesthetics[[nondata_cols]]), "}") - names(issues) <- rep("x", length(issues)) - cli::cli_abort(c( - "Aesthetics are not valid data columns.", - "x" = "The following aesthetics are invalid:", - issues, - "i" = "Did you mistype the name of a data column or forget to add {.fn after_stat}?" - )) - } + check_nondata_cols( + evaled, aesthetics, + problem = "Aesthetics are not valid data columns.", + hint = "Did you mistype the name of a data column or forget to add {.fn after_stat}?" + ) n <- nrow(data) aes_n <- list_sizes(evaled) @@ -392,17 +380,11 @@ Layer <- ggproto("Layer", NULL, mask = list(stage = stage_calculated) ) # Check that all columns in aesthetic stats are valid data - nondata_stat_cols <- check_nondata_cols(stat_data) - if (length(nondata_stat_cols) > 0) { - issues <- paste0("{.code ", nondata_stat_cols, " = ", as_label(aesthetics[[nondata_stat_cols]]), "}") - names(issues) <- rep("x", length(issues)) - cli::cli_abort(c( - "Aesthetics must be valid computed stats.", - "x" = "The following aesthetics are invalid:", - issues, - "i" = "Did you map your stat in the wrong layer?" - )) - } + check_nondata_cols( + stat_data, aesthetics, + problem = "Aesthetics must be valid computed stats.", + hint = "Did you map your stat in the wrong layer?" + ) stat_data <- data_frame0(!!!stat_data) @@ -464,24 +446,26 @@ Layer <- ggproto("Layer", NULL, } ) -check_subclass <- function(x, subclass, - argname = to_lower_ascii(subclass), - env = parent.frame(), - call = caller_env()) { +validate_subclass <- function(x, subclass, + argname = to_lower_ascii(subclass), + x_arg = caller_arg(x), + env = parent.frame(), + call = caller_env()) { + if (inherits(x, subclass)) { - x + return(x) } else if (is_scalar_character(x)) { name <- paste0(subclass, camelize(x, first = TRUE)) obj <- find_global(name, env = env) if (is.null(obj) || !inherits(obj, subclass)) { cli::cli_abort("Can't find {argname} called {.val {x}}.", call = call) - } else { - obj } - } else { - stop_input_type(x, as_cli("either a string or a {.cls {subclass}} object")) + return(obj) + } else if (is.null(x)) { + cli::cli_abort("The {.arg {x_arg}} argument cannot be empty.", call = call) } + stop_input_type(x, as_cli("either a string or a {.cls {subclass}} object")) } # helper function to adjust the draw_key slot of a geom diff --git a/R/save.R b/R/save.R index b06c567b2e..5e1ef5983a 100644 --- a/R/save.R +++ b/R/save.R @@ -95,10 +95,10 @@ ggsave <- function(filename, plot = get_last_plot(), dpi = 300, limitsize = TRUE, bg = NULL, create.dir = FALSE, ...) { - filename <- check_path(path, filename, create.dir) + filename <- validate_path(path, filename, create.dir) dpi <- parse_dpi(dpi) - dev <- plot_dev(device, filename, dpi = dpi) + dev <- validate_device(device, filename, dpi = dpi) dim <- plot_dim(c(width, height), scale = scale, units = units, limitsize = limitsize, dpi = dpi) @@ -116,8 +116,8 @@ ggsave <- function(filename, plot = get_last_plot(), invisible(filename) } -check_path <- function(path, filename, create.dir, - call = caller_env()) { +validate_path <- function(path, filename, create.dir, + call = caller_env()) { if (length(filename) > 1 && is.character(filename)) { cli::cli_warn(c( @@ -235,7 +235,7 @@ plot_dim <- function(dim = c(NA, NA), scale = 1, units = "in", dim } -plot_dev <- function(device, filename = NULL, dpi = 300, call = caller_env()) { +validate_device <- function(device, filename = NULL, dpi = 300, call = caller_env()) { force(filename) force(dpi) diff --git a/R/scale-.R b/R/scale-.R index 4bf54328b3..b2f9ef346a 100644 --- a/R/scale-.R +++ b/R/scale-.R @@ -622,11 +622,8 @@ Scale <- ggproto("Scale", NULL, ) check_breaks_labels <- function(breaks, labels, call = NULL) { - if (is.null(breaks)) { - return(TRUE) - } - if (is.null(labels)) { - return(TRUE) + if (is.null(breaks) || is.null(labels)) { + return(invisible()) } bad_labels <- is.atomic(breaks) && is.atomic(labels) && @@ -638,7 +635,7 @@ check_breaks_labels <- function(breaks, labels, call = NULL) { ) } - TRUE + invisible() } default_transform <- function(self, x) { diff --git a/R/scale-colour.R b/R/scale-colour.R index a17d872dbe..592aa288e1 100644 --- a/R/scale-colour.R +++ b/R/scale-colour.R @@ -81,7 +81,6 @@ scale_colour_continuous <- function(..., aesthetics = "colour", guide = "colourbar", na.value = "grey50", type = getOption("ggplot2.continuous.colour")) { - if (!is.null(type)) { scale <- scale_backward_compatibility( ..., guide = guide, na.value = na.value, scale = type, @@ -179,8 +178,7 @@ check_scale_type <- function(scale, name, aesthetic, scale_is_discrete = FALSE, "x" = "The provided scale is {scale_types[2]}." ), call = call) } - - scale + invisible() } # helper function for backwards compatibility through setting defaults @@ -241,8 +239,9 @@ scale_backward_compatibility <- function(..., scale, aesthetic, type) { if (!"..." %in% fn_fmls_names(scale)) { args <- args[intersect(names(args), fn_fmls_names(scale))] } - scale <- check_scale_type( - exec(scale, !!!args), + scale <- exec(scale, !!!args) + check_scale_type( + scale, paste("scale", aesthetic, type, sep = "_"), aesthetic, scale_is_discrete = type == "discrete" diff --git a/R/scales-.R b/R/scales-.R index 769613a2d8..87c5f6f586 100644 --- a/R/scales-.R +++ b/R/scales-.R @@ -154,6 +154,7 @@ ScalesList <- ggproto("ScalesList", NULL, return() } + for (aes in new_aesthetics) { self$add(find_scale(aes, data[[aes]], env)) } diff --git a/R/theme-elements.R b/R/theme-elements.R index 947e4e0af3..5a6b1a43cf 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -698,7 +698,7 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) { # @param el an element # @param elname the name of the element # @param element_tree the element tree to validate against -validate_element <- function(el, elname, element_tree, call = caller_env()) { +check_element <- function(el, elname, element_tree, call = caller_env()) { eldef <- element_tree[[elname]] if (is.null(eldef)) { diff --git a/R/theme.R b/R/theme.R index 2ebd892f62..cb7859dfe2 100644 --- a/R/theme.R +++ b/R/theme.R @@ -208,7 +208,7 @@ #' differently when added to a ggplot object. Also, when setting #' `complete = TRUE` all elements will be set to inherit from blank #' elements. -#' @param validate `TRUE` to run `validate_element()`, `FALSE` to bypass checks. +#' @param validate `TRUE` to run `check_element()`, `FALSE` to bypass checks. #' @export #' @seealso #' [+.gg()] and [%+replace%], @@ -561,12 +561,12 @@ is_theme_validate <- function(x) { isTRUE(validate %||% TRUE) } -validate_theme <- function(theme, tree = get_element_tree(), call = caller_env()) { +check_theme <- function(theme, tree = get_element_tree(), call = caller_env()) { if (!is_theme_validate(theme)) { return() } mapply( - validate_element, theme, names(theme), + check_element, theme, names(theme), MoreArgs = list(element_tree = tree, call = call) ) } @@ -627,7 +627,7 @@ plot_theme <- function(x, default = get_theme()) { theme[missing] <- ggplot_global$theme_default[missing] # Check that all elements have the correct class (element_text, unit, etc) - validate_theme(theme) + check_theme(theme) # Remove elements that are not registered theme[setdiff(names(theme), names(get_element_tree()))] <- NULL diff --git a/R/utilities-help.R b/R/utilities-help.R index 87f5419612..22bddc7dcd 100644 --- a/R/utilities-help.R +++ b/R/utilities-help.R @@ -2,8 +2,8 @@ # Geoms and there's some difference among their aesthetics). rd_aesthetics <- function(type, name, extra_note = NULL) { obj <- switch(type, - geom = check_subclass(name, "Geom", env = globalenv()), - stat = check_subclass(name, "Stat", env = globalenv()) + geom = validate_subclass(name, "Geom", env = globalenv()), + stat = validate_subclass(name, "Stat", env = globalenv()) ) aes <- rd_aesthetics_item(obj) diff --git a/R/utilities.R b/R/utilities.R index 54087eba68..9c47c78510 100644 --- a/R/utilities.R +++ b/R/utilities.R @@ -277,17 +277,29 @@ is.discrete <- function(x) { is.factor(x) || is.character(x) || is.logical(x) } -# This function checks that all columns of a dataframe `x` are data and returns -# the names of any columns that are not. -# We define "data" as atomic types or lists, not functions or otherwise. -# The `inherits(x, "Vector")` check is for checking S4 classes from Bioconductor -# and whether they can be expected to follow behavior typical of vectors. See -# also #3835 -check_nondata_cols <- function(x) { - idx <- (vapply(x, function(x) { - is.null(x) || rlang::is_vector(x) || inherits(x, "Vector") - }, logical(1))) - names(x)[which(!idx)] +check_nondata_cols <- function(data, mapping, problem = NULL, hint = NULL) { + # We define "data" as atomic types or lists, not functions or otherwise. + # The `inherits(x, "Vector")` check is for checking S4 classes from Bioconductor + # and whether they can be expected to follow behaviour typical of vectors. See + # also #3835 + invalid <- which(!vapply( + data, FUN.VALUE = logical(1), + function(x) is.null(x) || rlang::is_vector(x) || inherits(x, "Vector") + )) + invalid <- names(data)[invalid] + + if (length(invalid) < 1) { + return(invisible()) + } + + mapping <- vapply(mapping[invalid], as_label, character(1)) + issues <- paste0("{.code ", invalid, " = ", mapping, "}") + names(issues) <- rep("*", length(issues)) + issues <- c(x = "The following aesthetics are invalid:", issues) + + # Using 'call = NULL' here because `by_layer()` does a good job of indicating + # the origin of the error + cli::cli_abort(c(problem, issues, i = hint), call = NULL) } compact <- function(x) { diff --git a/tests/testthat/_snaps/facet-.md b/tests/testthat/_snaps/facet-.md index 17d76b1f86..154499e38a 100644 --- a/tests/testthat/_snaps/facet-.md +++ b/tests/testthat/_snaps/facet-.md @@ -3,7 +3,7 @@ Code facet_wrap(aes(foo)) Condition - Error in `validate_facets()`: + Error in `check_vars()`: ! Please use `vars()` to supply facet variables. --- @@ -11,7 +11,7 @@ Code facet_grid(aes(foo)) Condition - Error in `validate_facets()`: + Error in `check_vars()`: ! Please use `vars()` to supply facet variables. # facet_grid() fails if passed both a formula and a vars() @@ -73,7 +73,7 @@ Error: ! object 'no_such_variable' not found -# validate_facets() provide meaningful errors +# check_vars() provide meaningful errors Please use `vars()` to supply facet variables. diff --git a/tests/testthat/_snaps/facet-labels.md b/tests/testthat/_snaps/facet-labels.md index 6cdd9c1ad0..525e0dd0b7 100644 --- a/tests/testthat/_snaps/facet-labels.md +++ b/tests/testthat/_snaps/facet-labels.md @@ -16,6 +16,6 @@ # old school labellers still work - The `labeller` API has been updated. Labellers taking `variable` and `value` arguments are now deprecated. - i See labellers documentation. + The `labeller` argument of `facet_()` is deprecated as of ggplot2 2.0.0. + i Modern labellers do not take `variable` and `value` arguments anymore. diff --git a/tests/testthat/_snaps/fortify.md b/tests/testthat/_snaps/fortify.md index 2034f092fb..605829d9d8 100644 --- a/tests/testthat/_snaps/fortify.md +++ b/tests/testthat/_snaps/fortify.md @@ -10,7 +10,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `dim(data)` must return an of length 2. --- @@ -20,7 +20,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `dim(data)` must return an of length 2. --- @@ -30,7 +30,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `colnames(data)` must return a of length `ncol(data)`. --- @@ -50,7 +50,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `dim(data)` must return an of length 2. --- @@ -60,7 +60,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `dim(data)` must return an of length 2. --- @@ -70,7 +70,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `dim(data)` can't have `NA`s or negative values. --- @@ -80,7 +80,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `dim(data)` can't have `NA`s or negative values. --- @@ -100,7 +100,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `colnames(data)` must return a of length `ncol(data)`. --- @@ -110,7 +110,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.prevalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_like()`: ! `colnames(data)` must return a of length `ncol(data)`. --- @@ -130,7 +130,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.postvalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_conversion()`: ! `as.data.frame(data)` must return a . --- @@ -140,7 +140,7 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.postvalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_conversion()`: ! `as.data.frame(data)` must preserve dimensions. --- @@ -150,6 +150,6 @@ Condition Error in `fortify()`: ! `data` must be a , or an object coercible by `fortify()`, or a valid -like object coercible by `as.data.frame()`. - Caused by error in `.postvalidate_data_frame_like_object()`: + Caused by error in `check_data_frame_conversion()`: ! `as.data.frame(data)` must preserve column names. diff --git a/tests/testthat/_snaps/geom-.md b/tests/testthat/_snaps/geom-.md index 0eae2d74ba..b0ca0c7e85 100644 --- a/tests/testthat/_snaps/geom-.md +++ b/tests/testthat/_snaps/geom-.md @@ -2,10 +2,10 @@ Problem while setting up geom aesthetics. i Error occurred in the 1st layer. - Caused by error in `use_defaults()`: - ! Aesthetic modifiers returned invalid values - x The following mappings are invalid - x `colour = after_scale(data)` + Caused by error: + ! Aesthetic modifiers returned invalid values. + x The following aesthetics are invalid: + * `colour = after_scale(data)` i Did you map the modifier in the wrong layer? --- diff --git a/tests/testthat/_snaps/ggsave.md b/tests/testthat/_snaps/ggsave.md index 372d324b95..03440c5eba 100644 --- a/tests/testthat/_snaps/ggsave.md +++ b/tests/testthat/_snaps/ggsave.md @@ -58,7 +58,7 @@ --- Code - plot_dev("xyz") + validate_device("xyz") Condition Error: ! Unknown graphics device "xyz" @@ -66,7 +66,7 @@ --- Code - plot_dev(NULL, "test.xyz") + validate_device(NULL, "test.xyz") Condition Error: ! Unknown graphics device "xyz" diff --git a/tests/testthat/_snaps/layer.md b/tests/testthat/_snaps/layer.md index 70573a3d7c..79b561b17d 100644 --- a/tests/testthat/_snaps/layer.md +++ b/tests/testthat/_snaps/layer.md @@ -1,14 +1,14 @@ # layer() checks its input - Can't create layer without a geom. + The `geom` argument cannot be empty. --- - Can't create layer without a stat. + The `stat` argument cannot be empty. --- - Can't create layer without a position. + The `position` argument cannot be empty. --- @@ -43,20 +43,20 @@ Problem while computing aesthetics. i Error occurred in the 1st layer. - Caused by error in `compute_aesthetics()`: + Caused by error: ! Aesthetics are not valid data columns. x The following aesthetics are invalid: - x `fill = data` + * `fill = data` i Did you mistype the name of a data column or forget to add `after_stat()`? --- Problem while mapping stat to aesthetics. i Error occurred in the 1st layer. - Caused by error in `map_statistic()`: + Caused by error: ! Aesthetics must be valid computed stats. x The following aesthetics are invalid: - x `fill = after_stat(data)` + * `fill = after_stat(data)` i Did you map your stat in the wrong layer? # missing aesthetics trigger informative error @@ -85,22 +85,22 @@ Problem while computing aesthetics. i Error occurred in the 1st layer. - Caused by error in `compute_aesthetics()`: + Caused by error: ! Aesthetics are not valid data columns. x The following aesthetics are invalid: - x `colour = NULL` - x `fill = NULL` + * `colour = density` + * `fill = density` i Did you mistype the name of a data column or forget to add `after_stat()`? # computed stats are in appropriate layer Problem while mapping stat to aesthetics. i Error occurred in the 1st layer. - Caused by error in `map_statistic()`: + Caused by error: ! Aesthetics must be valid computed stats. x The following aesthetics are invalid: - x `colour = NULL` - x `fill = NULL` + * `colour = after_stat(density)` + * `fill = after_stat(density)` i Did you map your stat in the wrong layer? # layer reports the error with correct index etc diff --git a/tests/testthat/test-facet-.R b/tests/testthat/test-facet-.R index 11e86247ca..a24a5e4ca5 100644 --- a/tests/testthat/test-facet-.R +++ b/tests/testthat/test-facet-.R @@ -469,9 +469,9 @@ test_that("eval_facet() is tolerant for missing columns (#2963)", { ) }) -test_that("validate_facets() provide meaningful errors", { - expect_snapshot_error(validate_facets(aes(var))) - expect_snapshot_error(validate_facets(ggplot())) +test_that("check_vars() provide meaningful errors", { + expect_snapshot_error(check_vars(aes(var))) + expect_snapshot_error(check_vars(ggplot())) }) test_that("check_layout() throws meaningful errors", { diff --git a/tests/testthat/test-ggsave.R b/tests/testthat/test-ggsave.R index 4180eadc98..158dae2594 100644 --- a/tests/testthat/test-ggsave.R +++ b/tests/testthat/test-ggsave.R @@ -125,19 +125,19 @@ test_that("scale multiplies height & width", { # plot_dev --------------------------------------------------------------------- test_that("unknown device triggers error", { - expect_snapshot_error(plot_dev(1)) - expect_snapshot(plot_dev("xyz"), error = TRUE) - expect_snapshot(plot_dev(NULL, "test.xyz"), error = TRUE) + expect_snapshot_error(validate_device(1)) + expect_snapshot(validate_device("xyz"), error = TRUE) + expect_snapshot(validate_device(NULL, "test.xyz"), error = TRUE) }) test_that("text converted to function", { - expect_identical(body(plot_dev("png"))[[1]], quote(png_dev)) - expect_identical(body(plot_dev("pdf"))[[1]], quote(grDevices::pdf)) + expect_identical(body(validate_device("png"))[[1]], quote(png_dev)) + expect_identical(body(validate_device("pdf"))[[1]], quote(grDevices::pdf)) }) test_that("if device is NULL, guess from extension", { - expect_identical(body(plot_dev(NULL, "test.png"))[[1]], quote(png_dev)) + expect_identical(body(validate_device(NULL, "test.png"))[[1]], quote(png_dev)) }) # parse_dpi --------------------------------------------------------------- diff --git a/tests/testthat/test-layer.R b/tests/testthat/test-layer.R index 225cedd947..59970c7db5 100644 --- a/tests/testthat/test-layer.R +++ b/tests/testthat/test-layer.R @@ -8,8 +8,8 @@ test_that("layer() checks its input", { expect_snapshot_error(layer("point", "identity", mapping = 1:4, position = "identity")) expect_snapshot_error(layer("point", "identity", mapping = ggplot(), position = "identity")) - expect_snapshot_error(check_subclass("test", "geom")) - expect_snapshot_error(check_subclass(environment(), "geom")) + expect_snapshot_error(validate_subclass("test", "geom")) + expect_snapshot_error(validate_subclass(environment(), "geom")) }) test_that("aesthetics go in aes_params", { diff --git a/tests/testthat/test-scales-breaks-labels.R b/tests/testthat/test-scales-breaks-labels.R index 42e3d67bb3..e0b8474a40 100644 --- a/tests/testthat/test-scales-breaks-labels.R +++ b/tests/testthat/test-scales-breaks-labels.R @@ -12,8 +12,8 @@ test_that("labels match breaks", { }) test_that("labels don't have to match null breaks", { - expect_true(check_breaks_labels(breaks = 1:3, labels = NULL)) - expect_true(check_breaks_labels(breaks = NULL, labels = 1:2)) + expect_silent(check_breaks_labels(breaks = 1:3, labels = NULL)) + expect_silent(check_breaks_labels(breaks = NULL, labels = 1:2)) }) test_that("labels don't have extra spaces", { diff --git a/tests/testthat/test-theme.R b/tests/testthat/test-theme.R index ef358b10b6..81e08f18f8 100644 --- a/tests/testthat/test-theme.R +++ b/tests/testthat/test-theme.R @@ -250,7 +250,7 @@ test_that("complete and non-complete themes interact correctly with ggplot objec expect_equal(p$plot$theme$text$face, "italic") }) -test_that("theme(validate=FALSE) means do not validate_element", { +test_that("theme(validate=FALSE) means do not check_element", { p <- ggplot(data.frame(x = 1:3), aes(x, x)) + geom_point() bw <- p + theme_bw() red.text <- theme(text = element_text(colour = "red")) @@ -516,9 +516,9 @@ test_that("Theme elements are checked during build", { test_that("Theme validation behaves as expected", { tree <- get_element_tree() - expect_silent(validate_element(1, "aspect.ratio", tree)) - expect_silent(validate_element(1L, "aspect.ratio", tree)) - expect_snapshot_error(validate_element("A", "aspect.ratio", tree)) + expect_silent(check_element(1, "aspect.ratio", tree)) + expect_silent(check_element(1L, "aspect.ratio", tree)) + expect_snapshot_error(check_element("A", "aspect.ratio", tree)) }) test_that("Element subclasses are inherited", {