From 1175ed1808d759c3dfc17bcf341f3251b15e3229 Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Sun, 6 Apr 2025 14:33:58 +0530 Subject: [PATCH 1/9] replaced plyr occurences --- tests/testthat/helper-plot-data.r | 17 +++-- tests/testthat/test-compiler-animation.R | 70 ++++++++++--------- tests/testthat/test-compiler-fortify.r | 8 ++- .../test-compiler-save-separate-chunks.R | 14 ++-- 4 files changed, 61 insertions(+), 48 deletions(-) diff --git a/tests/testthat/helper-plot-data.r b/tests/testthat/helper-plot-data.r index 69e8717cc..655120a1d 100644 --- a/tests/testthat/helper-plot-data.r +++ b/tests/testthat/helper-plot-data.r @@ -1,14 +1,21 @@ # Transform the data as the coordinate system does +library(data.table) +# Transform the data as the coordinate system does cdata <- function(plot) { pieces <- ggplot_build(plot) + # Process each piece of data while maintaining panel structure + result <- lapply(pieces$data, function(d) { + dt <- as.data.table(d) - lapply(pieces$data, function(d) { - plyr::ddply(d, "PANEL", function(panel_data) { - scales <- panel_scales(pieces$panel, panel_data$PANEL[1]) + # Explicitly group by PANEL and process each panel's data + dt[, { + scales <- panel_scales(pieces$panel, PANEL) details <- plot$coordinates$train(scales) - plot$coordinates$transform(panel_data, details) - }) + as.data.table(plot$coordinates$transform(as.data.frame(.SD), details)) + }, by = PANEL] }) + + return(result) } pranges <- function(plot) { diff --git a/tests/testthat/test-compiler-animation.R b/tests/testthat/test-compiler-animation.R index 032d7fe06..8e1922258 100644 --- a/tests/testthat/test-compiler-animation.R +++ b/tests/testthat/test-compiler-animation.R @@ -1,38 +1,42 @@ acontext("animation") -if(require(maps) && require(plyr)){ - data(UStornadoes, package = "animint2") - stateOrder <- data.frame(state = unique(UStornadoes$state)[order(unique(UStornadoes$TornadoesSqMile), decreasing=T)], rank = 1:49) # order states by tornadoes per square mile - UStornadoes$state <- factor(UStornadoes$state, levels=stateOrder$state, ordered=TRUE) - UStornadoes$weight <- 1/UStornadoes$LandArea - # useful for stat_bin, etc. - USpolygons <- map_data("state") - USpolygons$state = state.abb[match(USpolygons$region, tolower(state.name))] - UStornadoCounts <- - ddply(UStornadoes, .(state, year), summarize, count=length(state)) - tornado.anim <- list( - map=ggplot()+ - geom_polygon(aes( - x=long, y=lat, group=group), - data=USpolygons, - clickSelects="state", - fill="black", colour="grey") + - geom_segment(aes( - x=startLong, y=startLat, xend=endLong, yend=endLat), - showSelected="year", - colour="#55B1F7", data=UStornadoes), - ts=ggplot()+ - make_tallrect(UStornadoCounts, "year")+ - geom_line(aes( - year, count, group=state), - clickSelects="state", - data=UStornadoCounts, alpha=3/5, size=4), - time=list(variable="year",ms=2000)) - test_that("tornado animation frames correct", { - info <- animint2dir(tornado.anim, open.browser=FALSE) - expect_identical(info$time$sequence, as.character(1950:2012)) - }) -} +library(data.table) +library(animint2) +library(maps) + +data(UStornadoes, package = "animint2") +stateOrder <- data.frame(state = unique(UStornadoes$state)[order(unique(UStornadoes$TornadoesSqMile), decreasing=T)], rank = 1:49) # order states by tornadoes per square mile +UStornadoes$state <- factor(UStornadoes$state, levels=stateOrder$state, ordered=TRUE) +UStornadoes$weight <- 1/UStornadoes$LandArea +# useful for stat_bin, etc. +USpolygons <- map_data("state") +USpolygons$state <- state.abb[match(USpolygons$region, tolower(state.name))] + +UStornadoes_dt <- data.table(UStornadoes) +UStornadoCounts <- UStornadoes_dt[, .(count = .N), by = .(state, year)] + +tornado.anim <- list( + map=ggplot()+ + geom_polygon(aes( + x=long, y=lat, group=group), + data=USpolygons, + clickSelects="state", + fill="black", colour="grey") + + geom_segment(aes( + x=startLong, y=startLat, xend=endLong, yend=endLat), + showSelected="year", + colour="#55B1F7", data=UStornadoes_dt), + ts=ggplot()+ + make_tallrect(UStornadoCounts, "year")+ + geom_line(aes( + year, count, group=state), + clickSelects="state", + data=UStornadoCounts, alpha=3/5, size=4), + time=list(variable="year",ms=2000)) +test_that("tornado animation frames correct", { + info <- animint2dir(tornado.anim, open.browser=FALSE) + expect_identical(info$time$sequence, as.character(1950:2012)) +}) ## WorldBank/gapminder example. data(WorldBank, package = "animint2") diff --git a/tests/testthat/test-compiler-fortify.r b/tests/testthat/test-compiler-fortify.r index 5265fa482..ffc4cb3c8 100644 --- a/tests/testthat/test-compiler-fortify.r +++ b/tests/testthat/test-compiler-fortify.r @@ -1,5 +1,6 @@ context("Fortify") library(sp) +library(animint2) test_that("Spatial polygons have correct ordering", { make_square <- function(x = 0, y = 0, height = 1, width = 1){ @@ -32,6 +33,9 @@ test_that("Spatial polygons have correct ordering", { polys2_sp <- SpatialPolygons(polys2) fake_sp2 <- SpatialPolygonsDataFrame(polys2_sp, fake_data) - expect_equivalent(fortify(fake_sp), plyr::arrange(fortify(fake_sp2), id, order)) - + # arranged with data.table[order(id, order)] + fortified_sp2 <- fortify(fake_sp2) + fortified_sp2 <- as.data.table(fortified_sp2) + fortified_sp2 <- fortified_sp2[order(id, order)] + expect_equivalent(fortify(fake_sp), fortified_sp2) }) diff --git a/tests/testthat/test-compiler-save-separate-chunks.R b/tests/testthat/test-compiler-save-separate-chunks.R index 6cc02d37c..e2f0a69ae 100644 --- a/tests/testthat/test-compiler-save-separate-chunks.R +++ b/tests/testthat/test-compiler-save-separate-chunks.R @@ -1,5 +1,5 @@ acontext("save separate chunks") -library(plyr) +library(data.table) data(FluView, package = "animint2") # use one season to test @@ -85,15 +85,13 @@ test_that("save separate chunks for geom_polygon", { }) ### test case 2 -USdots <- - ddply(FluView$USpolygons, .(region), summarise, - mean.lat = mean(lat), - mean.long = mean(long)) -# add state flu to points. -flu.points <- ldply(unique(state_flu$WEEKEND), function(we) { +USpolygons_dt <- as.data.table(FluView$USpolygons) +USdots <- USpolygons_dt[, .(mean.lat = mean(lat), mean.long = mean(long)), by = region] + +flu.points <- rbindlist(lapply(unique(state_flu$WEEKEND), function(we) { df <- subset(state_flu, WEEKEND == we) merge(USdots, df, by.x = "region", by.y = "state") -}) +})) test_that("save separate chunks for geom_point without specifying group", { # the compiler will not break a geom into chunks if any of the resulting From 385922868487d653900c348c15e358208fd0644a Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Sun, 6 Apr 2025 15:48:30 +0530 Subject: [PATCH 2/9] replaced plyr in test-renderer1-interactivity.r --- tests/testthat/test-renderer1-interactivity.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-renderer1-interactivity.R b/tests/testthat/test-renderer1-interactivity.R index d8805c08f..c3b0904f8 100644 --- a/tests/testthat/test-renderer1-interactivity.R +++ b/tests/testthat/test-renderer1-interactivity.R @@ -178,9 +178,10 @@ UStornadoes$state <- factor(UStornadoes$state, levels=stateOrder$state, ordered= UStornadoes$weight <- 1/UStornadoes$LandArea USpolygons <- map_data("state") USpolygons$state = state.abb[match(USpolygons$region, tolower(state.name))] -library(plyr) -UStornadoCounts <- - ddply(UStornadoes, .(state, year), summarize, count=length(state)) + +library(data.table) +UStornadoes_dt <- as.data.table(UStornadoes) +UStornadoCounts <- UStornadoes_dt[, .(count = .N), by = .(state, year)] seg.color <- "#55B1F7" tornado.lines <- list( map=ggplot()+ From 295ad567e405a58983dd04f49664cf5b74c3a437 Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Sun, 6 Apr 2025 16:03:08 +0530 Subject: [PATCH 3/9] replaced plyr in test-renderer1-hjust-text-anchor.r --- tests/testthat/test-renderer1-hjust-text-anchor.R | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/testthat/test-renderer1-hjust-text-anchor.R b/tests/testthat/test-renderer1-hjust-text-anchor.R index fcecb6403..47b0d3b17 100644 --- a/tests/testthat/test-renderer1-hjust-text-anchor.R +++ b/tests/testthat/test-renderer1-hjust-text-anchor.R @@ -39,12 +39,13 @@ grad.desc <- function( dat <- grad.desc() contour <- dat$contour -objective <- dat$objective -objective <- plyr::ldply(objective$iteration, function(i) { - df <- subset(objective, iteration <= i) - cbind(df, iteration2 = i) -}) -objective2 <- subset(objective, iteration == iteration2) +objective <- as.data.table(dat$objective) + +objective <- objective[, { + .SD[, .(iteration, x, y, z, iteration2 = i)] +}, by = .(i = iteration)][, i := NULL][] + +objective2 <- objective[iteration == iteration2] grad.desc.viz <- function(hjust) { objective2$hjust <- hjust From 3406fe293a7da5e61a7c8f2f26d3acfaa7d7f5dc Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Mon, 7 Apr 2025 10:22:59 +0530 Subject: [PATCH 4/9] made requested changes --- tests/testthat/helper-plot-data.r | 5 +- tests/testthat/test-compiler-animation.R | 68 ++++++++++++------------ tests/testthat/test-compiler-fortify.r | 7 ++- 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/tests/testthat/helper-plot-data.r b/tests/testthat/helper-plot-data.r index 655120a1d..942730abf 100644 --- a/tests/testthat/helper-plot-data.r +++ b/tests/testthat/helper-plot-data.r @@ -1,10 +1,9 @@ -# Transform the data as the coordinate system does library(data.table) # Transform the data as the coordinate system does cdata <- function(plot) { pieces <- ggplot_build(plot) # Process each piece of data while maintaining panel structure - result <- lapply(pieces$data, function(d) { + lapply(pieces$data, function(d) { dt <- as.data.table(d) # Explicitly group by PANEL and process each panel's data @@ -14,8 +13,6 @@ cdata <- function(plot) { as.data.table(plot$coordinates$transform(as.data.frame(.SD), details)) }, by = PANEL] }) - - return(result) } pranges <- function(plot) { diff --git a/tests/testthat/test-compiler-animation.R b/tests/testthat/test-compiler-animation.R index 8e1922258..ae2c1cbdd 100644 --- a/tests/testthat/test-compiler-animation.R +++ b/tests/testthat/test-compiler-animation.R @@ -2,41 +2,39 @@ acontext("animation") library(data.table) library(animint2) -library(maps) - -data(UStornadoes, package = "animint2") -stateOrder <- data.frame(state = unique(UStornadoes$state)[order(unique(UStornadoes$TornadoesSqMile), decreasing=T)], rank = 1:49) # order states by tornadoes per square mile -UStornadoes$state <- factor(UStornadoes$state, levels=stateOrder$state, ordered=TRUE) -UStornadoes$weight <- 1/UStornadoes$LandArea -# useful for stat_bin, etc. -USpolygons <- map_data("state") -USpolygons$state <- state.abb[match(USpolygons$region, tolower(state.name))] - -UStornadoes_dt <- data.table(UStornadoes) -UStornadoCounts <- UStornadoes_dt[, .(count = .N), by = .(state, year)] - -tornado.anim <- list( - map=ggplot()+ - geom_polygon(aes( - x=long, y=lat, group=group), - data=USpolygons, - clickSelects="state", - fill="black", colour="grey") + - geom_segment(aes( - x=startLong, y=startLat, xend=endLong, yend=endLat), - showSelected="year", - colour="#55B1F7", data=UStornadoes_dt), - ts=ggplot()+ - make_tallrect(UStornadoCounts, "year")+ - geom_line(aes( - year, count, group=state), - clickSelects="state", - data=UStornadoCounts, alpha=3/5, size=4), - time=list(variable="year",ms=2000)) -test_that("tornado animation frames correct", { - info <- animint2dir(tornado.anim, open.browser=FALSE) - expect_identical(info$time$sequence, as.character(1950:2012)) -}) +if(require(maps)){ + data(UStornadoes, package = "animint2") + stateOrder <- data.frame(state = unique(UStornadoes$state)[order(unique(UStornadoes$TornadoesSqMile), decreasing=T)], rank = 1:49) # order states by tornadoes per square mile + UStornadoes$state <- factor(UStornadoes$state, levels=stateOrder$state, ordered=TRUE) + UStornadoes$weight <- 1/UStornadoes$LandArea + # useful for stat_bin, etc. + USpolygons <- map_data("state") + USpolygons$state <- state.abb[match(USpolygons$region, tolower(state.name))] + UStornadoes_dt <- data.table(UStornadoes) + UStornadoCounts <- UStornadoes_dt[, .(count = .N), by = .(state, year)] + tornado.anim <- list( + map=ggplot()+ + geom_polygon(aes( + x=long, y=lat, group=group), + data=USpolygons, + clickSelects="state", + fill="black", colour="grey") + + geom_segment(aes( + x=startLong, y=startLat, xend=endLong, yend=endLat), + showSelected="year", + colour="#55B1F7", data=UStornadoes), + ts=ggplot()+ + make_tallrect(UStornadoCounts, "year")+ + geom_line(aes( + year, count, group=state), + clickSelects="state", + data=UStornadoCounts, alpha=3/5, size=4), + time=list(variable="year",ms=2000)) + test_that("tornado animation frames correct", { + info <- animint2dir(tornado.anim, open.browser=FALSE) + expect_identical(info$time$sequence, as.character(1950:2012)) + }) +} ## WorldBank/gapminder example. data(WorldBank, package = "animint2") diff --git a/tests/testthat/test-compiler-fortify.r b/tests/testthat/test-compiler-fortify.r index ffc4cb3c8..f1bc0f59d 100644 --- a/tests/testthat/test-compiler-fortify.r +++ b/tests/testthat/test-compiler-fortify.r @@ -34,8 +34,7 @@ test_that("Spatial polygons have correct ordering", { fake_sp2 <- SpatialPolygonsDataFrame(polys2_sp, fake_data) # arranged with data.table[order(id, order)] - fortified_sp2 <- fortify(fake_sp2) - fortified_sp2 <- as.data.table(fortified_sp2) - fortified_sp2 <- fortified_sp2[order(id, order)] - expect_equivalent(fortify(fake_sp), fortified_sp2) + fortified <- fortify(fake_sp2) + fortified <- fortified[order(fortified$id, fortified$order), ] + expect_equivalent(fortify(fake_sp), fortified) }) From bedfc5881490777ad8a2eb5b1a84a7e9a2a82928 Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Mon, 7 Apr 2025 10:42:11 +0530 Subject: [PATCH 5/9] removed empty space and comment --- tests/testthat/helper-plot-data.r | 1 - tests/testthat/test-compiler-fortify.r | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/testthat/helper-plot-data.r b/tests/testthat/helper-plot-data.r index 942730abf..ac649769a 100644 --- a/tests/testthat/helper-plot-data.r +++ b/tests/testthat/helper-plot-data.r @@ -5,7 +5,6 @@ cdata <- function(plot) { # Process each piece of data while maintaining panel structure lapply(pieces$data, function(d) { dt <- as.data.table(d) - # Explicitly group by PANEL and process each panel's data dt[, { scales <- panel_scales(pieces$panel, PANEL) diff --git a/tests/testthat/test-compiler-fortify.r b/tests/testthat/test-compiler-fortify.r index f1bc0f59d..e94e028b3 100644 --- a/tests/testthat/test-compiler-fortify.r +++ b/tests/testthat/test-compiler-fortify.r @@ -33,7 +33,6 @@ test_that("Spatial polygons have correct ordering", { polys2_sp <- SpatialPolygons(polys2) fake_sp2 <- SpatialPolygonsDataFrame(polys2_sp, fake_data) - # arranged with data.table[order(id, order)] fortified <- fortify(fake_sp2) fortified <- fortified[order(fortified$id, fortified$order), ] expect_equivalent(fortify(fake_sp), fortified) From 3db0885d2dc3059a8a6f15b40ec63cbc34bd923b Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Mon, 7 Apr 2025 10:45:27 +0530 Subject: [PATCH 6/9] removed plyr from DESCRIPTION and NAMESPACE --- DESCRIPTION | 1 - NAMESPACE | 2 -- 2 files changed, 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index f2dba5747..8bb579f77 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -74,7 +74,6 @@ Imports: grid, gtable (>= 0.1.1), MASS, - plyr (>= 1.7.1), reshape2, scales (>= 0.4.1), stats, diff --git a/NAMESPACE b/NAMESPACE index e3dd8a975..65a03459b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -509,7 +509,6 @@ import(RJSONIO) import(data.table) import(grid) import(gtable) -import(plyr) import(scales) importFrom(grDevices,col2rgb) importFrom(grDevices,rgb) @@ -517,7 +516,6 @@ importFrom(grid,arrow) importFrom(grid,unit) importFrom(knitr,knit_print) importFrom(methods,is) -importFrom(plyr,as.quoted) importFrom(plyr,defaults) importFrom(scales,alpha) importFrom(stats,na.omit) From d64098ca96aac2edbda82d7ad875b99f7f92e39b Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Sat, 12 Apr 2025 00:08:20 +0530 Subject: [PATCH 7/9] replacing as.quoted() --- R/facet-grid-.r | 1 - R/utilities.r | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/R/facet-grid-.r b/R/facet-grid-.r index cf5312be1..680b07fba 100644 --- a/R/facet-grid-.r +++ b/R/facet-grid-.r @@ -121,7 +121,6 @@ #' mg + facet_grid(vs + am ~ gear, margins = "gear") #' mg + facet_grid(vs + am ~ gear, margins = c("gear", "am")) #' } -#' @importFrom plyr as.quoted facet_grid <- function(facets, margins = FALSE, scales = "fixed", space = "fixed", shrink = TRUE, labeller = "label_value", as.table = TRUE, switch = NULL, drop = TRUE) { scales <- match.arg(scales, c("fixed", "free_x", "free_y", "free")) free <- list( diff --git a/R/utilities.r b/R/utilities.r index 578770fd9..e5b89fbc2 100644 --- a/R/utilities.r +++ b/R/utilities.r @@ -306,3 +306,90 @@ stop_servr <- function(tmpPath = ".") { } res } + +# Replacement for plyr::as.quoted +as.quoted <- function(x) { + if (is.null(x)) return(list()) + if (is.quoted(x)) return(x) + + if (is.character(x)) { + return(structure(lapply(x, as.name), class = "quoted")) + } + if (is.name(x)) { + return(structure(list(x), class = "quoted")) + } + if (is.formula(x)) { + return(structure(as.list(parse.formula(x)), class = "quoted")) + } + if (is.call(x)) { + if (identical(x[[1]], as.name("+"))) { + # Handle expressions like a + b + left <- as.quoted(x[[2]]) + right <- as.quoted(x[[3]]) + return(structure(c(left, right), class = "quoted")) + } + return(structure(list(x), class = "quoted")) + } + if (is.list(x)) { + return(structure(x, class = "quoted")) + } + + structure(list(x), class = "quoted") +} + +# Helper function to check if object is already quoted +is.quoted <- function(x) { + inherits(x, "quoted") +} + +# Helper to parse formula objects +parse.formula <- function(f) { + if (length(f) == 2) { + # One-sided formula + vars <- f[[2]] + } else if (length(f) == 3) { + # Two-sided formula + vars <- f[[2:3]] + } else { + stop("Invalid formula") + } + + if (is.call(vars) && identical(vars[[1]], as.name("+"))) { + # Handle formulas with multiple variables (e.g., a + b) + as.list(vars[-1]) + } else { + list(vars) + } +} + +# Evaluation function to replace plyr::eval.quoted +eval.quoted <- function(exprs, data = NULL, enclos = parent.frame()) { + if (!is.quoted(exprs)) exprs <- as.quoted(exprs) + + if (is.null(data)) { + lapply(exprs, eval, envir = enclos) + } else { + lapply(exprs, eval, envir = data, enclos = enclos) + } +} + +# Replacement for plyr::id +id <- function(x, drop = FALSE) { + if (length(x) == 0) return(integer()) + + if (is.data.frame(x)) { + # Handle data frames by converting to a list of vectors + x <- lapply(x, as.factor) + } else { + x <- as.factor(x) + } + + # For a single vector, just return the numeric values + if (!is.list(x)) { + return(as.integer(x)) + } + + # For multiple vectors, create unique combinations + combs <- do.call(paste, c(x, sep = "\r")) + as.integer(factor(combs, levels = unique(combs))) +} \ No newline at end of file From 1387f119a97807a859e78e435d112e45d14dca22 Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Sat, 12 Apr 2025 11:40:44 +0530 Subject: [PATCH 8/9] replacing defaults() --- NAMESPACE | 1 - R/utilities.r | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ R/z_animint.R | 2 +- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 65a03459b..8c80ee576 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -516,7 +516,6 @@ importFrom(grid,arrow) importFrom(grid,unit) importFrom(knitr,knit_print) importFrom(methods,is) -importFrom(plyr,defaults) importFrom(scales,alpha) importFrom(stats,na.omit) importFrom(stats,setNames) diff --git a/R/utilities.r b/R/utilities.r index e5b89fbc2..c5ceeefff 100644 --- a/R/utilities.r +++ b/R/utilities.r @@ -392,4 +392,65 @@ id <- function(x, drop = FALSE) { # For multiple vectors, create unique combinations combs <- do.call(paste, c(x, sep = "\r")) as.integer(factor(combs, levels = unique(combs))) +} + +#' Fill in missing values in a list with values from another list +#' +#' This function takes two lists and fills in missing values in the first list +#' with values from the second list. It's similar to modifyList() but preserves +#' NULLs and doesn't recursively merge nested lists. +#' +#' @param x the list to be modified +#' @param y the list of defaults to use to fill in missing values +#' @return a new list with missing values in x filled in from y +#' @noRd +defaults <- function(x, y) { + if (is.null(x)) return(y) + if (is.null(y)) return(x) + + # Special handling for unit objects + if (inherits(x, "unit") || inherits(y, "unit")) { + return(x) + } + # Special handling for theme elements + if (inherits(x, "element") || inherits(y, "element")) { + return(x) + } + # Handle unnamed vectors/lists + if (is.null(names(x)) && is.null(names(y))) { + return(x) + } + # If x is unnamed but y is named, add names from y + if (is.null(names(x)) && !is.null(names(y))) { + names(x) <- names(y)[seq_along(x)] + } + # Get names from both lists + nx <- names(x) + ny <- names(y) + # Find which names in y are missing from x + missing <- setdiff(ny, nx) + # Add missing elements from y to x + if (length(missing) > 0) { + # Handle lists specially to preserve attributes + if (is.list(x) && is.list(y)) { + x[missing] <- y[missing] + } else { + # For other types, do standard combination + x <- c(x, y[missing]) + } + } + # Preserve attributes where possible + if (!is.null(attributes(y))) { + attrs <- attributes(y) + # Don't copy over names or class + attrs$names <- NULL + attrs$class <- NULL + # Copy remaining attributes if they don't already exist + for (a in names(attrs)) { + if (is.null(attr(x, a))) { + attr(x, a) <- attrs[[a]] + } + } + } + x } \ No newline at end of file diff --git a/R/z_animint.R b/R/z_animint.R index 2608b31a0..d121239bb 100644 --- a/R/z_animint.R +++ b/R/z_animint.R @@ -729,7 +729,7 @@ getLegendList <- function(plistextra){ guides.args[[aes.name]] <- guide.type } guides.result <- do.call(guides, guides.args) - guides.list <- plyr::defaults(plot$guides, guides.result) + guides.list <- defaults(plot$guides, guides.result) gdefs <- guides_train(scales = scales, theme = theme, guides = guides.list, From 6839d5c9f6e7d3c4fe5a55f8091ef16dfbf5f2c6 Mon Sep 17 00:00:00 2001 From: Suhaani Agarwal Date: Sat, 12 Apr 2025 22:20:32 +0530 Subject: [PATCH 9/9] removed as.quoted import from ggplot2.r --- R/ggplot2.r | 1 - tests/testthat/testthat-problems.rds | Bin 0 -> 18325 bytes 2 files changed, 1 deletion(-) create mode 100644 tests/testthat/testthat-problems.rds diff --git a/R/ggplot2.r b/R/ggplot2.r index 90f86f657..04c1a4fa2 100644 --- a/R/ggplot2.r +++ b/R/ggplot2.r @@ -1,4 +1,3 @@ #' @import scales grid gtable -#' @importFrom plyr defaults #' @importFrom stats setNames NULL diff --git a/tests/testthat/testthat-problems.rds b/tests/testthat/testthat-problems.rds new file mode 100644 index 0000000000000000000000000000000000000000..a6b9a287222ec92904170abe0612a1e20a651e5e GIT binary patch literal 18325 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