diff --git a/DESCRIPTION b/DESCRIPTION index 4d7d98248d..dc40aa95f6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,6 +43,7 @@ Imports: scales (>= 1.2.0), stats, tibble, + vctrs (>= 0.4.1), withr (>= 2.0.0) Suggests: covr, @@ -79,7 +80,7 @@ Config/testthat/edition: 3 Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.0 +RoxygenNote: 7.2.0.9000 Collate: 'ggproto.r' 'ggplot-global.R' diff --git a/NAMESPACE b/NAMESPACE index 15d7b9c658..5cedb05e5e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,23 +4,20 @@ S3method("$",ggproto) S3method("$",ggproto_parent) S3method("$<-",uneval) S3method("+",gg) -S3method("[",mapped_discrete) S3method("[",uneval) -S3method("[<-",mapped_discrete) S3method("[<-",uneval) S3method("[[",ggproto) S3method("[[<-",uneval) S3method(.DollarNames,ggproto) -S3method(as.data.frame,mapped_discrete) S3method(as.list,ggproto) S3method(autolayer,default) S3method(autoplot,default) -S3method(c,mapped_discrete) S3method(drawDetails,zeroGrob) S3method(element_grob,element_blank) S3method(element_grob,element_line) S3method(element_grob,element_rect) S3method(element_grob,element_text) +S3method(format,ggplot2_mapped_discrete) S3method(format,ggproto) S3method(format,ggproto_method) S3method(fortify,"NULL") @@ -142,6 +139,30 @@ S3method(scale_type,sfc) S3method(single_value,default) S3method(single_value,factor) S3method(summary,ggplot) +S3method(vec_arith,ggplot2_mapped_discrete) +S3method(vec_arith.ggplot2_mapped_discrete,MISSING) +S3method(vec_arith.ggplot2_mapped_discrete,default) +S3method(vec_arith.ggplot2_mapped_discrete,ggplot2_mapped_discrete) +S3method(vec_arith.ggplot2_mapped_discrete,numeric) +S3method(vec_arith.numeric,ggplot2_mapped_discrete) +S3method(vec_cast,character.ggplot2_mapped_discrete) +S3method(vec_cast,double.ggplot2_mapped_discrete) +S3method(vec_cast,factor.ggplot2_mapped_discrete) +S3method(vec_cast,ggplot2_mapped_discrete.double) +S3method(vec_cast,ggplot2_mapped_discrete.factor) +S3method(vec_cast,ggplot2_mapped_discrete.ggplot2_mapped_discrete) +S3method(vec_cast,ggplot2_mapped_discrete.integer) +S3method(vec_cast,integer.ggplot2_mapped_discrete) +S3method(vec_math,ggplot2_mapped_discrete) +S3method(vec_ptype2,character.ggplot2_mapped_discrete) +S3method(vec_ptype2,double.ggplot2_mapped_discrete) +S3method(vec_ptype2,factor.ggplot2_mapped_discrete) +S3method(vec_ptype2,ggplot2_mapped_discrete.character) +S3method(vec_ptype2,ggplot2_mapped_discrete.double) +S3method(vec_ptype2,ggplot2_mapped_discrete.factor) +S3method(vec_ptype2,ggplot2_mapped_discrete.ggplot2_mapped_discrete) +S3method(vec_ptype2,ggplot2_mapped_discrete.integer) +S3method(vec_ptype2,integer.ggplot2_mapped_discrete) S3method(widthDetails,titleGrob) S3method(widthDetails,zeroGrob) export("%+%") @@ -668,6 +689,7 @@ export(update_geom_defaults) export(update_labels) export(update_stat_defaults) export(vars) +export(vec_arith.ggplot2_mapped_discrete) export(waiver) export(wrap_dims) export(xlab) @@ -679,6 +701,7 @@ import(grid) import(gtable) import(rlang) import(scales) +import(vctrs) importFrom(glue,glue) importFrom(glue,glue_collapse) importFrom(lifecycle,deprecated) diff --git a/R/aes.r b/R/aes.r index f01a1ea478..01e4e4d7b0 100644 --- a/R/aes.r +++ b/R/aes.r @@ -179,7 +179,7 @@ rename_aes <- function(x) { names(x) <- standardise_aes_names(names(x)) duplicated_names <- names(x)[duplicated(names(x))] if (length(duplicated_names) > 0L) { - cli::cli_warn("Duplicated aesthetics after name standardisation: {.field {unique(duplicated_names)}}") + cli::cli_warn("Duplicated aesthetics after name standardisation: {.field {unique0(duplicated_names)}}") } x } diff --git a/R/annotation-custom.r b/R/annotation-custom.r index 3d3eeefd17..cdaf7a1d13 100644 --- a/R/annotation-custom.r +++ b/R/annotation-custom.r @@ -73,7 +73,11 @@ GeomCustomAnn <- ggproto("GeomCustomAnn", Geom, if (!inherits(coord, "CoordCartesian")) { cli::cli_abort("{.fn annotation_custom} only works with {.fn coord_cartesian}") } - corners <- new_data_frame(list(x = c(xmin, xmax), y = c(ymin, ymax)), n = 2) + corners <- data_frame0( + x = c(xmin, xmax), + y = c(ymin, ymax), + .size = 2 + ) data <- coord$transform(corners, panel_params) x_rng <- range(data$x, na.rm = TRUE) diff --git a/R/annotation-logticks.r b/R/annotation-logticks.r index 8fd1bac112..8d42734748 100644 --- a/R/annotation-logticks.r +++ b/R/annotation-logticks.r @@ -213,7 +213,7 @@ GeomLogticks <- ggproto("GeomLogticks", Geom, } } - gTree(children = do.call("gList", ticks)) + gTree(children = inject(gList(!!!ticks))) }, default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = 1) @@ -254,7 +254,12 @@ calc_logticks <- function(base = 10, ticks_per_base = base - 1, longtick_after_base <- floor(ticks_per_base/2) tickend[ cycleIdx == longtick_after_base ] <- midend - tickdf <- new_data_frame(list(value = ticks, start = start, end = tickend), n = length(ticks)) + tickdf <- data_frame0( + value = ticks, + start = start, + end = tickend, + .size = length(ticks) + ) return(tickdf) } diff --git a/R/annotation-map.r b/R/annotation-map.r index d6d69d6512..1f0b314383 100644 --- a/R/annotation-map.r +++ b/R/annotation-map.r @@ -93,7 +93,7 @@ GeomAnnotationMap <- ggproto("GeomAnnotationMap", GeomMap, # must be sequential integers coords <- coord_munch(coord, map, panel_params) coords$group <- coords$group %||% coords$id - grob_id <- match(coords$group, unique(coords$group)) + grob_id <- match(coords$group, unique0(coords$group)) polygonGrob(coords$x, coords$y, default.units = "native", id = grob_id, diff --git a/R/annotation-raster.r b/R/annotation-raster.r index f389718d7a..b6fd119675 100644 --- a/R/annotation-raster.r +++ b/R/annotation-raster.r @@ -76,7 +76,11 @@ GeomRasterAnn <- ggproto("GeomRasterAnn", Geom, if (!inherits(coord, "CoordCartesian")) { cli::cli_abort("{.fn annotation_raster} only works with {.fn coord_cartesian}") } - corners <- new_data_frame(list(x = c(xmin, xmax), y = c(ymin, ymax)), n = 2) + corners <- data_frame0( + x = c(xmin, xmax), + y = c(ymin, ymax), + .size = 2 + ) data <- coord$transform(corners, panel_params) x_rng <- range(data$x, na.rm = TRUE) diff --git a/R/annotation.r b/R/annotation.r index 6223540d4a..32f34f1d28 100644 --- a/R/annotation.r +++ b/R/annotation.r @@ -57,7 +57,7 @@ annotate <- function(geom, x = NULL, y = NULL, xmin = NULL, xmax = NULL, # Check that all aesthetic have compatible lengths lengths <- vapply(aesthetics, length, integer(1)) - n <- unique(lengths) + n <- unique0(lengths) # if there is more than one unique length, ignore constants if (length(n) > 1L) { @@ -71,7 +71,7 @@ annotate <- function(geom, x = NULL, y = NULL, xmin = NULL, xmax = NULL, cli::cli_abort("Unequal parameter lengths: {details}") } - data <- new_data_frame(position, n = n) + data <- data_frame0(!!!position, .size = n) layer( geom = geom, params = list( diff --git a/R/axis-secondary.R b/R/axis-secondary.R index 297290d54b..8d79efd1b5 100644 --- a/R/axis-secondary.R +++ b/R/axis-secondary.R @@ -193,7 +193,7 @@ AxisSecondary <- ggproto("AxisSecondary", NULL, full_range <- self$transform_range(old_range) # Test for monotonicity - if (length(unique(sign(diff(full_range)))) != 1) + if (length(unique0(sign(diff(full_range)))) != 1) cli::cli_abort("Transformation for secondary axes must be monotonic") }, diff --git a/R/bench.r b/R/bench.r index 926d68d48b..daa1359dd1 100644 --- a/R/bench.r +++ b/R/bench.r @@ -26,7 +26,7 @@ benchplot <- function(x) { times <- rbind(construct, build, render, draw)[, 1:3] times <- rbind(times, colSums(times)) - cbind( + vec_cbind( step = c("construct", "build", "render", "draw", "TOTAL"), mat_2_df(times) ) diff --git a/R/bin.R b/R/bin.R index 9f9cbb8720..955e784d10 100644 --- a/R/bin.R +++ b/R/bin.R @@ -183,7 +183,7 @@ bin_out <- function(count = integer(0), x = numeric(0), width = numeric(0), xmin = x - width / 2, xmax = x + width / 2) { density <- count / width / sum(abs(count)) - new_data_frame(list( + data_frame0( count = count, x = x, xmin = xmin, @@ -191,6 +191,7 @@ bin_out <- function(count = integer(0), x = numeric(0), width = numeric(0), width = width, density = density, ncount = count / max(abs(count)), - ndensity = density / max(abs(density)) - ), n = length(count)) + ndensity = density / max(abs(density)), + .size = length(count) + ) } diff --git a/R/compat-plyr.R b/R/compat-plyr.R index 6c28f8f07c..8ce80921f7 100644 --- a/R/compat-plyr.R +++ b/R/compat-plyr.R @@ -62,7 +62,7 @@ id_var <- function(x, drop = FALSE) { id <- as.integer(x) n <- length(levels(x)) } else { - levels <- sort(unique(x), na.last = TRUE) + levels <- sort(unique0(x), na.last = TRUE) id <- match(x, levels) n <- max(id) } @@ -107,12 +107,12 @@ id <- function(.variables, drop = FALSE) { ndistinct <- vapply(ids, attr, "n", FUN.VALUE = numeric(1), USE.NAMES = FALSE) n <- prod(ndistinct) if (n > 2^31) { - char_id <- do.call("paste", c(ids, sep = "\r")) - res <- match(char_id, unique(char_id)) + char_id <- inject(paste(!!!ids, sep = "\r")) + res <- match(char_id, unique0(char_id)) } else { combs <- c(1, cumprod(ndistinct[-p])) - mat <- do.call("cbind", ids) + mat <- inject(cbind(!!!ids)) res <- c((mat - 1L) %*% combs + 1L) } if (drop) { @@ -153,13 +153,13 @@ count <- function(df, vars = NULL, wt_var = NULL) { wt <- .subset2(df, wt_var) freq <- vapply(split(wt, id), sum, numeric(1)) } - new_data_frame(c(as.list(labels), list(n = freq))) + data_frame0(labels, n = freq) } # Adapted from plyr::join.keys # Create a shared unique id across two data frames such that common variable # combinations in the two data frames gets the same id join_keys <- function(x, y, by) { - joint <- rbind_dfs(list(x[by], y[by])) + joint <- vec_rbind(x[by], y[by]) keys <- id(joint, drop = TRUE) n_x <- nrow(x) n_y <- nrow(y) @@ -251,103 +251,6 @@ round_any <- function(x, accuracy, f = round) { } f(x/accuracy) * accuracy } -#' Bind data frames together by common column names -#' -#' This function is akin to `plyr::rbind.fill`, `dplyr::bind_rows`, and -#' `data.table::rbindlist`. It takes data frames in a list and stacks them on -#' top of each other, filling out values with `NA` if the column is missing from -#' a data.frame -#' -#' @param dfs A list of data frames -#' -#' @return A data.frame with the union of all columns from the data frames given -#' in `dfs` -#' -#' @keywords internal -#' @noRd -#' -rbind_dfs <- function(dfs) { - out <- list() - columns <- unique(unlist(lapply(dfs, names))) - nrows <- vapply(dfs, .row_names_info, integer(1), type = 2L) - total <- sum(nrows) - if (length(columns) == 0) return(new_data_frame(list(), total)) - allocated <- rep(FALSE, length(columns)) - names(allocated) <- columns - col_levels <- list() - ord_levels <- list() - for (df in dfs) { - new_columns <- intersect(names(df), columns[!allocated]) - for (col in new_columns) { - if (is.factor(df[[col]])) { - all_ordered <- all(vapply(dfs, function(df) { - val <- .subset2(df, col) - is.null(val) || is.ordered(val) - }, logical(1))) - all_factors <- all(vapply(dfs, function(df) { - val <- .subset2(df, col) - is.null(val) || is.factor(val) - }, logical(1))) - if (all_ordered) { - ord_levels[[col]] <- unique(unlist(lapply(dfs, function(df) levels(.subset2(df, col))))) - } else if (all_factors) { - col_levels[[col]] <- unique(unlist(lapply(dfs, function(df) levels(.subset2(df, col))))) - } - out[[col]] <- rep(NA_character_, total) - } else { - out[[col]] <- rep(.subset2(df, col)[1][NA], total) - } - } - allocated[new_columns] <- TRUE - if (all(allocated)) break - } - is_date <- lapply(out, inherits, 'Date') - is_time <- lapply(out, inherits, 'POSIXct') - pos <- c(cumsum(nrows) - nrows + 1) - for (i in seq_along(dfs)) { - df <- dfs[[i]] - rng <- seq(pos[i], length.out = nrows[i]) - for (col in names(df)) { - date_col <- inherits(df[[col]], 'Date') - time_col <- inherits(df[[col]], 'POSIXct') - if (is_date[[col]] && !date_col) { - out[[col]][rng] <- as.Date( - unclass(df[[col]]), - origin = ggplot_global$date_origin - ) - } else if (is_time[[col]] && !time_col) { - out[[col]][rng] <- as.POSIXct( - unclass(df[[col]]), - origin = ggplot_global$time_origin - ) - } else if (date_col || time_col || inherits(df[[col]], 'factor')) { - out[[col]][rng] <- as.character(df[[col]]) - } else { - out[[col]][rng] <- df[[col]] - } - } - } - for (col in names(ord_levels)) { - out[[col]] <- ordered(out[[col]], levels = ord_levels[[col]]) - } - for (col in names(col_levels)) { - out[[col]] <- factor(out[[col]], levels = col_levels[[col]]) - } - attributes(out) <- list( - class = "data.frame", - names = names(out), - row.names = .set_row_names(total) - ) - out -} - -# Info needed for rbind_dfs date/time handling -on_load({ - date <- Sys.Date() - ggplot_global$date_origin <- date - unclass(date) - time <- Sys.time() - ggplot_global$time_origin <- time - unclass(time) -}) #' Apply function to unique subsets of a data.frame #' @@ -370,17 +273,18 @@ on_load({ #' @noRd dapply <- function(df, by, fun, ..., drop = TRUE) { grouping_cols <- .subset(df, by) - fallback_order <- unique(c(by, names(df))) + fallback_order <- unique0(c(by, names(df))) apply_fun <- function(x) { res <- fun(x, ...) if (is.null(res)) return(res) - if (length(res) == 0) return(new_data_frame()) + if (length(res) == 0) return(data_frame0()) vars <- lapply(setNames(by, by), function(col) .subset2(x, col)[1]) if (is.matrix(res)) res <- split_matrix(res) if (is.null(names(res))) names(res) <- paste0("V", seq_along(res)) - if (all(by %in% names(res))) return(new_data_frame(unclass(res))) + if (all(by %in% names(res))) return(data_frame0(!!!unclass(res))) res <- modify_list(unclass(vars), unclass(res)) - new_data_frame(res[intersect(c(fallback_order, names(res)), names(res))]) + res <- res[intersect(c(fallback_order, names(res)), names(res))] + data_frame0(!!!res) } # Shortcut when only one group @@ -390,10 +294,11 @@ dapply <- function(df, by, fun, ..., drop = TRUE) { ids <- id(grouping_cols, drop = drop) group_rows <- split_with_index(seq_len(nrow(df)), ids) - rbind_dfs(lapply(seq_along(group_rows), function(i) { + result <- lapply(seq_along(group_rows), function(i) { cur_data <- df_rows(df, group_rows[[i]]) apply_fun(cur_data) - })) + }) + vec_rbind(!!!result) } single_value <- function(x, ...) { diff --git a/R/coord-map.r b/R/coord-map.r index d8f4624186..261a74f60e 100644 --- a/R/coord-map.r +++ b/R/coord-map.r @@ -288,10 +288,11 @@ CoordMap <- ggproto("CoordMap", Coord, )) } - x_intercept <- with(panel_params, new_data_frame(list( + x_intercept <- with(panel_params, data_frame0( x = x.major, - y = y.range[1] - ), n = length(x.major))) + y = y.range[1], + .size = length(x.major) + )) pos <- self$transform(x_intercept, panel_params) axes <- list( @@ -312,10 +313,11 @@ CoordMap <- ggproto("CoordMap", Coord, )) } - x_intercept <- with(panel_params, new_data_frame(list( + x_intercept <- with(panel_params, data_frame0( x = x.range[1], - y = y.major - ), n = length(y.major))) + y = y.major, + .size = length(y.major) + )) pos <- self$transform(x_intercept, panel_params) axes <- list( diff --git a/R/coord-munch.r b/R/coord-munch.r index 2feb4e4b18..5ba5951da0 100644 --- a/R/coord-munch.r +++ b/R/coord-munch.r @@ -63,7 +63,7 @@ munch_data <- function(data, dist = NULL, segment_length = 0.01) { id <- c(rep(seq_len(nrow(data) - 1), extra), nrow(data)) aes_df <- data[id, setdiff(names(data), c("x", "y")), drop = FALSE] - new_data_frame(c(list(x = x, y = y), unclass(aes_df))) + data_frame0(x = x, y = y, aes_df) } # Interpolate. @@ -174,9 +174,15 @@ find_line_formula <- function(x, y) { slope <- diff(y) / diff(x) yintercept <- y[-1] - (slope * x[-1]) xintercept <- x[-1] - (y[-1] / slope) - new_data_frame(list(x1 = x[-length(x)], y1 = y[-length(y)], - x2 = x[-1], y2 = y[-1], - slope = slope, yintercept = yintercept, xintercept = xintercept)) + data_frame0( + x1 = x[-length(x)], + y1 = y[-length(y)], + x2 = x[-1], + y2 = y[-1], + slope = slope, + yintercept = yintercept, + xintercept = xintercept + ) } # Spiral arc length diff --git a/R/coord-polar.r b/R/coord-polar.r index 176e515fe6..bb8e9a16a0 100644 --- a/R/coord-polar.r +++ b/R/coord-polar.r @@ -212,23 +212,23 @@ CoordPolar <- ggproto("CoordPolar", Coord, element_render(theme, "panel.background"), if (length(theta) > 0) element_render( theme, majortheta, name = "angle", - x = c(rbind(0, 0.45 * sin(theta))) + 0.5, - y = c(rbind(0, 0.45 * cos(theta))) + 0.5, + x = vec_interleave(0, 0.45 * sin(theta)) + 0.5, + y = vec_interleave(0, 0.45 * cos(theta)) + 0.5, id.lengths = rep(2, length(theta)), default.units = "native" ), if (length(thetamin) > 0) element_render( theme, minortheta, name = "angle", - x = c(rbind(0, 0.45 * sin(thetamin))) + 0.5, - y = c(rbind(0, 0.45 * cos(thetamin))) + 0.5, + x = vec_interleave(0, 0.45 * sin(thetamin)) + 0.5, + y = vec_interleave(0, 0.45 * cos(thetamin)) + 0.5, id.lengths = rep(2, length(thetamin)), default.units = "native" ), element_render( theme, majorr, name = "radius", - x = rep(rfine, each = length(thetafine)) * sin(thetafine) + 0.5, - y = rep(rfine, each = length(thetafine)) * cos(thetafine) + 0.5, + x = rep(rfine, each = length(thetafine)) * rep(sin(thetafine), length(rfine)) + 0.5, + y = rep(rfine, each = length(thetafine)) * rep(cos(thetafine), length(rfine)) + 0.5, id.lengths = rep(length(thetafine), length(rfine)), default.units = "native" ) diff --git a/R/coord-sf.R b/R/coord-sf.R index e3bd037778..a2c2a49121 100644 --- a/R/coord-sf.R +++ b/R/coord-sf.R @@ -313,7 +313,7 @@ CoordSf <- ggproto("CoordSf", CoordCartesian, lapply(sf::st_geometry(panel_params$graticule), sf::st_as_grob, gp = line_gp) ) } - ggname("grill", do.call("grobTree", grobs)) + ggname("grill", inject(grobTree(!!!grobs))) }, render_axis_h = function(self, panel_params, theme) { @@ -339,8 +339,8 @@ CoordSf <- ggproto("CoordSf", CoordCartesian, id2 <- c(id2, which(graticule$type == "N" & graticule$y_end > 0.999)) } - ticks1 <- graticule[unique(id1), ] - ticks2 <- graticule[unique(id2), ] + ticks1 <- graticule[unique0(id1), ] + ticks2 <- graticule[unique0(id2), ] tick_positions <- c(ticks1$x_start, ticks2$x_end) tick_labels <- c(ticks1$degree_label, ticks2$degree_label) @@ -375,8 +375,8 @@ CoordSf <- ggproto("CoordSf", CoordCartesian, id2 <- c(id2, which(graticule$type == "N" & graticule$y_end < 0.001)) } - ticks1 <- graticule[unique(id1), ] - ticks2 <- graticule[unique(id2), ] + ticks1 <- graticule[unique0(id1), ] + ticks2 <- graticule[unique0(id2), ] tick_positions <- c(ticks1$x_start, ticks2$x_end) tick_labels <- c(ticks1$degree_label, ticks2$degree_label) @@ -417,8 +417,8 @@ CoordSf <- ggproto("CoordSf", CoordCartesian, id2 <- c(id2, which(graticule$type == "N" & graticule$x_start > 0.999)) } - ticks1 <- graticule[unique(id1), ] - ticks2 <- graticule[unique(id2), ] + ticks1 <- graticule[unique0(id1), ] + ticks2 <- graticule[unique0(id2), ] tick_positions <- c(ticks1$y_end, ticks2$y_start) tick_labels <- c(ticks1$degree_label, ticks2$degree_label) @@ -453,8 +453,8 @@ CoordSf <- ggproto("CoordSf", CoordCartesian, id2 <- c(id2, which(graticule$type == "N" & graticule$x_start < 0.001)) } - ticks1 <- graticule[unique(id1), ] - ticks2 <- graticule[unique(id2), ] + ticks1 <- graticule[unique0(id1), ] + ticks2 <- graticule[unique0(id2), ] tick_positions <- c(ticks1$y_end, ticks2$y_start) tick_labels <- c(ticks1$degree_label, ticks2$degree_label) diff --git a/R/facet-.r b/R/facet-.r index daf656e775..27a1e1a9cb 100644 --- a/R/facet-.r +++ b/R/facet-.r @@ -119,10 +119,10 @@ Facet <- ggproto("Facet", NULL, } }, draw_back = function(data, layout, x_scales, y_scales, theme, params) { - rep(list(zeroGrob()), length(unique(layout$PANEL))) + rep(list(zeroGrob()), length(unique0(layout$PANEL))) }, draw_front = function(data, layout, x_scales, y_scales, theme, params) { - rep(list(zeroGrob()), length(unique(layout$PANEL))) + rep(list(zeroGrob()), length(unique0(layout$PANEL))) }, draw_panels = function(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) { cli::cli_abort("Not implemented") @@ -155,7 +155,7 @@ Facet <- ggproto("Facet", NULL, panels }, setup_params = function(data, params) { - params$.possible_columns <- unique(unlist(lapply(data, names))) + params$.possible_columns <- unique0(unlist(lapply(data, names))) params }, setup_data = function(data, params) { @@ -257,10 +257,10 @@ df.grid <- function(a, b) { i_a = seq_len(nrow(a)), i_b = seq_len(nrow(b)) ) - unrowname(cbind( - a[indexes$i_a, , drop = FALSE], - b[indexes$i_b, , drop = FALSE] - )) + vec_cbind( + unrowname(a[indexes$i_a, , drop = FALSE]), + unrowname(b[indexes$i_b, , drop = FALSE]) + ) } # A facets spec is a list of facets. A grid facetting needs two facets @@ -432,7 +432,7 @@ is_facets <- function(x) { # but that seems like a reasonable tradeoff. eval_facets <- function(facets, data, possible_columns = NULL) { vars <- compact(lapply(facets, eval_facet, data, possible_columns = possible_columns)) - new_data_frame(tibble::as_tibble(vars)) + data_frame0(tibble::as_tibble(vars)) } eval_facet <- function(facet, data, possible_columns = NULL) { # Treat the case when `facet` is a quosure of a symbol specifically @@ -468,7 +468,14 @@ eval_facet <- function(facet, data, possible_columns = NULL) { layout_null <- function() { # PANEL needs to be a factor to be consistent with other facet types - new_data_frame(list(PANEL = factor(1), ROW = 1, COL = 1, SCALE_X = 1, SCALE_Y = 1)) + data_frame0( + PANEL = factor(1), + ROW = 1, + COL = 1, + SCALE_X = 1, + SCALE_Y = 1, + .size = 1L + ) } check_layout <- function(x) { @@ -521,24 +528,25 @@ find_panel <- function(table) { layout <- table$layout panels <- layout[grepl("^panel", layout$name), , drop = FALSE] - new_data_frame(list( + data_frame0( t = min(.subset2(panels, "t")), r = max(.subset2(panels, "r")), b = max(.subset2(panels, "b")), - l = min(.subset2(panels, "l")) - ), n = 1) + l = min(.subset2(panels, "l")), + .size = 1 + ) } #' @rdname find_panel #' @export panel_cols = function(table) { panels <- table$layout[grepl("^panel", table$layout$name), , drop = FALSE] - unique(panels[, c('l', 'r')]) + unique0(panels[, c('l', 'r')]) } #' @rdname find_panel #' @export panel_rows <- function(table) { panels <- table$layout[grepl("^panel", table$layout$name), , drop = FALSE] - unique(panels[, c('t', 'b')]) + unique0(panels[, c('t', 'b')]) } #' Take input data and define a mapping between faceting variables and ROW, #' COL and PANEL keys @@ -554,8 +562,8 @@ panel_rows <- function(table) { #' @keywords internal #' @export combine_vars <- function(data, env = emptyenv(), vars = NULL, drop = TRUE) { - possible_columns <- unique(unlist(lapply(data, names))) - if (length(vars) == 0) return(new_data_frame()) + possible_columns <- unique0(unlist(lapply(data, names))) + if (length(vars) == 0) return(data_frame0()) # For each layer, compute the facet values values <- compact(lapply(data, eval_facets, facets = vars, possible_columns = possible_columns)) @@ -577,7 +585,7 @@ combine_vars <- function(data, env = emptyenv(), vars = NULL, drop = TRUE) { )) } - base <- unique(rbind_dfs(values[has_all])) + base <- unique0(vec_rbind(!!!values[has_all])) if (!drop) { base <- unique_combs(base) } @@ -587,11 +595,11 @@ combine_vars <- function(data, env = emptyenv(), vars = NULL, drop = TRUE) { if (empty(value)) next; old <- base[setdiff(names(base), names(value))] - new <- unique(value[intersect(names(base), names(value))]) + new <- unique0(value[intersect(names(base), names(value))]) if (drop) { new <- unique_combs(new) } - base <- unique(rbind(base, df.grid(old, new))) + base <- unique0(vec_rbind(base, df.grid(old, new))) } if (empty(base)) { diff --git a/R/facet-grid-.r b/R/facet-grid-.r index 55cef88363..894fbb9c75 100644 --- a/R/facet-grid-.r +++ b/R/facet-grid-.r @@ -217,12 +217,18 @@ FacetGrid <- ggproto("FacetGrid", Facet, base <- df.grid(base_rows, base_cols) if (nrow(base) == 0) { - return(new_data_frame(list(PANEL = factor(1L), ROW = 1L, COL = 1L, SCALE_X = 1L, SCALE_Y = 1L))) + return(data_frame0( + PANEL = factor(1L), + ROW = 1L, + COL = 1L, + SCALE_X = 1L, + SCALE_Y = 1L + )) } # Add margins base <- reshape_add_margins(base, list(names(rows), names(cols)), params$margins) - base <- unique(base) + base <- unique0(base) # Create panel info dataset panel <- id(base, drop = TRUE) @@ -231,7 +237,7 @@ FacetGrid <- ggproto("FacetGrid", Facet, rows <- if (!length(names(rows))) rep(1L, length(panel)) else id(base[names(rows)], drop = TRUE) cols <- if (!length(names(cols))) rep(1L, length(panel)) else id(base[names(cols)], drop = TRUE) - panels <- new_data_frame(c(list(PANEL = panel, ROW = rows, COL = cols), base)) + panels <- data_frame0(PANEL = panel, ROW = rows, COL = cols, base) panels <- panels[order(panels$PANEL), , drop = FALSE] rownames(panels) <- NULL @@ -242,7 +248,7 @@ FacetGrid <- ggproto("FacetGrid", Facet, }, map_data = function(data, layout, params) { if (empty(data)) { - return(cbind(data, PANEL = integer(0))) + return(vec_cbind(data %|W|% NULL, PANEL = integer(0))) } rows <- params$rows @@ -265,15 +271,16 @@ FacetGrid <- ggproto("FacetGrid", Facet, # duplicating the data missing_facets <- setdiff(vars, names(facet_vals)) if (length(missing_facets) > 0) { - to_add <- unique(layout[missing_facets]) + to_add <- unique0(layout[missing_facets]) data_rep <- rep.int(1:nrow(data), nrow(to_add)) facet_rep <- rep(1:nrow(to_add), each = nrow(data)) data <- unrowname(data[data_rep, , drop = FALSE]) - facet_vals <- unrowname(cbind( - facet_vals[data_rep, , drop = FALSE], - to_add[facet_rep, , drop = FALSE])) + facet_vals <- unrowname(vec_cbind( + unrowname(facet_vals[data_rep, , drop = FALSE]), + unrowname(to_add[facet_rep, , drop = FALSE])) + ) } # Add PANEL variable @@ -283,6 +290,7 @@ FacetGrid <- ggproto("FacetGrid", Facet, } else { facet_vals[] <- lapply(facet_vals[], as.factor) facet_vals[] <- lapply(facet_vals[], addNA, ifany = TRUE) + layout[] <- lapply(layout[], as.factor) keys <- join_keys(facet_vals, layout, by = vars) @@ -299,8 +307,8 @@ FacetGrid <- ggproto("FacetGrid", Facet, rows <- which(layout$COL == 1) axes <- render_axes(ranges[cols], ranges[rows], coord, theme, transpose = TRUE) - col_vars <- unique(layout[names(params$cols)]) - row_vars <- unique(layout[names(params$rows)]) + col_vars <- unique0(layout[names(params$cols)]) + row_vars <- unique0(layout[names(params$rows)]) # Adding labels metadata, useful for labellers attr(col_vars, "type") <- "cols" attr(col_vars, "facet") <- "grid" @@ -440,6 +448,6 @@ ulevels <- function(x) { x <- addNA(x, TRUE) factor(levels(x), levels(x), exclude = NULL) } else { - sort(unique(x)) + sort(unique0(x)) } } diff --git a/R/facet-null.r b/R/facet-null.r index 8216b42979..a665c96edd 100644 --- a/R/facet-null.r +++ b/R/facet-null.r @@ -30,10 +30,10 @@ FacetNull <- ggproto("FacetNull", Facet, # Need the is.waive check for special case where no data, but aesthetics # are mapped to vectors if (is.waive(data)) - return(new_data_frame(list(PANEL = factor()))) + return(data_frame0(PANEL = factor())) if (empty(data)) - return(new_data_frame(c(data, list(PANEL = factor())))) + return(data_frame0(data, PANEL = factor())) # Needs to be a factor to be consistent with other facet types data$PANEL <- factor(1) diff --git a/R/facet-wrap.r b/R/facet-wrap.r index 243ee721d3..70ca5dc89a 100644 --- a/R/facet-wrap.r +++ b/R/facet-wrap.r @@ -147,29 +147,29 @@ FacetWrap <- ggproto("FacetWrap", Facet, return(layout_null()) } - base <- unrowname( - combine_vars(data, params$plot_env, vars, drop = params$drop) - ) + base <- combine_vars(data, params$plot_env, vars, drop = params$drop) id <- id(base, drop = TRUE) n <- attr(id, "n") dims <- wrap_dims(n, params$nrow, params$ncol) - layout <- new_data_frame(list(PANEL = factor(id, levels = seq_len(n)))) - - if (params$as.table) { - layout$ROW <- as.integer((id - 1L) %/% dims[2] + 1L) - } else { - layout$ROW <- as.integer(dims[1] - (id - 1L) %/% dims[2]) - } - layout$COL <- as.integer((id - 1L) %% dims[2] + 1L) + layout <- data_frame0( + PANEL = factor(id, levels = seq_len(n)), + ROW = if (params$as.table) { + as.integer((id - 1L) %/% dims[2] + 1L) + } else { + as.integer(dims[1] - (id - 1L) %/% dims[2]) + }, + COL = as.integer((id - 1L) %% dims[2] + 1L), + .size = length(id) + ) # For vertical direction, flip row and col if (identical(params$dir, "v")) { layout[c("ROW", "COL")] <- layout[c("COL", "ROW")] } - panels <- cbind(layout, unrowname(base)) + panels <- vec_cbind(layout, base) panels <- panels[order(panels$PANEL), , drop = FALSE] rownames(panels) <- NULL @@ -181,7 +181,7 @@ FacetWrap <- ggproto("FacetWrap", Facet, }, map_data = function(data, layout, params) { if (empty(data)) { - return(cbind(data, PANEL = integer(0))) + return(vec_cbind(data %|W|% NULL, PANEL = integer(0))) } vars <- params$facets @@ -193,19 +193,21 @@ FacetWrap <- ggproto("FacetWrap", Facet, facet_vals <- eval_facets(vars, data, params$.possible_columns) facet_vals[] <- lapply(facet_vals[], as.factor) + layout[] <- lapply(layout[], as.factor) missing_facets <- setdiff(names(vars), names(facet_vals)) if (length(missing_facets) > 0) { - to_add <- unique(layout[missing_facets]) + to_add <- unique0(layout[missing_facets]) data_rep <- rep.int(1:nrow(data), nrow(to_add)) facet_rep <- rep(1:nrow(to_add), each = nrow(data)) - data <- unrowname(data[data_rep, , drop = FALSE]) - facet_vals <- unrowname(cbind( + data <- data[data_rep, , drop = FALSE] + facet_vals <- vec_cbind( facet_vals[data_rep, , drop = FALSE], - to_add[facet_rep, , drop = FALSE])) + to_add[facet_rep, , drop = FALSE] + ) } keys <- join_keys(facet_vals, layout, by = names(vars)) @@ -243,7 +245,7 @@ FacetWrap <- ggproto("FacetWrap", Facet, if (length(params$facets) == 0) { # Add a dummy label - labels_df <- new_data_frame(list("(all)" = "(all)"), n = 1) + labels_df <- data_frame0("(all)" = "(all)", .size = 1) } else { labels_df <- layout[names(params$facets)] } @@ -322,10 +324,12 @@ FacetWrap <- ggproto("FacetWrap", Facet, empty_bottom <- apply(empties, 2, function(x) c(diff(x) == 1, FALSE)) if (any(empty_bottom)) { pos <- which(empty_bottom) - panel_loc <- data_frame(ROW = row_ind[pos], COL = col_ind[pos]) - # Substitute with vctrs::vec_match(panel_loc, layout[, c("ROW", "COL")]) - # Once we switch to vctrs wholesale - panels <- merge(panel_loc, cbind(layout, .index = seq_len(nrow(layout))))$.index + panel_loc <- data_frame0( + ROW = row_ind[pos], + COL = col_ind[pos], + .size = length(pos) + ) + panels <- vec_match(panel_loc, layout[, c("ROW", "COL")]) x_axes <- axes$x$bottom[layout$SCALE_X[panels]] if (params$strip.position == "bottom" && !inside && @@ -339,8 +343,12 @@ FacetWrap <- ggproto("FacetWrap", Facet, empty_top <- apply(empties, 2, function(x) c(FALSE, diff(x) == -1)) if (any(empty_top)) { pos <- which(empty_top) - panel_loc <- data_frame(ROW = row_ind[pos], COL = col_ind[pos]) - panels <- merge(panel_loc, cbind(layout, .index = seq_len(nrow(layout))))$.index + panel_loc <- data_frame0( + ROW = row_ind[pos], + COL = col_ind[pos], + .size = length(pos) + ) + panels <- vec_match(panel_loc, layout[, c("ROW", "COL")]) x_axes <- axes$x$top[layout$SCALE_X[panels]] if (params$strip.position == "top" && !inside && @@ -354,8 +362,12 @@ FacetWrap <- ggproto("FacetWrap", Facet, empty_right <- t(apply(empties, 1, function(x) c(diff(x) == 1, FALSE))) if (any(empty_right)) { pos <- which(empty_right) - panel_loc <- data_frame(ROW = row_ind[pos], COL = col_ind[pos]) - panels <- merge(panel_loc, cbind(layout, .index = seq_len(nrow(layout))))$.index + panel_loc <- data_frame0( + ROW = row_ind[pos], + COL = col_ind[pos], + .size = length(pos) + ) + panels <- vec_match(panel_loc, layout[, c("ROW", "COL")]) y_axes <- axes$y$right[layout$SCALE_Y[panels]] if (params$strip.position == "right" && !inside && @@ -369,8 +381,12 @@ FacetWrap <- ggproto("FacetWrap", Facet, empty_left <- t(apply(empties, 1, function(x) c(FALSE, diff(x) == -1))) if (any(empty_left)) { pos <- which(empty_left) - panel_loc <- data_frame(ROW = row_ind[pos], COL = col_ind[pos]) - panels <- merge(panel_loc, cbind(layout, .index = seq_len(nrow(layout))))$.index + panel_loc <- data_frame0( + ROW = row_ind[pos], + COL = col_ind[pos], + .size = length(pos) + ) + panels <- vec_match(panel_loc, layout[, c("ROW", "COL")]) y_axes <- axes$y$left[layout$SCALE_Y[panels]] if (params$strip.position == "left" && !inside && diff --git a/R/fortify-map.r b/R/fortify-map.r index 99950d5310..dbf48ad334 100644 --- a/R/fortify-map.r +++ b/R/fortify-map.r @@ -24,14 +24,17 @@ #' geom_polygon(aes(group = group), colour = "white") #' } fortify.map <- function(model, data, ...) { - df <- new_data_frame(list( + df <- data_frame0( long = model$x, lat = model$y, group = cumsum(is.na(model$x) & is.na(model$y)) + 1, - order = seq_along(model$x) - ), n = length(model$x)) + order = seq_along(model$x), + .size = length(model$x) + ) - names <- do.call("rbind", lapply(strsplit(model$names, "[:,]"), "[", 1:2)) + # TODO: convert to vec_rbind() once it accepts a function in .name_repair + names <- lapply(strsplit(model$names, "[:,]"), "[", 1:2) + names <- inject(rbind(!!!names)) df$region <- names[df$group, 1] df$subregion <- names[df$group, 2] df[stats::complete.cases(df$lat, df$long), ] diff --git a/R/fortify-multcomp.r b/R/fortify-multcomp.r index eaa8d316bd..0c79c75784 100644 --- a/R/fortify-multcomp.r +++ b/R/fortify-multcomp.r @@ -33,12 +33,13 @@ NULL #' @rdname fortify-multcomp #' @export fortify.glht <- function(model, data, ...) { - unrowname(base::data.frame( + base::data.frame( lhs = rownames(model$linfct), rhs = model$rhs, estimate = stats::coef(model), check.names = FALSE, - stringsAsFactors = FALSE)) + stringsAsFactors = FALSE + ) } #' @rdname fortify-multcomp @@ -48,12 +49,13 @@ fortify.confint.glht <- function(model, data, ...) { coef <- model$confint colnames(coef) <- to_lower_ascii(colnames(coef)) - unrowname(base::data.frame( + base::data.frame( lhs = rownames(coef), rhs = model$rhs, coef, check.names = FALSE, - stringsAsFactors = FALSE)) + stringsAsFactors = FALSE + ) } #' @method fortify summary.glht @@ -64,12 +66,13 @@ fortify.summary.glht <- function(model, data, ...) { model$test[c("coefficients", "sigma", "tstat", "pvalues")]) names(coef) <- c("estimate", "se", "t", "p") - unrowname(base::data.frame( + base::data.frame( lhs = rownames(coef), rhs = model$rhs, coef, check.names = FALSE, - stringsAsFactors = FALSE)) + stringsAsFactors = FALSE + ) } @@ -77,9 +80,10 @@ fortify.summary.glht <- function(model, data, ...) { #' @rdname fortify-multcomp #' @export fortify.cld <- function(model, data, ...) { - unrowname(base::data.frame( + base::data.frame( lhs = names(model$mcletters$Letters), letters = model$mcletters$Letters, check.names = FALSE, - stringsAsFactors = FALSE)) + stringsAsFactors = FALSE + ) } diff --git a/R/fortify-spatial.r b/R/fortify-spatial.r index 0897abd38d..21ccbf9f28 100644 --- a/R/fortify-spatial.r +++ b/R/fortify-spatial.r @@ -25,7 +25,8 @@ fortify.SpatialPolygonsDataFrame <- function(model, data, region = NULL, ...) { attr <- as.data.frame(model) # If not specified, split into regions based on polygons if (is.null(region)) { - coords <- rbind_dfs(lapply(model@polygons,fortify)) + coords <- lapply(model@polygons,fortify) + coords <- vec_rbind(!!!coords) cli::cli_inform("Regions defined for each Polygons") } else { cp <- sp::polygons(model) @@ -42,7 +43,8 @@ fortify.SpatialPolygonsDataFrame <- function(model, data, region = NULL, ...) { #' @export #' @method fortify SpatialPolygons fortify.SpatialPolygons <- function(model, data, ...) { - rbind_dfs(lapply(model@polygons, fortify)) + polys <- lapply(model@polygons, fortify) + vec_rbind(!!!polys) } #' @rdname fortify.sp @@ -50,11 +52,12 @@ fortify.SpatialPolygons <- function(model, data, ...) { #' @method fortify Polygons fortify.Polygons <- function(model, data, ...) { subpolys <- model@Polygons - pieces <- rbind_dfs(lapply(seq_along(subpolys), function(i) { + pieces <- lapply(seq_along(subpolys), function(i) { df <- fortify(subpolys[[model@plotOrder[i]]]) df$piece <- i df - })) + }) + pieces <- vec_rbind(!!!pieces) pieces$order <- 1:nrow(pieces) pieces$id <- model@ID @@ -78,7 +81,8 @@ fortify.Polygon <- function(model, data, ...) { #' @export #' @method fortify SpatialLinesDataFrame fortify.SpatialLinesDataFrame <- function(model, data, ...) { - rbind_dfs(lapply(model@lines, fortify)) + lines <- lapply(model@lines, fortify) + vec_rbind(!!!lines) } #' @rdname fortify.sp @@ -86,11 +90,12 @@ fortify.SpatialLinesDataFrame <- function(model, data, ...) { #' @method fortify Lines fortify.Lines <- function(model, data, ...) { lines <- model@Lines - pieces <- rbind_dfs(lapply(seq_along(lines), function(i) { + pieces <- lapply(seq_along(lines), function(i) { df <- fortify(lines[[i]]) df$piece <- i df - })) + }) + pieces <- vec_rbind(!!!pieces) pieces$order <- 1:nrow(pieces) pieces$id <- model@ID diff --git a/R/geom-.r b/R/geom-.r index 9ec3691ab9..ed12c06349 100644 --- a/R/geom-.r +++ b/R/geom-.r @@ -78,12 +78,11 @@ Geom <- ggproto("Geom", # Trim off extra parameters params <- params[intersect(names(params), self$parameters())] - args <- c(list(quote(data), quote(panel_params), quote(coord)), params) lapply(split(data, data$PANEL), function(data) { if (empty(data)) return(zeroGrob()) panel_params <- layout$panel_params[[data$PANEL[1]]] - do.call(self$draw_panel, args) + inject(self$draw_panel(data, panel_params, coord, !!!params)) }) }, @@ -94,7 +93,7 @@ Geom <- ggproto("Geom", }) ggname(snake_class(self), gTree( - children = do.call("gList", grobs) + children = inject(gList(!!!grobs)) )) }, @@ -151,7 +150,7 @@ Geom <- ggproto("Geom", } names(modified_aes) <- names(rename_aes(modifiers)) - modified_aes <- new_data_frame(compact(modified_aes)) + modified_aes <- data_frame0(!!!compact(modified_aes)) data <- cunion(modified_aes, data) } diff --git a/R/geom-abline.r b/R/geom-abline.r index ff7d359ab6..4d18c8d8c5 100644 --- a/R/geom-abline.r +++ b/R/geom-abline.r @@ -96,10 +96,11 @@ geom_abline <- function(mapping = NULL, data = NULL, if (missing(intercept)) intercept <- 0 n_slopes <- max(length(slope), length(intercept)) - data <- new_data_frame(list( + data <- data_frame0( intercept = intercept, - slope = slope - ), n = n_slopes) + slope = slope, + .size = n_slopes + ) mapping <- aes(intercept = intercept, slope = slope) show.legend <- FALSE } @@ -138,7 +139,7 @@ GeomAbline <- ggproto("GeomAbline", Geom, data$y <- ranges$x[1] * data$slope + data$intercept data$yend <- ranges$x[2] * data$slope + data$intercept - GeomSegment$draw_panel(unique(data), panel_params, coord, lineend = lineend) + GeomSegment$draw_panel(unique0(data), panel_params, coord, lineend = lineend) }, default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), diff --git a/R/geom-boxplot.r b/R/geom-boxplot.r index d787f64b7a..1ead4e61bd 100644 --- a/R/geom-boxplot.r +++ b/R/geom-boxplot.r @@ -229,36 +229,33 @@ GeomBoxplot <- ggproto("GeomBoxplot", Geom, group = data$group ) - whiskers <- new_data_frame(c( - list( - x = c(data$x, data$x), - xend = c(data$x, data$x), - y = c(data$upper, data$lower), - yend = c(data$ymax, data$ymin), - alpha = c(NA_real_, NA_real_) - ), - common - ), n = 2) + whiskers <- data_frame0( + x = c(data$x, data$x), + xend = c(data$x, data$x), + y = c(data$upper, data$lower), + yend = c(data$ymax, data$ymin), + alpha = c(NA_real_, NA_real_), + !!!common, + .size = 2 + ) whiskers <- flip_data(whiskers, flipped_aes) - box <- new_data_frame(c( - list( - xmin = data$xmin, - xmax = data$xmax, - ymin = data$lower, - y = data$middle, - ymax = data$upper, - ynotchlower = ifelse(notch, data$notchlower, NA), - ynotchupper = ifelse(notch, data$notchupper, NA), - notchwidth = notchwidth, - alpha = data$alpha - ), - common - )) + box <- data_frame0( + xmin = data$xmin, + xmax = data$xmax, + ymin = data$lower, + y = data$middle, + ymax = data$upper, + ynotchlower = ifelse(notch, data$notchlower, NA), + ynotchupper = ifelse(notch, data$notchupper, NA), + notchwidth = notchwidth, + alpha = data$alpha, + !!!common + ) box <- flip_data(box, flipped_aes) if (!is.null(data$outliers) && length(data$outliers[[1]] >= 1)) { - outliers <- new_data_frame(list( + outliers <- data_frame0( y = data$outliers[[1]], x = data$x[1], colour = outlier.colour %||% data$colour[1], @@ -267,8 +264,9 @@ GeomBoxplot <- ggproto("GeomBoxplot", Geom, size = outlier.size %||% data$size[1], stroke = outlier.stroke %||% data$stroke[1], fill = NA, - alpha = outlier.alpha %||% data$alpha[1] - ), n = length(data$outliers[[1]])) + alpha = outlier.alpha %||% data$alpha[1], + .size = length(data$outliers[[1]]) + ) outliers <- flip_data(outliers, flipped_aes) outliers_grob <- GeomPoint$draw_panel(outliers, panel_params, coord) diff --git a/R/geom-crossbar.r b/R/geom-crossbar.r index 74b678c75c..90103d15c4 100644 --- a/R/geom-crossbar.r +++ b/R/geom-crossbar.r @@ -60,7 +60,7 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, if (has_notch) { if (data$ynotchlower < data$ymin || data$ynotchupper > data$ymax) cli::cli_inform(c( - "Notch went outside hinges", + "Notch went outside hinges", i = "Do you want {.code notch = FALSE}?" )) @@ -69,7 +69,7 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, middle$x <- middle$x + notchindent middle$xend <- middle$xend - notchindent - box <- new_data_frame(list( + box <- data_frame0( x = c( data$xmin, data$xmin, data$xmin + notchindent, data$xmin, data$xmin, data$xmax, data$xmax, data$xmax - notchindent, data$xmax, data$xmax, @@ -86,10 +86,10 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, linetype = rep(data$linetype, 11), fill = rep(data$fill, 11), group = rep(seq_len(nrow(data)), 11) - )) + ) } else { # No notch - box <- new_data_frame(list( + box <- data_frame0( x = c(data$xmin, data$xmin, data$xmax, data$xmax, data$xmin), y = c(data$ymax, data$ymin, data$ymin, data$ymax, data$ymax), alpha = rep(data$alpha, 5), @@ -98,7 +98,7 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, linetype = rep(data$linetype, 5), fill = rep(data$fill, 5), group = rep(seq_len(nrow(data)), 5) # each bar forms it's own group - )) + ) } box <- flip_data(box, flipped_aes) middle <- flip_data(middle, flipped_aes) diff --git a/R/geom-errorbar.r b/R/geom-errorbar.r index 41e1cad5b5..7fe0d5a54b 100644 --- a/R/geom-errorbar.r +++ b/R/geom-errorbar.r @@ -54,18 +54,18 @@ GeomErrorbar <- ggproto("GeomErrorbar", Geom, draw_panel = function(data, panel_params, coord, lineend = "butt", width = NULL, flipped_aes = FALSE) { data <- flip_data(data, flipped_aes) - x <- as.vector(rbind(data$xmin, data$xmax, NA, data$x, data$x, NA, data$xmin, data$xmax)) - y <- as.vector(rbind(data$ymax, data$ymax, NA, data$ymax, data$ymin, NA, data$ymin, data$ymin)) - data <- new_data_frame(list( + 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) + data <- data_frame0( x = x, y = y, colour = rep(data$colour, each = 8), alpha = rep(data$alpha, each = 8), linewidth = rep(data$linewidth, each = 8), linetype = rep(data$linetype, each = 8), - group = rep(1:(nrow(data)), each = 8), - row.names = 1:(nrow(data) * 8) - )) + group = rep(seq_len(nrow(data)), each = 8), + .size = nrow(data) * 8 + ) data <- flip_data(data, flipped_aes) GeomPath$draw_panel(data, panel_params, coord, lineend = lineend) }, diff --git a/R/geom-errorbarh.r b/R/geom-errorbarh.r index 93ceea200d..ecda020fa0 100644 --- a/R/geom-errorbarh.r +++ b/R/geom-errorbarh.r @@ -68,16 +68,16 @@ GeomErrorbarh <- ggproto("GeomErrorbarh", Geom, }, draw_panel = function(data, panel_params, coord, height = NULL, lineend = "butt") { - GeomPath$draw_panel(new_data_frame(list( - x = as.vector(rbind(data$xmax, data$xmax, NA, data$xmax, data$xmin, NA, data$xmin, data$xmin)), - y = as.vector(rbind(data$ymin, data$ymax, NA, data$y, data$y, NA, data$ymin, data$ymax)), + GeomPath$draw_panel(data_frame0( + x = vec_interleave(data$xmax, data$xmax, NA, data$xmax, data$xmin, NA, data$xmin, data$xmin), + y = vec_interleave(data$ymin, data$ymax, NA, data$y, data$y, NA, data$ymin, data$ymax), colour = rep(data$colour, each = 8), alpha = rep(data$alpha, each = 8), linewidth = rep(data$linewidth, each = 8), linetype = rep(data$linetype, each = 8), group = rep(1:(nrow(data)), each = 8), - row.names = 1:(nrow(data) * 8) - )), panel_params, coord, lineend = lineend) + .size = nrow(data) * 8 + ), panel_params, coord, lineend = lineend) }, rename_size = TRUE diff --git a/R/geom-function.R b/R/geom-function.R index 10d49be80d..44f8ea6fb5 100644 --- a/R/geom-function.R +++ b/R/geom-function.R @@ -93,7 +93,7 @@ GeomFunction <- ggproto("GeomFunction", GeomPath, draw_panel = function(self, data, panel_params, coord, arrow = NULL, lineend = "butt", linejoin = "round", linemitre = 10, na.rm = FALSE) { - groups <- unique(data$group) + groups <- unique0(data$group) if (length(groups) > 1) { cli::cli_warn(c( "Multiple drawing groups in {.fn {snake_class(self)}}", diff --git a/R/geom-hline.r b/R/geom-hline.r index f1e4bb8286..e46bd3a573 100644 --- a/R/geom-hline.r +++ b/R/geom-hline.r @@ -19,7 +19,7 @@ geom_hline <- function(mapping = NULL, data = NULL, cli::cli_warn("{.fn geom_hline}: Ignoring {.arg data} because {.arg yintercept} was provided.") } - data <- new_data_frame(list(yintercept = yintercept)) + data <- data_frame0(yintercept = yintercept) mapping <- aes(yintercept = yintercept) show.legend <- FALSE } @@ -52,7 +52,7 @@ GeomHline <- ggproto("GeomHline", Geom, data$y <- data$yintercept data$yend <- data$yintercept - GeomSegment$draw_panel(unique(data), panel_params, coord, lineend = lineend) + GeomSegment$draw_panel(unique0(data), panel_params, coord, lineend = lineend) }, default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), diff --git a/R/geom-map.r b/R/geom-map.r index 0b390348c6..4a1037c17f 100644 --- a/R/geom-map.r +++ b/R/geom-map.r @@ -139,7 +139,7 @@ GeomMap <- ggproto("GeomMap", GeomPolygon, # must be sequential integers coords <- coord_munch(coord, map, panel_params) coords$group <- coords$group %||% coords$id - grob_id <- match(coords$group, unique(coords$group)) + grob_id <- match(coords$group, unique0(coords$group)) # Align data with map data_rows <- match(coords$id[!duplicated(grob_id)], data$map_id) diff --git a/R/geom-path.r b/R/geom-path.r index b8a76bf639..e87bbcdf78 100644 --- a/R/geom-path.r +++ b/R/geom-path.r @@ -167,16 +167,17 @@ GeomPath <- ggproto("GeomPath", Geom, # Work out whether we should use lines or segments attr <- dapply(munched, "group", function(df) { - linetype <- unique(df$linetype) - new_data_frame(list( + linetype <- unique0(df$linetype) + data_frame0( solid = identical(linetype, 1) || identical(linetype, "solid"), - constant = nrow(unique(df[, c("alpha", "colour","linewidth", "linetype")])) == 1 - ), n = 1) + constant = nrow(unique0(df[, c("alpha", "colour", "linewidth", "linetype")])) == 1, + .size = 1 + ) }) solid_lines <- all(attr$solid) constant <- all(attr$constant) if (!solid_lines && !constant) { - cli::cli_abort("{.fn {snake_class(self)}} can't have varying {.field colour}, {.field size}, and/or {.field alpha} along the line when {.field linetype} isn't solid") + cli::cli_abort("{.fn {snake_class(self)}} can't have varying {.field colour}, {.field linewidth}, and/or {.field alpha} along the line when {.field linetype} isn't solid") } # Work out grouping variables for grobs @@ -200,7 +201,7 @@ GeomPath <- ggproto("GeomPath", Geom, ) ) } else { - id <- match(munched$group, unique(munched$group)) + id <- match(munched$group, unique0(munched$group)) polylineGrob( munched$x, munched$y, id = id, default.units = "native", arrow = arrow, @@ -359,5 +360,5 @@ stairstep <- function(data, direction = "hv") { data_attr <- data[xs, setdiff(names(data), c("x", "y"))] } - new_data_frame(c(list(x = x, y = y), data_attr)) + data_frame0(x = x, y = y, data_attr) } diff --git a/R/geom-point.r b/R/geom-point.r index 85b36b231c..59d4301297 100644 --- a/R/geom-point.r +++ b/R/geom-point.r @@ -185,12 +185,12 @@ translate_shape_string <- function(shape_string) { nonunique_strings <- shape_match == 0 if (any(invalid_strings)) { - bad_string <- unique(shape_string[invalid_strings]) + bad_string <- unique0(shape_string[invalid_strings]) cli::cli_abort("Shape aesthetic contains invalid value{?s}: {.val {bad_string}}") } if (any(nonunique_strings)) { - bad_string <- unique(shape_string[nonunique_strings]) + bad_string <- unique0(shape_string[nonunique_strings]) cli::cli_abort(c( "shape names must be given unambiguously", "i" = "Fix {.val {bad_string}}" diff --git a/R/geom-polygon.r b/R/geom-polygon.r index 9c771cced7..3355fa3bc5 100644 --- a/R/geom-polygon.r +++ b/R/geom-polygon.r @@ -146,7 +146,7 @@ GeomPolygon <- ggproto("GeomPolygon", Geom, } # Sort by group to make sure that colors, fill, etc. come in same order munched <- munched[order(munched$group, munched$subgroup), ] - id <- match(munched$subgroup, unique(munched$subgroup)) + id <- match(munched$subgroup, unique0(munched$subgroup)) # For gpar(), there is one entry per polygon (not one entry per point). # We'll pull the first value from each group, and assume all these values diff --git a/R/geom-raster.r b/R/geom-raster.r index a9a2c20a51..b7ab3fa92f 100644 --- a/R/geom-raster.r +++ b/R/geom-raster.r @@ -57,7 +57,7 @@ GeomRaster <- ggproto("GeomRaster", Geom, hjust <- params$hjust %||% 0.5 vjust <- params$vjust %||% 0.5 - x_diff <- diff(sort(unique(as.numeric(data$x)))) + x_diff <- diff(sort(unique0(as.numeric(data$x)))) if (length(x_diff) == 0) { w <- 1 } else if (any(abs(diff(x_diff)) > precision)) { @@ -69,7 +69,7 @@ GeomRaster <- ggproto("GeomRaster", Geom, } else { w <- x_diff[1] } - y_diff <- diff(sort(unique(as.numeric(data$y)))) + y_diff <- diff(sort(unique0(as.numeric(data$y)))) if (length(y_diff) == 0) { h <- 1 } else if (any(abs(diff(y_diff)) > precision)) { diff --git a/R/geom-rect.r b/R/geom-rect.r index 9ee285f5d6..3263d091d3 100644 --- a/R/geom-rect.r +++ b/R/geom-rect.r @@ -41,12 +41,12 @@ GeomRect <- ggproto("GeomRect", Geom, polys <- lapply(split(data, seq_len(nrow(data))), function(row) { poly <- rect_to_poly(row$xmin, row$xmax, row$ymin, row$ymax) - aes <- new_data_frame(row[aesthetics])[rep(1,5), ] + aes <- row[rep(1,5), aesthetics] - GeomPolygon$draw_panel(cbind(poly, aes), panel_params, coord, lineend = lineend, linejoin = linejoin) + GeomPolygon$draw_panel(vec_cbind(poly, aes), panel_params, coord, lineend = lineend, linejoin = linejoin) }) - ggname("bar", do.call("grobTree", polys)) + ggname("geom_rect", inject(grobTree(!!!polys))) } else { coords <- coord$transform(data, panel_params) ggname("geom_rect", rectGrob( @@ -81,8 +81,8 @@ GeomRect <- ggproto("GeomRect", Geom, # # @keyword internal rect_to_poly <- function(xmin, xmax, ymin, ymax) { - new_data_frame(list( + data_frame0( y = c(ymax, ymax, ymin, ymin, ymax), x = c(xmin, xmax, xmax, xmin, xmin) - )) + ) } diff --git a/R/geom-ribbon.r b/R/geom-ribbon.r index 081b21fb30..c92835f32d 100644 --- a/R/geom-ribbon.r +++ b/R/geom-ribbon.r @@ -111,7 +111,7 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, data <- data[order(data$group), ] # Check that aesthetics are constant - aes <- unique(data[c("colour", "fill", "linewidth", "linetype", "alpha")]) + aes <- unique0(data[c("colour", "fill", "linewidth", "linetype", "alpha")]) if (nrow(aes) > 1) { cli::cli_abort("Aesthetics can not vary along a ribbon") } @@ -131,17 +131,17 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, data <- unclass(data) #for faster indexing # The upper line and lower line need to processed separately (#4023) - positions_upper <- new_data_frame(list( + positions_upper <- data_frame0( x = data$x, y = data$ymax, id = ids - )) + ) - positions_lower <- new_data_frame(list( + positions_lower <- data_frame0( x = rev(data$x), y = rev(data$ymin), id = rev(ids) - )) + ) positions_upper <- flip_data(positions_upper, flipped_aes) positions_lower <- flip_data(positions_lower, flipped_aes) @@ -149,7 +149,7 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, munched_upper <- coord_munch(coord, positions_upper, panel_params) munched_lower <- coord_munch(coord, positions_lower, panel_params) - munched_poly <- rbind(munched_upper, munched_lower) + munched_poly <- vec_rbind(munched_upper, munched_lower) is_full_outline <- identical(outline.type, "full") g_poly <- polygonGrob( @@ -174,7 +174,7 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, munched_lower$id <- munched_lower$id + max(ids, na.rm = TRUE) munched_lines <- switch(outline.type, - both = rbind(munched_upper, munched_lower), + both = vec_rbind(munched_upper, munched_lower), upper = munched_upper, lower = munched_lower, cli::cli_abort(c( diff --git a/R/geom-rug.r b/R/geom-rug.r index 6d4c3e7ac4..eb32b289ca 100644 --- a/R/geom-rug.r +++ b/R/geom-rug.r @@ -151,7 +151,7 @@ GeomRug <- ggproto("GeomRug", Geom, } } - gTree(children = do.call("gList", rugs)) + gTree(children = inject(gList(!!!rugs))) }, default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), diff --git a/R/geom-segment.r b/R/geom-segment.r index ef511f35c2..bff655f374 100644 --- a/R/geom-segment.r +++ b/R/geom-segment.r @@ -135,7 +135,7 @@ GeomSegment <- ggproto("GeomSegment", Geom, starts <- subset(data, select = c(-xend, -yend)) ends <- rename(subset(data, select = c(-x, -y)), c("xend" = "x", "yend" = "y")) - pieces <- rbind(starts, ends) + pieces <- vec_rbind(starts, ends) pieces <- pieces[order(pieces$group),] GeomPath$draw_panel(pieces, panel_params, coord, arrow = arrow, diff --git a/R/geom-sf.R b/R/geom-sf.R index 2489180d56..5b96e3c7be 100644 --- a/R/geom-sf.R +++ b/R/geom-sf.R @@ -193,7 +193,7 @@ sf_grob <- function(x, lineend = "butt", linejoin = "round", linemitre = 10, defaults[[3]], rename(GeomPoint$default_aes, c(size = "point_size", fill = "point_fill")) ) - default_names <- unique(unlist(lapply(defaults, names))) + default_names <- unique0(unlist(lapply(defaults, names))) defaults <- lapply(setNames(default_names, default_names), function(n) { unlist(lapply(defaults, function(def) def[[n]] %||% NA)) }) diff --git a/R/geom-violin.r b/R/geom-violin.r index 20d20f7c81..9c4cea54d4 100644 --- a/R/geom-violin.r +++ b/R/geom-violin.r @@ -144,14 +144,14 @@ GeomViolin <- ggproto("GeomViolin", Geom, ) # Make sure it's sorted properly to draw the outline - newdata <- rbind( + newdata <- vec_rbind( transform(data, x = xminv)[order(data$y), ], transform(data, x = xmaxv)[order(data$y, decreasing = TRUE), ] ) # Close the polygon: set first and last point the same # Needed for coord_polar and such - newdata <- rbind(newdata, newdata[1,]) + newdata <- vec_rbind(newdata, newdata[1,]) newdata <- flip_data(newdata, flipped_aes) # Draw quantiles if requested, so long as there is non-zero y range @@ -168,7 +168,7 @@ GeomViolin <- ggproto("GeomViolin", Geom, drop = FALSE ] aesthetics$alpha <- rep(1, nrow(quantiles)) - both <- cbind(quantiles, aesthetics) + both <- vec_cbind(quantiles, aesthetics) both <- both[!is.na(both$group), , drop = FALSE] both <- flip_data(both, flipped_aes) quantile_grob <- if (nrow(both) == 0) { @@ -207,10 +207,10 @@ create_quantile_segment_frame <- function(data, draw_quantiles) { violin.xmaxvs <- (stats::approxfun(data$y, data$xmaxv))(ys) # We have two rows per segment drawn. Each segment gets its own group. - new_data_frame(list( + data_frame0( x = interleave(violin.xminvs, violin.xmaxvs), y = rep(ys, each = 2), group = rep(ys, each = 2) - )) + ) } diff --git a/R/geom-vline.r b/R/geom-vline.r index d81f089ad7..6810f766e5 100644 --- a/R/geom-vline.r +++ b/R/geom-vline.r @@ -19,7 +19,7 @@ geom_vline <- function(mapping = NULL, data = NULL, cli::cli_warn("{.fn geom_vline}: Ignoring {.arg data} because {.arg xintercept} was provided.") } - data <- new_data_frame(list(xintercept = xintercept)) + data <- data_frame0(xintercept = xintercept) mapping <- aes(xintercept = xintercept) show.legend <- FALSE } @@ -52,7 +52,7 @@ GeomVline <- ggproto("GeomVline", Geom, data$y <- ranges$y[1] data$yend <- ranges$y[2] - GeomSegment$draw_panel(unique(data), panel_params, coord, lineend = lineend) + GeomSegment$draw_panel(unique0(data), panel_params, coord, lineend = lineend) }, default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), diff --git a/R/ggplot2-package.R b/R/ggplot2-package.R index 18ed13674c..102dc32bc5 100644 --- a/R/ggplot2-package.R +++ b/R/ggplot2-package.R @@ -2,7 +2,7 @@ "_PACKAGE" ## usethis namespace: start -#' @import scales grid gtable rlang +#' @import scales grid gtable rlang vctrs #' @importFrom glue glue glue_collapse #' @importFrom lifecycle deprecated #' @importFrom stats setNames diff --git a/R/guide-bins.R b/R/guide-bins.R index f252027f0f..047db20166 100644 --- a/R/guide-bins.R +++ b/R/guide-bins.R @@ -158,7 +158,7 @@ guide_train.bins <- function(guide, scale, aesthetic = NULL) { if (!is.numeric(scale$breaks)) { breaks <- breaks[!breaks %in% limits] } - all_breaks <- unique(c(limits[1], breaks, limits[2])) + all_breaks <- unique0(c(limits[1], breaks, limits[2])) bin_at <- all_breaks[-1] - diff(all_breaks) / 2 } else { # If the breaks are not numeric it is used with a discrete scale. We check @@ -178,7 +178,7 @@ guide_train.bins <- function(guide, scale, aesthetic = NULL) { limits <- all_breaks[c(1, length(all_breaks))] breaks <- all_breaks[-c(1, length(all_breaks))] } - key <- new_data_frame(setNames(list(c(scale$map(bin_at), NA)), aes_column_name)) + key <- data_frame(c(scale$map(bin_at), NA), .name_repair = ~ aes_column_name) labels <- scale$get_labels(breaks) show_limits <- rep(show_limits, 2) if (is.character(scale$labels) || is.numeric(scale$labels)) { @@ -376,9 +376,8 @@ guide_gengrob.bins <- function(guide, theme) { guide$keyheight %||% theme$legend.key.height %||% theme$legend.key.size ) - key_size_mat <- do.call("cbind", - lapply(guide$geoms, function(g) g$data$size / 10) - ) + key_size <- lapply(guide$geoms, function(g) g$data$size / 10) + key_size_mat <- inject(cbind(!!!key_size)) # key_size_mat can be an empty matrix (e.g. the data doesn't contain size # column), so subset it only when it has any rows and columns. @@ -410,11 +409,11 @@ guide_gengrob.bins <- function(guide, theme) { label_widths <- max(apply(label_sizes, 2, max)) label_heights <- max(apply(label_sizes, 1, max)) - key_loc <- data_frame( + key_loc <- data_frame0( R = seq(2, by = 2, length.out = n_keys), C = if (label.position %in% c("right", "bottom")) 1 else 3 ) - label_loc <- data_frame( + label_loc <- data_frame0( R = seq(1, by = 2, length.out = n_keys + 1), C = if (label.position %in% c("right", "bottom")) 3 else 1 ) diff --git a/R/guide-colorbar.r b/R/guide-colorbar.r index 57986afbef..6f11a92727 100644 --- a/R/guide-colorbar.r +++ b/R/guide-colorbar.r @@ -214,7 +214,7 @@ guide_train.colorbar <- function(guide, scale, aesthetic = NULL) { if (length(breaks) == 0 || all(is.na(breaks))) return() - ticks <- new_data_frame(setNames(list(scale$map(breaks)), aesthetic %||% scale$aesthetics[1])) + ticks <- data_frame(scale$map(breaks), .name_repair = ~ aesthetic %||% scale$aesthetics[1]) ticks$.value <- breaks ticks$.label <- scale$get_labels(breaks) @@ -224,9 +224,13 @@ guide_train.colorbar <- function(guide, scale, aesthetic = NULL) { .limits <- scale$get_limits() .bar <- seq(.limits[1], .limits[2], length.out = guide$nbin) if (length(.bar) == 0) { - .bar = unique(.limits) + .bar = unique0(.limits) } - guide$bar <- new_data_frame(list(colour = scale$map(.bar), value = .bar), n = length(.bar)) + guide$bar <- data_frame0( + colour = scale$map(.bar), + value = .bar, + .size = length(.bar) + ) if (guide$reverse) { guide$key <- guide$key[nrow(guide$key):1, ] guide$bar <- guide$bar[nrow(guide$bar):1, ] @@ -413,11 +417,7 @@ guide_gengrob.colorbar <- function(guide, theme) { # If any of the labels are quoted language objects, convert them # to expressions. Labels from formatter functions can return these if (any(vapply(label, is.call, logical(1)))) { - label <- lapply(label, function(l) { - if (is.call(l)) substitute(expression(x), list(x = l)) - else l - }) - label <- do.call(c, label) + label <- as.expression(label) } grob.label <- element_grob( element = label.theme, diff --git a/R/guide-colorsteps.R b/R/guide-colorsteps.R index cde853cbb1..e23b6d899b 100644 --- a/R/guide-colorsteps.R +++ b/R/guide-colorsteps.R @@ -78,7 +78,7 @@ guide_train.colorsteps <- function(guide, scale, aesthetic = NULL) { if (!is.numeric(scale$breaks)) { breaks <- breaks[!breaks %in% limits] } - all_breaks <- unique(c(limits[1], breaks, limits[2])) + all_breaks <- unique0(c(limits[1], breaks, limits[2])) bin_at <- all_breaks[-1] - diff(all_breaks) / 2 } else { # If the breaks are not numeric it is used with a discrete scale. We check @@ -101,7 +101,10 @@ guide_train.colorsteps <- function(guide, scale, aesthetic = NULL) { limits <- all_breaks[c(1, length(all_breaks))] breaks <- all_breaks[-c(1, length(all_breaks))] } - ticks <- new_data_frame(setNames(list(scale$map(breaks)), aesthetic %||% scale$aesthetics[1])) + ticks <- data_frame( + scale$map(breaks), + .name_repair = ~ aesthetic %||% scale$aesthetics[1] + ) ticks$.value <- seq_along(breaks) - 0.5 ticks$.label <- scale$get_labels(breaks) guide$nbin <- length(breaks) + 1L @@ -115,7 +118,11 @@ guide_train.colorsteps <- function(guide, scale, aesthetic = NULL) { guide$nbin <- guide$nbin - 1L } guide$key <- ticks - guide$bar <- new_data_frame(list(colour = scale$map(bin_at), value = seq_along(bin_at) - 1), n = length(bin_at)) + guide$bar <- data_frame0( + colour = scale$map(bin_at), + value = seq_along(bin_at) - 1, + .size = length(bin_at) + ) if (guide$reverse) { guide$key <- guide$key[nrow(guide$key):1, ] diff --git a/R/guide-legend.r b/R/guide-legend.r index 37923c5856..37f0071d35 100644 --- a/R/guide-legend.r +++ b/R/guide-legend.r @@ -210,7 +210,7 @@ guide_train.legend <- function(guide, scale, aesthetic = NULL) { # argument to this function or, as a fall back, the first in the vector # of possible aesthetics handled by the scale aes_column_name <- aesthetic %||% scale$aesthetics[1] - key <- new_data_frame(setNames(list(scale$map(breaks)), aes_column_name)) + key <- data_frame(scale$map(breaks), .name_repair = ~ aes_column_name) key$.label <- scale$get_labels(breaks) # Drop out-of-range values for continuous scale @@ -235,7 +235,7 @@ guide_train.legend <- function(guide, scale, aesthetic = NULL) { #' @export guide_merge.legend <- function(guide, new_guide) { new_guide$key$.label <- NULL - guide$key <- cbind(guide$key, new_guide$key) + guide$key <- vec_cbind(guide$key, new_guide$key) guide$override.aes <- c(guide$override.aes, new_guide$override.aes) if (any(duplicated(names(guide$override.aes)))) { cli::cli_warn("Duplicated {.arg override.aes} is ignored.") @@ -387,7 +387,8 @@ guide_gengrob.legend <- function(guide, theme) { guide$keyheight %||% theme$legend.key.height %||% theme$legend.key.size ) - key_size_mat <- do.call("cbind", lapply(guide$geoms, function(g) g$data$size / 10)) + key_size <- lapply(guide$geoms, function(g) g$data$size / 10) + key_size_mat <- inject(cbind(!!!key_size)) if (nrow(key_size_mat) == 0 || ncol(key_size_mat) == 0) { key_size_mat <- matrix(0, ncol = 1, nrow = nbreak) @@ -442,10 +443,10 @@ guide_gengrob.legend <- function(guide, theme) { ) if (guide$byrow) { - vps <- new_data_frame(list( + vps <- data_frame0( R = ceiling(seq(nbreak) / legend.ncol), C = (seq(nbreak) - 1) %% legend.ncol + 1 - )) + ) } else { vps <- mat_2_df(arrayInd(seq(nbreak), dim(key_sizes)), c("R", "C")) } diff --git a/R/guides-.r b/R/guides-.r index f752e033a3..6db4d8655c 100644 --- a/R/guides-.r +++ b/R/guides-.r @@ -280,8 +280,10 @@ guides_build <- function(ggrobs, theme) { theme$legend.spacing.y <- theme$legend.spacing.y %||% theme$legend.spacing theme$legend.spacing.x <- theme$legend.spacing.x %||% theme$legend.spacing - widths <- do.call("unit.c", lapply(ggrobs, function(g)sum(g$widths))) - heights <- do.call("unit.c", lapply(ggrobs, function(g)sum(g$heights))) + widths <- lapply(ggrobs, function(g) sum(g$widths)) + widths <- inject(unit.c(!!!widths)) + heights <- lapply(ggrobs, function(g) sum(g$heights)) + heights <- inject(unit.c(!!!heights)) # Set the justification of each legend within the legend box # First value is xjust, second value is yjust diff --git a/R/guides-axis.r b/R/guides-axis.r index efb3ee9b2a..0457d216b7 100644 --- a/R/guides-axis.r +++ b/R/guides-axis.r @@ -66,8 +66,10 @@ guide_train.axis <- function(guide, scale, aesthetic = NULL) { aesthetic <- aesthetic %||% scale$aesthetics[1] breaks <- scale$get_breaks() - empty_ticks <- new_data_frame( - list(aesthetic = numeric(0), .value = numeric(0), .label = character(0)) + empty_ticks <- data_frame0( + aesthetic = numeric(0), + .value = numeric(0), + .label = character(0) ) names(empty_ticks) <- c(aesthetic, ".value", ".label") @@ -81,7 +83,7 @@ guide_train.axis <- function(guide, scale, aesthetic = NULL) { guide$key <- empty_ticks } else { mapped_breaks <- if (scale$is_discrete()) scale$map(breaks) else breaks - ticks <- new_data_frame(setNames(list(mapped_breaks), aesthetic)) + ticks <- data_frame(mapped_breaks, .name_repair = ~ aesthetic) ticks$.value <- breaks ticks$.label <- scale$get_labels(breaks) @@ -248,7 +250,7 @@ draw_axis <- function(break_positions, break_labels, axis_position, theme, # break_labels can be a list() of language objects if (is.list(break_labels)) { if (any(vapply(break_labels, is.language, logical(1)))) { - break_labels <- do.call(expression, break_labels) + break_labels <- inject(expression(!!!break_labels)) } else { break_labels <- unlist(break_labels) } @@ -280,7 +282,8 @@ draw_axis <- function(break_positions, break_labels, axis_position, theme, # create gtable non_position_sizes <- paste0(non_position_size, "s") - label_dims <- do.call(unit.c, lapply(label_grobs, measure_labels_non_pos)) + label_dims <- lapply(label_grobs, measure_labels_non_pos) + label_dims <- inject(unit.c(!!!label_dims)) grobs <- c(list(ticks_grob), label_grobs) grob_dims <- unit.c(max(tick_length, unit(0, "pt")), label_dims) @@ -437,7 +440,7 @@ warn_for_guide_position <- function(guide) { return() } - if (length(unique(guide$key[[position_aes]][breaks_are_unique])) == 1) { + if (length(unique0(guide$key[[position_aes]][breaks_are_unique])) == 1) { cli::cli_warn(c( "Position guide is perpendicular to the intended axis", "i" = "Did you mean to specify a different guide {.arg position}?" diff --git a/R/hexbin.R b/R/hexbin.R index 296f8f2cce..3f6fabc7ec 100644 --- a/R/hexbin.R +++ b/R/hexbin.R @@ -31,10 +31,11 @@ hexBinSummarise <- function(x, y, z, binwidth, fun = mean, fun.args = list(), dr IDs = TRUE ) - value <- do.call(tapply, c(list(quote(z), quote(hb@cID), quote(fun)), fun.args)) + value <- inject(tapply(z, hb@cID, fun, !!!fun.args)) # Convert to data frame - out <- new_data_frame(hexbin::hcell2xy(hb)) + out <- hexbin::hcell2xy(hb) + out <- data_frame0(!!!out) out$value <- as.vector(value) out$width <- binwidth[1] out$height <- binwidth[2] diff --git a/R/labeller.r b/R/labeller.r index 76898efa11..55bd3de2d6 100644 --- a/R/labeller.r +++ b/R/labeller.r @@ -89,7 +89,7 @@ NULL collapse_labels_lines <- function(labels) { is_exp <- vapply(labels, function(l) length(l) > 0 && is.expression(l[[1]]), logical(1)) - out <- do.call("Map", c(list(paste, sep = ", "), labels)) + out <- inject(mapply(paste, !!!labels, sep = ", ", SIMPLIFY = FALSE)) label <- list(unname(unlist(out))) if (all(is_exp)) { label <- lapply(label, function(l) list(parse(text = paste0("list(", l, ")")))) @@ -133,8 +133,8 @@ label_both <- function(labels, multi_line = TRUE, sep = ": ") { out[[i]] <- paste(variable[[i]], value[[i]], sep = sep) } } else { - value <- do.call("paste", c(value, sep = ", ")) - variable <- do.call("paste", c(variable, sep = ", ")) + value <- inject(paste(!!!value, sep = ", ")) + variable <- inject(paste(!!!variable, sep = ", ")) out <- Map(paste, variable, value, sep = sep) out <- list(unname(unlist(out))) } @@ -217,7 +217,7 @@ label_bquote <- function(rows = NULL, cols = NULL, params <- as_environment(params, call_env) eval(substitute(bquote(expr, params), list(expr = quoted))) } - list(do.call("Map", c(list(f = evaluate), labels))) + list(inject(mapply(evaluate, !!!labels, SIMPLIFY = FALSE))) } structure(fun, class = "labeller") @@ -489,11 +489,11 @@ build_strip <- function(label_df, labeller, theme, horizontal) { }) } - # Create matrix of labels - labels <- lapply(labeller(label_df), cbind) - labels <- do.call("cbind", labels) + # Create labels + labels <- data_frame0(!!!labeller(label_df)) ncol <- ncol(labels) nrow <- nrow(labels) + labels_vec <- unlist(labels, use.names = FALSE) # Decide strip clipping clip <- calc_element("strip.clip", theme)[[1]] @@ -501,13 +501,13 @@ build_strip <- function(label_df, labeller, theme, horizontal) { clip <- c("on", "off", "inherit")[clip] if (horizontal) { - grobs_top <- lapply(labels, element_render, theme = theme, + grobs_top <- lapply(labels_vec, element_render, theme = theme, element = "strip.text.x.top", margin_x = TRUE, margin_y = TRUE) grobs_top <- assemble_strips(matrix(grobs_top, ncol = ncol, nrow = nrow), theme, horizontal, clip = clip) - grobs_bottom <- lapply(labels, element_render, theme = theme, + grobs_bottom <- lapply(labels_vec, element_render, theme = theme, element = "strip.text.x.bottom", margin_x = TRUE, margin_y = TRUE) grobs_bottom <- assemble_strips(matrix(grobs_bottom, ncol = ncol, nrow = nrow), @@ -518,13 +518,13 @@ build_strip <- function(label_df, labeller, theme, horizontal) { bottom = grobs_bottom ) } else { - grobs_left <- lapply(labels, element_render, theme = theme, + grobs_left <- lapply(labels_vec, element_render, theme = theme, element = "strip.text.y.left", margin_x = TRUE, margin_y = TRUE) grobs_left <- assemble_strips(matrix(grobs_left, ncol = ncol, nrow = nrow), theme, horizontal, clip = clip) - grobs_right <- lapply(labels[, rev(seq_len(ncol(labels))), drop = FALSE], + grobs_right <- lapply(unlist(labels[, rev(seq_len(ncol(labels))), drop = FALSE], use.names = FALSE), element_render, theme = theme, element = "strip.text.y.right", margin_x = TRUE, margin_y = TRUE) diff --git a/R/labels.r b/R/labels.r index ff5756cad3..669db6b5fa 100644 --- a/R/labels.r +++ b/R/labels.r @@ -209,7 +209,7 @@ generate_alt_text <- function(p) { # Get layer types layers <- vapply(p$layers, function(l) snake_class(l$geom), character(1)) - layers <- sub("_", " ", sub("^geom_", "", unique(layers))) + layers <- sub("_", " ", sub("^geom_", "", unique0(layers))) layers <- glue( " using ", if (length(layers) == 1) "a " else "", diff --git a/R/layer-sf.R b/R/layer-sf.R index 3fcf8fd2cd..b3b575e923 100644 --- a/R/layer-sf.R +++ b/R/layer-sf.R @@ -113,7 +113,7 @@ scale_type.sfc <- function(x) "identity" # helper function to determine the geometry type of sf object detect_sf_type <- function(sf) { - geometry_type <- unique(as.character(sf::st_geometry_type(sf))) + geometry_type <- unique0(as.character(sf::st_geometry_type(sf))) if (length(geometry_type) != 1) geometry_type <- "GEOMETRY" sf_types[geometry_type] } diff --git a/R/layer.r b/R/layer.r index 11776b1ea1..9b9020e17a 100644 --- a/R/layer.r +++ b/R/layer.r @@ -222,16 +222,16 @@ Layer <- ggproto("Layer", NULL, layer_data = function(self, plot_data) { if (is.waive(self$data)) { - plot_data + data <- plot_data } else if (is.function(self$data)) { data <- self$data(plot_data) if (!is.data.frame(data)) { cli::cli_abort("{.fn layer_data} must return a {.cls data.frame}") } - data } else { - self$data + data <- self$data } + if (is.null(data) || is.waive(data)) data else unrowname(data) }, # hook to allow a layer access to the final layer data @@ -326,7 +326,7 @@ Layer <- ggproto("Layer", NULL, compute_statistic = function(self, data, layout) { if (empty(data)) - return(new_data_frame()) + return(data_frame0()) self$computed_stat_params <- self$stat$setup_params(data, self$stat_params) data <- self$stat$setup_data(data, self$computed_stat_params) @@ -334,7 +334,7 @@ Layer <- ggproto("Layer", NULL, }, map_statistic = function(self, data, plot) { - if (empty(data)) return(new_data_frame()) + if (empty(data)) return(data_frame0()) # Make sure data columns are converted to correct names. If not done, a # column with e.g. a color name will not be found in an after_stat() @@ -375,7 +375,7 @@ Layer <- ggproto("Layer", NULL, } names(stat_data) <- names(new) - stat_data <- new_data_frame(compact(stat_data)) + stat_data <- data_frame0(!!!compact(stat_data)) # Add any new scales, if needed scales_add_defaults(plot$scales, data, new, plot$plot_env) @@ -389,7 +389,7 @@ Layer <- ggproto("Layer", NULL, }, compute_geom_1 = function(self, data) { - if (empty(data)) return(new_data_frame()) + if (empty(data)) return(data_frame0()) check_required_aesthetics( self$geom$required_aes, @@ -401,7 +401,7 @@ Layer <- ggproto("Layer", NULL, }, compute_position = function(self, data, layout) { - if (empty(data)) return(new_data_frame()) + if (empty(data)) return(data_frame0()) params <- self$position$setup_params(data) data <- self$position$setup_data(data, params) diff --git a/R/layout.R b/R/layout.R index 80e1940807..3808e9f5ce 100644 --- a/R/layout.R +++ b/R/layout.R @@ -30,7 +30,7 @@ Layout <- ggproto("Layout", NULL, panel_scales_y = NULL, panel_params = NULL, - setup = function(self, data, plot_data = new_data_frame(), plot_env = emptyenv()) { + setup = function(self, data, plot_data = data_frame0(), plot_env = emptyenv()) { data <- c(list(plot_data), data) # Setup facets @@ -88,7 +88,7 @@ Layout <- ggproto("Layout", NULL, ggname( paste("panel", i, sep = "-"), - gTree(children = do.call("gList", panel)) + gTree(children = inject(gList(!!!panel))) ) }) plot_table <- self$facet$draw_panels( @@ -303,6 +303,6 @@ scale_apply <- function(data, vars, method, scale_id, scales) { scales[[i]][[method]](data[[var]][scale_index[[i]]]) }) o <- order(unlist(scale_index))[seq_len(sum(lengths(pieces)))] - do.call("c", pieces)[o] + vec_c(!!!pieces)[o] }) } diff --git a/R/limits.r b/R/limits.r index 8426d6669e..da77e82522 100644 --- a/R/limits.r +++ b/R/limits.r @@ -183,11 +183,15 @@ limits.POSIXlt <- function(lims, var, call = caller_env()) { #' expand_limits(colour = factor(seq(2, 10, by = 2))) expand_limits <- function(...) { data <- list2(...) + + # unpack data frame columns data_dfs <- vapply(data, is.data.frame, logical(1)) - data <- do.call(c, c(list(data[!data_dfs]), data[data_dfs])) + data <- unlist(c(list(data[!data_dfs]), data[data_dfs]), recursive = FALSE) + + # Repeat vectors up to max length and collect to data frame n_rows <- max(vapply(data, length, integer(1))) data <- lapply(data, rep, length.out = n_rows) - data <- new_data_frame(data) + data <- data_frame0(!!!data) geom_blank(aes_all(names(data)), data, inherit.aes = FALSE) } diff --git a/R/performance.R b/R/performance.R index 208f902c69..b26b1a7072 100644 --- a/R/performance.R +++ b/R/performance.R @@ -1,31 +1,3 @@ -# Fast data.frame constructor and indexing -# No checking, recycling etc. unless asked for -new_data_frame <- function(x = list(), n = NULL) { - if (length(x) != 0 && is.null(names(x))) { - cli::cli_abort("Elements must be named") - } - lengths <- vapply(x, length, integer(1)) - if (is.null(n)) { - n <- if (length(x) == 0 || min(lengths) == 0) 0 else max(lengths) - } - for (i in seq_along(x)) { - if (lengths[i] == n) next - if (lengths[i] != 1) { - cli::cli_abort("Elements must equal the number of rows or 1") - } - x[[i]] <- rep(x[[i]], n) - } - - class(x) <- "data.frame" - - attr(x, "row.names") <- .set_row_names(n) - x -} - -data_frame <- function(...) { - new_data_frame(list(...)) -} - split_matrix <- function(x, col_names = colnames(x)) { force(col_names) x <- lapply(seq_len(ncol(x)), function(i) x[, i]) @@ -34,13 +6,15 @@ split_matrix <- function(x, col_names = colnames(x)) { } mat_2_df <- function(x, col_names = colnames(x)) { - new_data_frame(split_matrix(x, col_names)) + cols <- split_matrix(x, col_names) + data_frame0(!!!cols, .size = nrow(x)) } df_col <- function(x, name) .subset2(x, name) df_rows <- function(x, i) { - new_data_frame(lapply(x, `[`, i = i)) + cols <- lapply(x, `[`, i = i) + data_frame0(!!!cols, .size = length(i)) } # More performant modifyList without recursion diff --git a/R/position-.r b/R/position-.r index 14e58877a0..e9ea2ddf6f 100644 --- a/R/position-.r +++ b/R/position-.r @@ -55,7 +55,7 @@ Position <- ggproto("Position", compute_layer = function(self, data, params, layout) { dapply(data, "PANEL", function(data) { - if (empty(data)) return(new_data_frame()) + if (empty(data)) return(data_frame0()) scales <- layout$get_scales(data$PANEL[1]) self$compute_panel(data = data, params = params, scales = scales) diff --git a/R/position-collide.r b/R/position-collide.r index 20cf3173bb..035979e4ed 100644 --- a/R/position-collide.r +++ b/R/position-collide.r @@ -16,7 +16,7 @@ collide_setup <- function(data, width = NULL, name, strategy, } # Width determined from data, must be floating point constant - widths <- unique(data$xmax - data$xmin) + widths <- unique0(data$xmax - data$xmin) widths <- widths[!is.na(widths)] # # Suppress warning message since it's not reliable @@ -45,10 +45,10 @@ collide <- function(data, width = NULL, name, strategy, data <- data[ord, ] # Check for overlap - intervals <- as.numeric(t(unique(data[c("xmin", "xmax")]))) + intervals <- as.numeric(t(unique0(data[c("xmin", "xmax")]))) intervals <- intervals[!is.na(intervals)] - if (length(unique(intervals)) > 1 & any(diff(scale(intervals)) < -1e-6)) { + if (length(unique0(intervals)) > 1 & any(diff(scale(intervals)) < -1e-6)) { cli::cli_warn("{.fn {name}} requires non-overlapping {.field x} intervals") # This is where the algorithm from [L. Wilkinson. Dot plots. # The American Statistician, 1999.] should be used diff --git a/R/position-dodge.r b/R/position-dodge.r index 807c24c2ce..ac2a832755 100644 --- a/R/position-dodge.r +++ b/R/position-dodge.r @@ -144,7 +144,7 @@ PositionDodge <- ggproto("PositionDodge", Position, # Assumes that each set has the same horizontal position. pos_dodge <- function(df, width, n = NULL) { if (is.null(n)) { - n <- length(unique(df$group)) + n <- length(unique0(df$group)) } if (n == 1) @@ -159,7 +159,7 @@ pos_dodge <- function(df, width, n = NULL) { # Have a new group index from 1 to number of groups. # This might be needed if the group numbers in this set don't include all of 1:n - groupidx <- match(df$group, sort(unique(df$group))) + groupidx <- match(df$group, sort(unique0(df$group))) # Find the center for each group, then use that to calculate xmin and xmax df$x <- df$x + width * ((groupidx - 0.5) / n - .5) diff --git a/R/position-jitter.r b/R/position-jitter.r index 2c6d78323a..66f4694cad 100644 --- a/R/position-jitter.r +++ b/R/position-jitter.r @@ -83,7 +83,7 @@ PositionJitter <- ggproto("PositionJitter", Position, x <- if (length(x_aes) == 0) 0 else data[[x_aes[1]]] y_aes <- intersect(ggplot_global$y_aes, names(data)) y <- if (length(y_aes) == 0) 0 else data[[y_aes[1]]] - dummy_data <- new_data_frame(list(x = x, y = y), nrow(data)) + dummy_data <- data_frame0(x = x, y = y, .size = nrow(data)) fixed_jitter <- with_seed_null(params$seed, transform_position(dummy_data, trans_x, trans_y)) x_jit <- fixed_jitter$x - x y_jit <- fixed_jitter$y - y diff --git a/R/position-jitterdodge.R b/R/position-jitterdodge.R index 6418908675..8705d3b023 100644 --- a/R/position-jitterdodge.R +++ b/R/position-jitterdodge.R @@ -53,7 +53,7 @@ PositionJitterdodge <- ggproto("PositionJitterdodge", Position, cli::cli_abort("{.fn position_jitterdodge} requires at least one aesthetic to dodge by") } ndodge <- lapply(data[dodgecols], levels) # returns NULL for numeric, i.e. non-dodge layers - ndodge <- length(unique(unlist(ndodge))) + ndodge <- length(unique0(unlist(ndodge))) list( dodge.width = self$dodge.width, diff --git a/R/position-stack.r b/R/position-stack.r index 6c327e4b84..5d0dae7015 100644 --- a/R/position-stack.r +++ b/R/position-stack.r @@ -210,7 +210,7 @@ PositionStack <- ggproto("PositionStack", Position, ) } - data <- rbind(neg, pos)[match(seq_len(nrow(data)), c(which(negative), which(!negative))),] + data <- vec_rbind(neg, pos)[match(seq_len(nrow(data)), c(which(negative), which(!negative))),] flip_data(data, params$flipped_aes) } ) diff --git a/R/quick-plot.r b/R/quick-plot.r index a6c6a956e9..60be9e9a3c 100644 --- a/R/quick-plot.r +++ b/R/quick-plot.r @@ -106,7 +106,7 @@ qplot <- function(x, y, ..., data, facets = NULL, margins = FALSE, if (missing(data)) { # If data not explicitly specified, will be pulled from workspace - data <- new_data_frame() + data <- data_frame0() # Faceting variables must be in a data frame, so pull those out facetvars <- all.vars(facets) diff --git a/R/reshape-add-margins.R b/R/reshape-add-margins.R index 196d47ad1e..c7b17ea025 100644 --- a/R/reshape-add-margins.R +++ b/R/reshape-add-margins.R @@ -10,7 +10,7 @@ reshape_add_margins <- function(df, vars, margins = TRUE) { x <- addNA(x, TRUE) factor(x, levels = c(levels(x), "(all)"), exclude = NULL) } - vars <- unique(unlist(margin_vars)) + vars <- unique0(unlist(margin_vars)) df[vars] <- lapply(df[vars], addAll) rownames(df) <- NULL @@ -22,7 +22,7 @@ reshape_add_margins <- function(df, vars, margins = TRUE) { df }) - do.call("rbind", margin_dfs) + vec_rbind(!!!margin_dfs) } reshape_margins <- function(vars, margins = NULL) { diff --git a/R/save.r b/R/save.r index 06ec8b5353..c975d83cc6 100644 --- a/R/save.r +++ b/R/save.r @@ -173,7 +173,8 @@ plot_dev <- function(device, filename = NULL, dpi = 300, call = caller_env()) { if ("units" %in% names(args)) { call_args$units <- 'in' } - dev <- function(...) do.call(device, modify_list(list(...), call_args)) + args <- modify_list(list(...), call_args) + dev <- function(...) inject(device(!!!args)) return(dev) } diff --git a/R/scale-.r b/R/scale-.r index ca33fe11a7..f8f20f9842 100644 --- a/R/scale-.r +++ b/R/scale-.r @@ -599,7 +599,7 @@ ScaleContinuous <- ggproto("ScaleContinuous", Scale, map = function(self, x, limits = self$get_limits()) { x <- self$rescale(self$oob(x, range = limits), limits) - uniq <- unique(x) + uniq <- unique0(x) pal <- self$palette(uniq) scaled <- pal[match(x, uniq)] @@ -739,7 +739,7 @@ ScaleContinuous <- ggproto("ScaleContinuous", Scale, labels <- lapply(labels, `[`, 1) if (any(vapply(labels, is.language, logical(1)))) { - labels <- do.call(expression, labels) + labels <- inject(expression(!!!labels)) } else { labels <- unlist(labels) } @@ -1013,7 +1013,7 @@ ScaleBinned <- ggproto("ScaleBinned", Scale, x } else { breaks <- self$get_breaks(limits) - breaks <- sort(unique(c(limits[1], breaks, limits[2]))) + breaks <- sort(unique0(c(limits[1], breaks, limits[2]))) x <- self$rescale(self$oob(x, range = limits), limits) breaks <- self$rescale(breaks, limits) @@ -1158,7 +1158,7 @@ ScaleBinned <- ggproto("ScaleBinned", Scale, if (self$show.limits) { limits <- self$get_limits() - major <- sort(unique(c(limits, major))) + major <- sort(unique0(c(limits, major))) } # labels diff --git a/R/scale-binned.R b/R/scale-binned.R index 615bd9424a..f599c1b500 100644 --- a/R/scale-binned.R +++ b/R/scale-binned.R @@ -70,7 +70,7 @@ ScaleBinnedPosition <- ggproto("ScaleBinnedPosition", ScaleBinned, map = function(self, x, limits = self$get_limits()) { breaks <- self$get_breaks(limits) - all_breaks <- unique(sort(c(limits[1], breaks, limits[2]))) + all_breaks <- unique0(sort(c(limits[1], breaks, limits[2]))) if (self$after.stat) { # Backtransform to original scale @@ -103,7 +103,7 @@ ScaleBinnedPosition <- ggproto("ScaleBinnedPosition", ScaleBinned, get_breaks = function(self, limits = self$get_limits()) { breaks <- ggproto_parent(ScaleBinned, self)$get_breaks(limits) if (self$show.limits) { - breaks <- sort(unique(c(self$get_limits(), breaks))) + breaks <- sort(unique0(c(self$get_limits(), breaks))) } breaks } diff --git a/R/scale-discrete-.r b/R/scale-discrete-.r index 018cd514de..11ec374937 100644 --- a/R/scale-discrete-.r +++ b/R/scale-discrete-.r @@ -122,7 +122,7 @@ ScaleDiscretePosition <- ggproto("ScaleDiscretePosition", ScaleDiscrete, if (is.discrete(x)) { x <- seq_along(limits)[match(as.character(x), limits)] } - new_mapped_discrete(x) + mapped_discrete(x) }, rescale = function(self, x, limits = self$get_limits(), range = self$dimension(limits = limits)) { @@ -141,35 +141,96 @@ ScaleDiscretePosition <- ggproto("ScaleDiscretePosition", ScaleDiscrete, } ) -# TODO: This is a clear candidate for vctrs once we adopt it -new_mapped_discrete <- function(x) { - if (is.null(x)) { - return(x) - } - if (!is.numeric(x)) { - cli::cli_abort("{.cls mapped_discrete} objects can only be created from numeric vectors") - } - class(x) <- c("mapped_discrete", "numeric") - x +new_mapped_discrete <- function(x = double()) { + vec_assert(x, double()) + obj <- new_vctr(x, class = "ggplot2_mapped_discrete") + # vctrs does not support inheriting from numeric base class + class(obj) <- c(class(obj), "numeric") + obj +} +mapped_discrete <- function(x = double()) { + if (is.null(x)) return(NULL) + if (is.array(x)) x <- as.vector(x) + new_mapped_discrete(vec_cast(x, double())) +} +is_mapped_discrete <- function(x) inherits(x, "ggplot2_mapped_discrete") +#' @export +format.ggplot2_mapped_discrete <- function(x, ...) format(vec_data(x), ...) +#' @export +vec_ptype2.ggplot2_mapped_discrete.ggplot2_mapped_discrete <- function(x, y, ...) new_mapped_discrete() +#' @export +vec_ptype2.ggplot2_mapped_discrete.double <- function(x, y, ...) new_mapped_discrete() +#' @export +vec_ptype2.double.ggplot2_mapped_discrete <- function(x, y, ...) new_mapped_discrete() +#' @export +vec_ptype2.ggplot2_mapped_discrete.integer <- function(x, y, ...) new_mapped_discrete() +#' @export +vec_ptype2.integer.ggplot2_mapped_discrete <- function(x, y, ...) new_mapped_discrete() +#' @export +vec_ptype2.ggplot2_mapped_discrete.character <- function(x, y, ...) character() +#' @export +vec_ptype2.character.ggplot2_mapped_discrete <- function(x, y, ...) character() +#' @export +vec_ptype2.ggplot2_mapped_discrete.factor <- function(x, y, ...) new_mapped_discrete() +#' @export +vec_ptype2.factor.ggplot2_mapped_discrete <- function(x, y, ...) new_mapped_discrete() +#' @export +vec_cast.ggplot2_mapped_discrete.ggplot2_mapped_discrete <- function(x, to, ...) x +#' @export +vec_cast.ggplot2_mapped_discrete.integer <- function(x, to, ...) mapped_discrete(x) +#' @export +vec_cast.integer.ggplot2_mapped_discrete <- function(x, to, ...) as.integer(vec_data(x)) +#' @export +vec_cast.ggplot2_mapped_discrete.double <- function(x, to, ...) new_mapped_discrete(x) +#' @export +vec_cast.double.ggplot2_mapped_discrete <- function(x, to, ...) vec_data(x) +#' @export +vec_cast.character.ggplot2_mapped_discrete <- function(x, to, ...) as.character(vec_data(x)) +#' @export +vec_cast.ggplot2_mapped_discrete.factor <- function(x, to, ...) mapped_discrete(unclass(x)) +#' @export +vec_cast.factor.ggplot2_mapped_discrete <- function(x, to, ...) factor(vec_data(x), ...) +#' Utilities for working with discrete values mapped to numeric domain +#' +#' @param op The operator to apply +#' @param x,y items to apply the operator to +#' @param ... passed on +#' @export vec_arith.ggplot2_mapped_discrete +#' @method vec_arith ggplot2_mapped_discrete +#' +#' @keywords internal +#' @export +vec_arith.ggplot2_mapped_discrete <- function(op, x, y, ...) { + UseMethod("vec_arith.ggplot2_mapped_discrete", y) } -is_mapped_discrete <- function(x) inherits(x, "mapped_discrete") #' @export -c.mapped_discrete <- function(..., recursive = FALSE) { - new_mapped_discrete(c(unlist(lapply(list(...), unclass)))) +#' @method vec_arith.ggplot2_mapped_discrete default +vec_arith.ggplot2_mapped_discrete.default <- function(op, x, y, ...) { + stop_incompatible_op(op, x, y) } #' @export -`[.mapped_discrete` <- function(x, ..., drop = TRUE) { - new_mapped_discrete(NextMethod()) +#' @method vec_arith.ggplot2_mapped_discrete ggplot2_mapped_discrete +vec_arith.ggplot2_mapped_discrete.ggplot2_mapped_discrete <- function(op, x, y, ...) { + mapped_discrete(vec_arith_base(op, x, y)) } #' @export -`[<-.mapped_discrete` <- function(x, ..., value) { - if (length(value) == 0) { - return(x) - } - value <- as.numeric(unclass(value)) - new_mapped_discrete(NextMethod()) +#' @method vec_arith.ggplot2_mapped_discrete numeric +vec_arith.ggplot2_mapped_discrete.numeric <- function(op, x, y, ...) { + mapped_discrete(vec_arith_base(op, x, y)) +} +#' @export +#' @method vec_arith.numeric ggplot2_mapped_discrete +vec_arith.numeric.ggplot2_mapped_discrete <- function(op, x, y, ...) { + mapped_discrete(vec_arith_base(op, x, y)) +} +#' @export +#' @method vec_arith.ggplot2_mapped_discrete MISSING +vec_arith.ggplot2_mapped_discrete.MISSING <- function(op, x, y, ...) { + op_fn <- getExportedValue("base", op) + mapped_discrete(op_fn(vec_data(x))) } #' @export -as.data.frame.mapped_discrete <- function (x, ...) { - as.data.frame.vector(x = unclass(x), ...) +vec_math.ggplot2_mapped_discrete <- function(.fn, .x, ...) { + res <- vec_math_base(.fn, .x, ...) + if (is.numeric(res)) mapped_discrete(res) else res } diff --git a/R/scales-.r b/R/scales-.r index ebe28d39c4..1537ff0f65 100644 --- a/R/scales-.r +++ b/R/scales-.r @@ -75,7 +75,7 @@ scales_map_df <- function(scales, df) { mapped <- unlist(lapply(scales$scales, function(scale) scale$map_df(df = df)), recursive = FALSE) - new_data_frame(c(mapped, df[setdiff(names(df), names(mapped))])) + data_frame0(!!!mapped, df[setdiff(names(df), names(mapped))]) } # Transform values to cardinal representation @@ -94,7 +94,8 @@ scales_transform_df <- function(scales, df) { transformed <- unlist(lapply(scale_list, function(s) s$transform_df(df = df)), recursive = FALSE) - new_data_frame(c(transformed, df[setdiff(names(df), names(transformed))])) + untransformed <- df[setdiff(names(df), names(transformed))] + data_frame0(!!!transformed, untransformed) } scales_backtransform_df <- function(scales, df) { diff --git a/R/stat-.r b/R/stat-.r index 5d03ae859a..6460515077 100644 --- a/R/stat-.r +++ b/R/stat-.r @@ -97,15 +97,18 @@ Stat <- ggproto("Stat", args <- c(list(data = quote(data), scales = quote(scales)), params) dapply(data, "PANEL", function(data) { scales <- layout$get_scales(data$PANEL[1]) - try_fetch(do.call(self$compute_panel, args), error = function(cnd) { - cli::cli_warn("Computation failed in {.fn {snake_class(self)}}", parent = cnd) - new_data_frame() - }) + try_fetch( + inject(self$compute_panel(data = data, scales = scales, !!!params)), + error = function(cnd) { + cli::cli_warn("Computation failed in {.fn {snake_class(self)}}", parent = cnd) + data_frame0() + } + ) }) }, compute_panel = function(self, data, scales, ...) { - if (empty(data)) return(new_data_frame()) + if (empty(data)) return(data_frame0()) groups <- split(data, data$group) stats <- lapply(groups, function(group) { @@ -113,16 +116,16 @@ Stat <- ggproto("Stat", }) stats <- mapply(function(new, old) { - if (empty(new)) return(new_data_frame()) + if (empty(new)) return(data_frame0()) unique <- uniquecols(old) missing <- !(names(unique) %in% names(new)) - cbind( + vec_cbind( new, unique[rep(1, nrow(new)), missing,drop = FALSE] ) }, stats, groups, SIMPLIFY = FALSE) - rbind_dfs(stats) + vec_rbind(!!!stats) }, compute_group = function(self, data, scales) { diff --git a/R/stat-bin.r b/R/stat-bin.r index 71bef6ae32..07f76b1557 100644 --- a/R/stat-bin.r +++ b/R/stat-bin.r @@ -97,7 +97,7 @@ StatBin <- ggproto("StatBin", Stat, } x <- flipped_names(params$flipped_aes)$x - if (is.integer(data[[x]])) { + if (is_mapped_discrete(data[[x]])) { cli::cli_abort(c( "{.fn {snake_class(self)}} requires a continuous {.field {x}} aesthetic", "x" = "the {.field {x}} aesthetic is discrete.", diff --git a/R/stat-bindot.r b/R/stat-bindot.r index edd11ae949..edba5bae20 100644 --- a/R/stat-bindot.r +++ b/R/stat-bindot.r @@ -99,10 +99,11 @@ StatBindot <- ggproto("StatBindot", Stat, # Collapse each bin and get a count data <- dapply(data, "bincenter", function(x) { - new_data_frame(list( + data_frame0( binwidth = .subset2(x, "binwidth")[1], - count = sum(.subset2(x, "weight")) - )) + count = sum(.subset2(x, "weight")), + .size = 1 + ) }) if (sum(data$count, na.rm = TRUE) != 0) { @@ -130,7 +131,7 @@ StatBindot <- ggproto("StatBindot", Stat, # It returns a data frame with the original data (x), weights, bin #, and the bin centers. densitybin <- function(x, weight = NULL, binwidth = NULL, method = method, range = NULL) { - if (length(stats::na.omit(x)) == 0) return(new_data_frame()) + if (length(stats::na.omit(x)) == 0) return(data_frame0()) if (is.null(weight)) weight <- rep(1, length(x)) weight[is.na(weight)] <- 0 @@ -156,16 +157,17 @@ densitybin <- function(x, weight = NULL, binwidth = NULL, method = method, range bin[i] <- cbin } - results <- new_data_frame(list( + results <- data_frame0( x = x, bin = bin, binwidth = binwidth, - weight = weight - ), n = length(x)) + weight = weight, + .size = length(x) + ) results <- dapply(results, "bin", function(df) { - df$bincenter = (min(df$x) + max(df$x)) / 2 - return(df) - }) + df$bincenter = (min(df$x) + max(df$x)) / 2 + return(df) + }) return(results) } diff --git a/R/stat-boxplot.r b/R/stat-boxplot.r index 8d951e1654..83f092902e 100644 --- a/R/stat-boxplot.r +++ b/R/stat-boxplot.r @@ -103,10 +103,10 @@ StatBoxplot <- ggproto("StatBoxplot", Stat, stats[c(1, 5)] <- range(c(stats[2:4], data$y[!outliers]), na.rm = TRUE) } - if (length(unique(data$x)) > 1) + if (length(unique0(data$x)) > 1) width <- diff(range(data$x)) * 0.9 - df <- new_data_frame(as.list(stats)) + df <- data_frame0(!!!as.list(stats)) df$outliers <- list(data$y[outliers]) if (is.null(data$weight)) { diff --git a/R/stat-contour.r b/R/stat-contour.r index 4737a283e5..54b99583e8 100644 --- a/R/stat-contour.r +++ b/R/stat-contour.r @@ -201,8 +201,8 @@ contour_breaks <- function(z_range, bins = NULL, binwidth = NULL, breaks = NULL) #' xyz_to_isolines <- function(data, breaks) { isoband::isolines( - x = sort(unique(data$x)), - y = sort(unique(data$y)), + x = sort(unique0(data$x)), + y = sort(unique0(data$y)), z = isoband_z_matrix(data), levels = breaks ) @@ -210,8 +210,8 @@ xyz_to_isolines <- function(data, breaks) { xyz_to_isobands <- function(data, breaks) { isoband::isobands( - x = sort(unique(data$x)), - y = sort(unique(data$y)), + x = sort(unique0(data$x)), + y = sort(unique0(data$y)), z = isoband_z_matrix(data), levels_low = breaks[-length(breaks)], levels_high = breaks[-1] @@ -230,8 +230,8 @@ xyz_to_isobands <- function(data, breaks) { #' isoband_z_matrix <- function(data) { # Convert vector of data to raster - x_pos <- as.integer(factor(data$x, levels = sort(unique(data$x)))) - y_pos <- as.integer(factor(data$y, levels = sort(unique(data$y)))) + x_pos <- as.integer(factor(data$x, levels = sort(unique0(data$x)))) + y_pos <- as.integer(factor(data$y, levels = sort(unique0(data$y)))) nrow <- max(y_pos) ncol <- max(x_pos) @@ -255,7 +255,7 @@ iso_to_path <- function(iso, group = 1) { if (all(lengths == 0)) { cli::cli_warn("{.fn stat_contour}: Zero contours were generated") - return(new_data_frame()) + return(data_frame0()) } levels <- names(iso) @@ -268,15 +268,13 @@ iso_to_path <- function(iso, group = 1) { groups <- paste(group, sprintf("%03d", item_id), sprintf("%03d", ids), sep = "-") groups <- factor(groups) - new_data_frame( - list( - level = rep(levels, lengths), - x = xs, - y = ys, - piece = as.integer(groups), - group = groups - ), - n = length(xs) + data_frame0( + level = rep(levels, lengths), + x = xs, + y = ys, + piece = as.integer(groups), + group = groups, + .size = length(xs) ) } @@ -293,7 +291,7 @@ iso_to_polygon <- function(iso, group = 1) { if (all(lengths == 0)) { cli::cli_warn("{.fn stat_contour}: Zero contours were generated") - return(new_data_frame()) + return(data_frame0()) } levels <- names(iso) @@ -306,16 +304,14 @@ iso_to_polygon <- function(iso, group = 1) { groups <- paste(group, sprintf("%03d", item_id), sep = "-") groups <- factor(groups) - new_data_frame( - list( - level = rep(levels, lengths), - x = xs, - y = ys, - piece = as.integer(groups), - group = groups, - subgroup = ids - ), - n = length(xs) + data_frame0( + level = rep(levels, lengths), + x = xs, + y = ys, + piece = as.integer(groups), + group = groups, + subgroup = ids, + .size = length(xs) ) } diff --git a/R/stat-count.r b/R/stat-count.r index 6a2f41ce5b..9a4aa47680 100644 --- a/R/stat-count.r +++ b/R/stat-count.r @@ -79,13 +79,14 @@ StatCount <- ggproto("StatCount", Stat, count <- as.numeric(tapply(weight, x, sum, na.rm = TRUE)) count[is.na(count)] <- 0 - bars <- new_data_frame(list( + bars <- data_frame0( count = count, prop = count / sum(abs(count)), - x = sort(unique(x)), + x = sort(unique0(x)), width = width, - flipped_aes = flipped_aes - ), n = length(count)) + flipped_aes = flipped_aes, + .size = length(count) + ) flip_data(bars, flipped_aes) } ) diff --git a/R/stat-density-2d.r b/R/stat-density-2d.r index 250da2cfd1..bae1320f64 100644 --- a/R/stat-density-2d.r +++ b/R/stat-density-2d.r @@ -150,13 +150,15 @@ StatDensity2d <- ggproto("StatDensity2d", Stat, contour_stat <- StatContour } - args <- c(list(data = quote(data), scales = quote(scales)), params) dapply(data, "PANEL", function(data) { scales <- layout$get_scales(data$PANEL[1]) - try_fetch(do.call(contour_stat$compute_panel, args), error = function(cnd) { - cli::cli_warn("Computation failed in {.fn {snake_class(self)}}", parent = cnd) - new_data_frame() - }) + try_fetch( + inject(contour_stat$compute_panel(data = data, scales = scales, !!!params)), + error = function(cnd) { + cli::cli_warn("Computation failed in {.fn {snake_class(self)}}", parent = cnd) + data_frame0() + } + ) }) }, diff --git a/R/stat-density.r b/R/stat-density.r index 5029c68bc8..c712d921fb 100644 --- a/R/stat-density.r +++ b/R/stat-density.r @@ -113,25 +113,27 @@ compute_density <- function(x, w, from, to, bw = "nrd0", adjust = 1, # if less than 2 points return data frame of NAs and a warning if (nx < 2) { cli::cli_warn("Groups with fewer than two data points have been dropped.") - return(new_data_frame(list( + return(data_frame0( x = NA_real_, density = NA_real_, scaled = NA_real_, ndensity = NA_real_, count = NA_real_, - n = NA_integer_ - ), n = 1)) + n = NA_integer_, + .size = 1 + )) } dens <- stats::density(x, weights = w, bw = bw, adjust = adjust, kernel = kernel, n = n, from = from, to = to) - new_data_frame(list( + data_frame0( x = dens$x, density = dens$y, scaled = dens$y / max(dens$y, na.rm = TRUE), ndensity = dens$y / max(dens$y, na.rm = TRUE), count = dens$y * nx, - n = nx - ), n = length(dens$x)) + n = nx, + .size = length(dens$x) + ) } diff --git a/R/stat-ecdf.r b/R/stat-ecdf.r index 9d5a1ca6b5..4a9daccc45 100644 --- a/R/stat-ecdf.r +++ b/R/stat-ecdf.r @@ -92,7 +92,7 @@ StatEcdf <- ggproto("StatEcdf", Stat, data <- flip_data(data, flipped_aes) # If n is NULL, use raw values; otherwise interpolate if (is.null(n)) { - x <- unique(data$x) + x <- unique0(data$x) } else { x <- seq(min(data$x), max(data$x), length.out = n) } @@ -102,7 +102,11 @@ StatEcdf <- ggproto("StatEcdf", Stat, } data_ecdf <- ecdf(data$x)(x) - df_ecdf <- new_data_frame(list(x = x, y = data_ecdf), n = length(x)) + df_ecdf <- data_frame0( + x = x, + y = data_ecdf, + .size = length(x) + ) df_ecdf$flipped_aes <- flipped_aes flip_data(df_ecdf, flipped_aes) } diff --git a/R/stat-ellipse.R b/R/stat-ellipse.R index 0039ea9792..d295973b35 100644 --- a/R/stat-ellipse.R +++ b/R/stat-ellipse.R @@ -87,10 +87,10 @@ calculate_ellipse <- function(data, vars, type, level, segments){ if (!type %in% c("t", "norm", "euclid")) { cli::cli_inform("Unrecognized ellipse type") - ellipse <- rbind(as.numeric(c(NA, NA))) + ellipse <- matrix(NA_real_, ncol = 2) } else if (dfd < 3) { cli::cli_inform("Too few points to calculate an ellipse") - ellipse <- rbind(as.numeric(c(NA, NA))) + ellipse <- matrix(NA_real_, ncol = 2) } else { if (type == "t") { v <- MASS::cov.trob(data[,vars]) diff --git a/R/stat-function.r b/R/stat-function.r index e74a06c0a0..8e57e96ded 100644 --- a/R/stat-function.r +++ b/R/stat-function.r @@ -74,16 +74,13 @@ StatFunction <- ggproto("StatFunction", Stat, if (is.formula(fun)) fun <- as_function(fun) - y_out <- do.call(fun, c(list(quote(x_trans)), args)) + y_out <- inject(fun(x_trans, !!!args)) if (!is.null(scales$y) && !scales$y$is_discrete()) { # For continuous scales, need to apply transform y_out <- scales$y$trans$transform(y_out) } - new_data_frame(list( - x = xseq, - y = y_out - )) + data_frame0(x = xseq, y = y_out) } ) @@ -93,7 +90,7 @@ StatFunction <- ggproto("StatFunction", Stat, # input data that may have been provided. ensure_nonempty_data <- function(data) { if (empty(data)) { - new_data_frame(list(group = 1), n = 1) + data_frame0(group = 1, .size = 1) } else { data } diff --git a/R/stat-qq-line.R b/R/stat-qq-line.R index 54bb1bd747..e1a95ebe69 100644 --- a/R/stat-qq-line.R +++ b/R/stat-qq-line.R @@ -67,16 +67,13 @@ StatQqLine <- ggproto("StatQqLine", Stat, cli::cli_abort("{.arg quantiles} must have the same length as the data") } - theoretical <- do.call( - distribution, - c(list(p = quote(quantiles)), dparams) - ) + theoretical <- inject(distribution(p = quantiles, !!!dparams)) if (length(line.p) != 2) { cli::cli_abort("Cannot fit line quantiles {line.p}. {.arg line.p} must have length 2.") } - x_coords <- do.call(distribution, c(list(p = line.p), dparams)) + x_coords <- inject(distribution(p = line.p, !!!dparams)) y_coords <- quantile(sample, line.p) slope <- diff(y_coords) / diff(x_coords) intercept <- y_coords[1L] - slope * x_coords[1L] @@ -87,6 +84,6 @@ StatQqLine <- ggproto("StatQqLine", Stat, x <- range(theoretical) } - new_data_frame(list(x = x, y = slope * x + intercept)) + data_frame0(x = x, y = slope * x + intercept) } ) diff --git a/R/stat-qq.r b/R/stat-qq.r index 4992ef4fe6..55dfd4c3d2 100644 --- a/R/stat-qq.r +++ b/R/stat-qq.r @@ -97,8 +97,8 @@ StatQq <- ggproto("StatQq", Stat, cli::cli_abort("The length of {.arg quantiles} must match the length of the data") } - theoretical <- do.call(distribution, c(list(p = quote(quantiles)), dparams)) + theoretical <- inject(distribution(p = quantiles, !!!dparams)) - new_data_frame(list(sample = sample, theoretical = theoretical)) + data_frame0(sample = sample, theoretical = theoretical) } ) diff --git a/R/stat-quantile.r b/R/stat-quantile.r index acb6c64338..ffecc6ead8 100644 --- a/R/stat-quantile.r +++ b/R/stat-quantile.r @@ -74,7 +74,7 @@ StatQuantile <- ggproto("StatQuantile", Stat, xmax <- max(data$x, na.rm = TRUE) xseq <- seq(xmin, xmax, length.out = 100) } - grid <- new_data_frame(list(x = xseq)) + grid <- data_frame0(x = xseq, .size = length(xseq)) # if method was specified as a character string, replace with # the corresponding function @@ -86,16 +86,29 @@ StatQuantile <- ggproto("StatQuantile", Stat, method <- match.fun(method) # allow users to supply their own methods } - rbind_dfs(lapply(quantiles, quant_pred, data = data, method = method, - formula = formula, weight = weight, grid = grid, method.args = method.args)) + result <- lapply( + quantiles, + quant_pred, + data = data, + method = method, + formula = formula, + weight = weight, + grid = grid, + method.args = method.args + ) + vec_rbind(!!!result) } ) quant_pred <- function(quantile, data, method, formula, weight, grid, method.args = method.args) { - args <- c(list(quote(formula), data = quote(data), tau = quote(quantile), - weights = quote(weight)), method.args) - model <- do.call(method, args) + model <- inject(method( + formula, + data = data, + tau = quantile, + weights = weight, + !!!method.args + )) grid$y <- stats::predict(model, newdata = grid) grid$quantile <- quantile diff --git a/R/stat-smooth-methods.r b/R/stat-smooth-methods.r index db6d9fe2fd..77d50cdff3 100644 --- a/R/stat-smooth-methods.r +++ b/R/stat-smooth-methods.r @@ -10,8 +10,13 @@ predictdf <- function(model, xseq, se, level) UseMethod("predictdf") #' @export predictdf.default <- function(model, xseq, se, level) { - pred <- stats::predict(model, newdata = new_data_frame(list(x = xseq)), se.fit = se, - level = level, interval = if (se) "confidence" else "none") + pred <- stats::predict( + model, + newdata = data_frame0(x = xseq), + se.fit = se, + level = level, + interval = if (se) "confidence" else "none" + ) if (se) { fit <- as.data.frame(pred$fit) @@ -24,8 +29,12 @@ predictdf.default <- function(model, xseq, se, level) { #' @export predictdf.glm <- function(model, xseq, se, level) { - pred <- stats::predict(model, newdata = data_frame(x = xseq), se.fit = se, - type = "link") + pred <- stats::predict( + model, + newdata = data_frame0(x = xseq), + se.fit = se, + type = "link" + ) if (se) { std <- stats::qnorm(level / 2 + 0.5) @@ -43,7 +52,11 @@ predictdf.glm <- function(model, xseq, se, level) { #' @export predictdf.loess <- function(model, xseq, se, level) { - pred <- stats::predict(model, newdata = data_frame(x = xseq), se = se) + pred <- stats::predict( + model, + newdata = data_frame0(x = xseq), + se = se + ) if (se) { y <- pred$fit @@ -58,7 +71,11 @@ predictdf.loess <- function(model, xseq, se, level) { #' @export predictdf.locfit <- function(model, xseq, se, level) { - pred <- stats::predict(model, newdata = data_frame(x = xseq), se.fit = se) + pred <- stats::predict( + model, + newdata = data_frame0(x = xseq), + se.fit = se + ) if (se) { y <- pred$fit diff --git a/R/stat-smooth.r b/R/stat-smooth.r index 97781d381a..aad4dccf91 100644 --- a/R/stat-smooth.r +++ b/R/stat-smooth.r @@ -129,9 +129,9 @@ StatSmooth <- ggproto("StatSmooth", Stat, xseq = NULL, level = 0.95, method.args = list(), na.rm = FALSE, flipped_aes = NA) { data <- flip_data(data, flipped_aes) - if (length(unique(data$x)) < 2) { + if (length(unique0(data$x)) < 2) { # Not enough data to perform fit - return(new_data_frame()) + return(data_frame0()) } if (is.null(data$weight)) data$weight <- 1 @@ -141,7 +141,7 @@ StatSmooth <- ggproto("StatSmooth", Stat, if (fullrange) { xseq <- scales$x$dimension() } else { - xseq <- sort(unique(data$x)) + xseq <- sort(unique0(data$x)) } } else { if (fullrange) { @@ -170,8 +170,12 @@ StatSmooth <- ggproto("StatSmooth", Stat, method.args$method <- "REML" } - base.args <- list(quote(formula), data = quote(data), weights = quote(weight)) - model <- do.call(method, c(base.args, method.args)) + model <- inject(method( + formula, + data = data, + weights = weight, + !!!method.args + )) prediction <- predictdf(model, xseq, se, level) prediction$flipped_aes <- flipped_aes diff --git a/R/stat-summary-2d.r b/R/stat-summary-2d.r index 10af6521ec..8d366bcf54 100644 --- a/R/stat-summary-2d.r +++ b/R/stat-summary-2d.r @@ -102,7 +102,7 @@ StatSummary2d <- ggproto("StatSummary2d", Stat, fun <- as_function(fun) f <- function(x) { - do.call(fun, c(list(quote(x)), fun.args)) + inject(fun(x, !!!fun.args)) } out <- tapply_df(data$z, list(xbin = xbin, ybin = ybin), f, drop = drop) diff --git a/R/stat-summary-bin.R b/R/stat-summary-bin.R index 9f34fa46e2..cc6002b84e 100644 --- a/R/stat-summary-bin.R +++ b/R/stat-summary-bin.R @@ -100,7 +100,7 @@ make_summary_fun <- function(fun.data, fun, fun.max, fun.min, fun.args) { # Function that takes complete data frame as input fun.data <- as_function(fun.data) function(df) { - do.call(fun.data, c(list(quote(df$y)), fun.args)) + inject(fun.data(df$y, !!!fun.args)) } } else if (!is.null(fun) || !is.null(fun.max) || !is.null(fun.min)) { # Three functions that take vectors as inputs @@ -108,15 +108,15 @@ make_summary_fun <- function(fun.data, fun, fun.max, fun.min, fun.args) { call_f <- function(fun, x) { if (is.null(fun)) return(NA_real_) fun <- as_function(fun) - do.call(fun, c(list(quote(x)), fun.args)) + inject(fun(x, !!!fun.args)) } function(df, ...) { - new_data_frame(list( + data_frame0( ymin = call_f(fun.min, df$y), y = call_f(fun, df$y), ymax = call_f(fun.max, df$y) - )) + ) } } else { cli::cli_inform("No summary function supplied, defaulting to {.fn mean_se}") diff --git a/R/stat-summary.r b/R/stat-summary.r index ff4a96fe55..dc7f696adc 100644 --- a/R/stat-summary.r +++ b/R/stat-summary.r @@ -251,10 +251,10 @@ wrap_hmisc <- function(fun) { check_installed("Hmisc") fun <- getExportedValue("Hmisc", fun) - result <- do.call(fun, list(x = quote(x), ...)) + result <- fun(x = x, ...) rename( - new_data_frame(as.list(result)), + data_frame0(!!!as.list(result)), c(Median = "y", Mean = "y", Lower = "ymin", Upper = "ymax") ) } @@ -293,5 +293,10 @@ mean_se <- function(x, mult = 1) { x <- stats::na.omit(x) se <- mult * sqrt(stats::var(x) / length(x)) mean <- mean(x) - new_data_frame(list(y = mean, ymin = mean - se, ymax = mean + se), n = 1) + data_frame0( + y = mean, + ymin = mean - se, + ymax = mean + se, + .size = 1 + ) } diff --git a/R/stat-unique.r b/R/stat-unique.r index 2f9ec6ec30..38483a2d7b 100644 --- a/R/stat-unique.r +++ b/R/stat-unique.r @@ -35,5 +35,5 @@ stat_unique <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export StatUnique <- ggproto("StatUnique", Stat, - compute_panel = function(data, scales) unique(data) + compute_panel = function(data, scales) unique0(data) ) diff --git a/R/stat-ydensity.r b/R/stat-ydensity.r index d74b4f738b..5c7d1c3d9c 100644 --- a/R/stat-ydensity.r +++ b/R/stat-ydensity.r @@ -73,7 +73,7 @@ StatYdensity <- ggproto("StatYdensity", Stat, kernel = "gaussian", trim = TRUE, na.rm = FALSE, flipped_aes = FALSE) { if (nrow(data) < 2) { cli::cli_warn("Groups with fewer than two data points have been dropped.") - return(new_data_frame()) + return(data_frame0()) } range <- range(data$y, na.rm = TRUE) modifier <- if (trim) 0 else 3 @@ -85,7 +85,7 @@ StatYdensity <- ggproto("StatYdensity", Stat, dens$x <- mean(range(data$x)) # Compute width if x has multiple values - if (length(unique(data$x)) > 1) { + if (length(unique0(data$x)) > 1) { width <- diff(range(data$x)) * 0.9 } dens$width <- width diff --git a/R/theme-defaults.r b/R/theme-defaults.r index a97282ce1e..f1b261298f 100644 --- a/R/theme-defaults.r +++ b/R/theme-defaults.r @@ -669,5 +669,5 @@ theme_all_null <- function() { ) args <- c(elements, list(complete = TRUE)) - do.call(theme, args) + inject(theme(!!!args)) } diff --git a/R/utilities-matrix.r b/R/utilities-matrix.r index 2241ba74f8..dd35e082ba 100644 --- a/R/utilities-matrix.r +++ b/R/utilities-matrix.r @@ -15,26 +15,11 @@ cunion <- function(a, b) { interleave <- function(...) UseMethod("interleave") #' @export interleave.unit <- function(...) { - do.call("unit.c", do.call("interleave.default", lapply(list(...), as.list))) + units <- lapply(list(...), as.list) + interleaved_list <- interleave.default(!!!units) + inject(unit.c(!!!interleaved_list)) } #' @export interleave.default <- function(...) { - vectors <- list(...) - - # Check lengths - lengths <- unique(setdiff(vapply(vectors, length, integer(1)), 1L)) - if (length(lengths) == 0) lengths <- 1 - if (length(lengths) > 1) { - cli::cli_abort("vectors must have at least one element") - } - - # Replicate elements of length one up to correct length - singletons <- vapply(vectors, length, integer(1)) == 1L - vectors[singletons] <- lapply(vectors[singletons], rep, lengths) - - # Interleave vectors - n <- lengths - p <- length(vectors) - interleave <- rep(1:n, each = p) + seq(0, p - 1) * n - unlist(vectors, recursive = FALSE)[interleave] + vec_interleave(...) } diff --git a/R/utilities-resolution.r b/R/utilities-resolution.r index 85d69972fe..e7230f3863 100644 --- a/R/utilities-resolution.r +++ b/R/utilities-resolution.r @@ -21,9 +21,9 @@ resolution <- function(x, zero = TRUE) { if (is.integer(x) || zero_range(range(x, na.rm = TRUE))) return(1) - x <- unique(as.numeric(x)) + x <- unique0(as.numeric(x)) if (zero) { - x <- unique(c(0, x)) + x <- unique0(c(0, x)) } min(diff(sort(x))) diff --git a/R/utilities-table.r b/R/utilities-table.r index 76d87d15ba..77d7e83407 100644 --- a/R/utilities-table.r +++ b/R/utilities-table.r @@ -1,11 +1,13 @@ compute_grob_widths <- function(grob_layout, widths) { cols <- split(grob_layout, grob_layout$l) - do.call("unit.c", lapply(cols, compute_grob_dimensions, dims = widths)) + widths <- lapply(cols, compute_grob_dimensions, dims = widths) + inject(unit.c(!!!widths)) } compute_grob_heights <- function(grob_layout, heights) { cols <- split(grob_layout, grob_layout$t) - do.call("unit.c", lapply(cols, compute_grob_dimensions, dims = heights)) + heights <- lapply(cols, compute_grob_dimensions, dims = heights) + inject(unit.c(!!!heights)) } compute_grob_dimensions <- function(grob_layout, dims) { @@ -16,7 +18,7 @@ compute_grob_dimensions <- function(grob_layout, dims) { grob_layout <- grob_layout[grob_layout$type %in% names(dims), , drop = FALSE] - dims <- unique(Map(function(type, pos) { + dims <- unique0(Map(function(type, pos) { type_width <- dims[[type]] if (length(type_width) == 1) type_width else type_width[pos] }, grob_layout$type, grob_layout$id)) @@ -24,11 +26,11 @@ compute_grob_dimensions <- function(grob_layout, dims) { if (all(units)) { if (all(lapply(dims, attr, "unit") == "null")) unit(max(unlist(dims)), "null") - else do.call("max", dims) + else inject(max(!!!dims)) } else { raw_max <- unit(max(unlist(dims[!units])), "cm") if (any(units)) { - unit_max <- max(do.call("unit.c", dims[units])) + unit_max <- max(inject(unit.c(!!!dims[units]))) max(raw_max, unit_max) } else { diff --git a/R/utilities.r b/R/utilities.r index 6c8ecab715..318e7124ad 100644 --- a/R/utilities.r +++ b/R/utilities.r @@ -61,7 +61,7 @@ clist <- function(l) { # # @keyword internal uniquecols <- function(df) { - df <- df[1, sapply(df, function(x) length(unique(x)) == 1), drop = FALSE] + df <- df[1, sapply(df, function(x) length(unique0(x)) == 1), drop = FALSE] rownames(df) <- 1:nrow(df) df } @@ -326,7 +326,7 @@ find_args <- function(...) { # Used in annotations to ensure printed even when no # global data -dummy_data <- function() new_data_frame(list(x = NA), n = 1) +dummy_data <- function() data_frame0(x = NA, .size = 1) with_seed_null <- function(seed, code) { if (is.null(seed)) { @@ -348,10 +348,16 @@ seq_asc <- function(to, from) { #' @importFrom tibble tibble NULL +# Wrapping vctrs data_frame constructor with no name repair +data_frame0 <- function(...) data_frame(..., .name_repair = "minimal") + +# Wrapping unique0() to accept NULL +unique0 <- function(x, ...) if (is.null(x)) x else vec_unique(x, ...) + # Check inputs with tibble but allow column vectors (see #2609 and #2374) as_gg_data_frame <- function(x) { x <- lapply(x, validate_column_vec) - new_data_frame(x) + data_frame0(!!!x) } validate_column_vec <- function(x) { if (is_column_vec(x)) { @@ -539,14 +545,14 @@ has_flipped_aes <- function(data, params = list(), main_is_orthogonal = NA, if (group_has_equal) { if (has_x) { if (length(x) == 1) return(FALSE) - x_groups <- vapply(split(data$x, data$group), function(x) length(unique(x)), integer(1)) + x_groups <- vapply(split(data$x, data$group), function(x) length(unique0(x)), integer(1)) if (all(x_groups == 1)) { return(FALSE) } } if (has_y) { if (length(y) == 1) return(TRUE) - y_groups <- vapply(split(data$y, data$group), function(x) length(unique(x)), integer(1)) + y_groups <- vapply(split(data$y, data$group), function(x) length(unique0(x)), integer(1)) if (all(y_groups == 1)) { return(TRUE) } diff --git a/man/vec_arith.ggplot2_mapped_discrete.Rd b/man/vec_arith.ggplot2_mapped_discrete.Rd new file mode 100644 index 0000000000..fd38b5d99f --- /dev/null +++ b/man/vec_arith.ggplot2_mapped_discrete.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/scale-discrete-.r +\name{vec_arith.ggplot2_mapped_discrete} +\alias{vec_arith.ggplot2_mapped_discrete} +\title{Utilities for working with discrete values mapped to numeric domain} +\usage{ +\method{vec_arith}{ggplot2_mapped_discrete}(op, x, y, ...) +} +\arguments{ +\item{op}{The operator to apply} + +\item{x, y}{items to apply the operator to} + +\item{...}{passed on} +} +\description{ +Utilities for working with discrete values mapped to numeric domain +} +\keyword{internal} diff --git a/tests/testthat/_snaps/geom-path.md b/tests/testthat/_snaps/geom-path.md index af6d86df60..e5c4d0eb4f 100644 --- a/tests/testthat/_snaps/geom-path.md +++ b/tests/testthat/_snaps/geom-path.md @@ -3,5 +3,5 @@ Problem while converting geom to grob. i Error occurred in the 1st layer. Caused by error in `draw_panel()`: - ! `geom_path()` can't have varying colour, size, and/or alpha along the line when linetype isn't solid + ! `geom_path()` can't have varying colour, linewidth, and/or alpha along the line when linetype isn't solid diff --git a/tests/testthat/_snaps/utilities.md b/tests/testthat/_snaps/utilities.md index 2df2d33d43..d8086c174d 100644 --- a/tests/testthat/_snaps/utilities.md +++ b/tests/testthat/_snaps/utilities.md @@ -52,5 +52,5 @@ # interleave() checks the vector lengths - vectors must have at least one element + Can't recycle `..1` (size 4) to match `..2` (size 0). diff --git a/tests/testthat/test-build.r b/tests/testthat/test-build.r index 24930a0373..7d112f8d4f 100644 --- a/tests/testthat/test-build.r +++ b/tests/testthat/test-build.r @@ -23,8 +23,8 @@ test_that("position aesthetics are coerced to correct type", { l2 <- ggplot(df, aes(x, z)) + geom_point() + scale_x_discrete() d2 <- layer_data(l2, 1) - expect_s3_class(d2$x, "mapped_discrete") - expect_s3_class(d2$y, "mapped_discrete") + expect_s3_class(d2$x, "ggplot2_mapped_discrete") + expect_s3_class(d2$y, "ggplot2_mapped_discrete") }) test_that("non-position aesthetics are mapped", { diff --git a/tests/testthat/test-coord-polar.r b/tests/testthat/test-coord-polar.r index c3b25ce2fa..f1570b6a96 100644 --- a/tests/testthat/test-coord-polar.r +++ b/tests/testthat/test-coord-polar.r @@ -74,9 +74,9 @@ test_that("Inf is squished to range", { # 0.4 is the upper limit of radius hardcoded in r_rescale() expect_equal(d[[2]]$r, 0.4) - expect_equal(d[[2]]$theta, new_mapped_discrete(0)) + expect_equal(d[[2]]$theta, mapped_discrete(0)) expect_equal(d[[3]]$r, 0) - expect_equal(d[[3]]$theta, new_mapped_discrete(0)) + expect_equal(d[[3]]$theta, mapped_discrete(0)) }) diff --git a/tests/testthat/test-geom-freqpoly.R b/tests/testthat/test-geom-freqpoly.R index 52de05f4a7..60b798787f 100644 --- a/tests/testthat/test-geom-freqpoly.R +++ b/tests/testthat/test-geom-freqpoly.R @@ -4,7 +4,7 @@ test_that("can do frequency polygon with categorical x", { p <- ggplot(df, aes(x)) + geom_freqpoly(stat = "count") d <- layer_data(p) - expect_s3_class(d$x, "mapped_discrete") - expect_equal(d$x, new_mapped_discrete(1:3)) + expect_s3_class(d$x, "ggplot2_mapped_discrete") + expect_equal(d$x, mapped_discrete(1:3)) expect_equal(d$y, 3:1) }) diff --git a/tests/testthat/test-layer.r b/tests/testthat/test-layer.r index 29ddb03a52..298532fe88 100644 --- a/tests/testthat/test-layer.r +++ b/tests/testthat/test-layer.r @@ -112,13 +112,13 @@ test_that("retransform works on computed aesthetics in `map_statistic`", { test_that("layer_data returns a data.frame", { l <- geom_point() - expect_equal(l$layer_data(mtcars), mtcars) + expect_equal(l$layer_data(mtcars), unrowname(mtcars)) l <- geom_point(data = head(mtcars)) - expect_equal(l$layer_data(mtcars), head(mtcars)) + expect_equal(l$layer_data(mtcars), head(unrowname(mtcars))) l <- geom_point(data = head) - expect_equal(l$layer_data(mtcars), head(mtcars)) + expect_equal(l$layer_data(mtcars), head(unrowname(mtcars))) l <- geom_point(data = ~ head(., 10)) - expect_equal(l$layer_data(mtcars), head(mtcars, 10)) + expect_equal(l$layer_data(mtcars), head(unrowname(mtcars), 10)) l <- geom_point(data = nrow) expect_snapshot_error(l$layer_data(mtcars)) }) diff --git a/tests/testthat/test-performance.R b/tests/testthat/test-performance.R index 3706e26cfb..1c65622b4a 100644 --- a/tests/testthat/test-performance.R +++ b/tests/testthat/test-performance.R @@ -32,34 +32,3 @@ test_that("modify_list erases null elements", { expect_null(res$c) expect_named(res, c('a', 'b', 'd')) }) - - -# new_data_frame() -------------------------------------------------------- - -test_that("new_data_frame handles zero-length inputs", { - # zero-length input creates zero-length data frame - d <- new_data_frame(list(x = numeric(0), y = numeric(0))) - expect_equal(nrow(d), 0L) - - # constants are ignored in the context of zero-length input - d <- new_data_frame(list(x = numeric(0), y = numeric(0), z = 1)) - expect_equal(nrow(d), 0L) - - # vectors of length > 1 don't mix with zero-length input - expect_error( - new_data_frame(list(x = numeric(0), y = numeric(0), z = 1, a = c(1, 2))), - "Elements must equal the number of rows or 1" - ) - - # explicit recycling doesn't work with zero-length input - expect_error( - new_data_frame(list(x = numeric(0), z = 1), n = 5), - "Elements must equal the number of rows or 1" - ) - # but it works without - d <- new_data_frame(list(x = 1, y = "a"), n = 5) - expect_equal(nrow(d), 5L) - expect_identical(d$x, rep(1, 5L)) - expect_identical(d$y, rep("a", 5L)) - -}) diff --git a/tests/testthat/test-position-dodge2.R b/tests/testthat/test-position-dodge2.R index 4f5fcf90dc..a48bf7fd86 100644 --- a/tests/testthat/test-position-dodge2.R +++ b/tests/testthat/test-position-dodge2.R @@ -87,13 +87,10 @@ test_that("boxes in facetted plots keep the correct width", { }) test_that("width of groups is computed per facet", { - df <- tibble::tribble( - ~g1, ~g2, ~y, - "x", "a", 1, - "x", "b", 2, - "y", "a", 3, - "y", "b", 4, - "y", "c", 3, + df <- data_frame( + g1 = c("x", "x", "y", "y", "y"), + g2 = c("a", "b", "a", "b", "c"), + y = c(1, 2, 3, 4, 3) ) p <- ggplot(df, aes("x", y, fill = g2)) + diff --git a/tests/testthat/test-rbind-dfs.R b/tests/testthat/test-rbind-dfs.R deleted file mode 100644 index 9184711911..0000000000 --- a/tests/testthat/test-rbind-dfs.R +++ /dev/null @@ -1,12 +0,0 @@ -test_that("rbind_dfs keep classes of columns", { - df <- data_frame( - integer = seq_len(10), - numeric = as.numeric(seq_len(10)), - character = letters[1:10], - factor = factor(letters[1:10]), - ordered = ordered(letters[1:10]), - date = Sys.Date() - ) - df2 <- rbind_dfs(list(df[1:5, ], df[6:10, ])) - expect_equal(df2, df) -}) diff --git a/tests/testthat/test-scale-discrete.R b/tests/testthat/test-scale-discrete.R index 1ddd25bb1b..f06531cf2e 100644 --- a/tests/testthat/test-scale-discrete.R +++ b/tests/testthat/test-scale-discrete.R @@ -151,14 +151,14 @@ test_that("Aesthetics with no continuous interpretation fails when called", { # mapped_discrete --------------------------------------------------------- test_that("mapped_discrete vectors behaves as predicted", { - expect_null(new_mapped_discrete(NULL)) - expect_s3_class(new_mapped_discrete(c(0, 3.5)), "mapped_discrete") - expect_s3_class(new_mapped_discrete(seq_len(4)), "mapped_discrete") - expect_error(new_mapped_discrete(letters)) - - x <- new_mapped_discrete(1:10) - expect_s3_class(x[2:4], "mapped_discrete") - expect_s3_class(c(x, x), "mapped_discrete") - x[5:7] <- new_mapped_discrete(seq_len(3)) - expect_s3_class(x, "mapped_discrete") + expect_null(mapped_discrete(NULL)) + expect_s3_class(mapped_discrete(c(0, 3.5)), "ggplot2_mapped_discrete") + expect_s3_class(mapped_discrete(seq_len(4)), "ggplot2_mapped_discrete") + expect_error(mapped_discrete(letters)) + + x <- mapped_discrete(1:10) + expect_s3_class(x[2:4], "ggplot2_mapped_discrete") + expect_s3_class(c(x, x), "ggplot2_mapped_discrete") + x[5:7] <- mapped_discrete(seq_len(3)) + expect_s3_class(x, "ggplot2_mapped_discrete") }) diff --git a/tests/testthat/test-stat-bin.R b/tests/testthat/test-stat-bin.R index 0394295be6..24aa21ec6a 100644 --- a/tests/testthat/test-stat-bin.R +++ b/tests/testthat/test-stat-bin.R @@ -197,13 +197,13 @@ test_that("stat_count preserves x order for continuous and discrete", { # x is factor where levels match numeric order mtcars$carb2 <- factor(mtcars$carb) b <- ggplot_build(ggplot(mtcars, aes(carb2)) + geom_bar()) - expect_identical(b$data[[1]]$x, new_mapped_discrete(1:6)) + expect_identical(b$data[[1]]$x, mapped_discrete(1:6)) expect_identical(b$data[[1]]$y, c(7,10,3,10,1,1)) # x is factor levels differ from numeric order mtcars$carb3 <- factor(mtcars$carb, levels = c(4,1,2,3,6,8)) b <- ggplot_build(ggplot(mtcars, aes(carb3)) + geom_bar()) - expect_identical(b$data[[1]]$x, new_mapped_discrete(1:6)) + expect_identical(b$data[[1]]$x, mapped_discrete(1:6)) expect_identical(b$layout$panel_params[[1]]$x$get_labels(), c("4","1","2","3","6","8")) expect_identical(b$data[[1]]$y, c(10,7,10,3,1,1)) }) diff --git a/tests/testthat/test-stat-function.R b/tests/testthat/test-stat-function.R index fbe4f38b7e..497c18ef41 100644 --- a/tests/testthat/test-stat-function.R +++ b/tests/testthat/test-stat-function.R @@ -60,7 +60,7 @@ test_that("works with discrete x", { stat_function(fun = as.numeric, geom = "point", n = 2) ret <- layer_data(base) - expect_equal(ret$x, new_mapped_discrete(1:2)) + expect_equal(ret$x, mapped_discrete(1:2)) expect_equal(ret$y, 1:2) })