From 66325743de89a7833a7c793995fbecbcc900df51 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 09:18:40 +0200 Subject: [PATCH 01/10] remove `build_ggplot()` in favour of `ggplot_build()` --- NAMESPACE | 2 -- R/plot-build.R | 34 ++++++++---------------- man/{build_ggplot.Rd => ggplot_build.Rd} | 5 +--- 3 files changed, 12 insertions(+), 29 deletions(-) rename man/{build_ggplot.Rd => ggplot_build.Rd} (96%) diff --git a/NAMESPACE b/NAMESPACE index 5893c8bb5a..973719699c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -59,7 +59,6 @@ S3method(fortify,tbl_df) S3method(ggplot,"function") S3method(ggplot,default) S3method(ggplot_add,default) -S3method(ggplot_build,default) S3method(ggplot_gtable,default) S3method(grid.draw,absoluteGrob) S3method(grobHeight,absoluteGrob) @@ -292,7 +291,6 @@ export(autoplot) export(benchplot) export(binned_scale) export(borders) -export(build_ggplot) export(calc_element) export(check_device) export(class_ggplot) diff --git a/R/plot-build.R b/R/plot-build.R index ecd94621c2..aacda0d362 100644 --- a/R/plot-build.R +++ b/R/plot-build.R @@ -25,19 +25,19 @@ #' The `r link_book("build step section", "internals#sec-ggplotbuild")` #' @keywords internal #' @export -build_ggplot <- S7::new_generic("build_ggplot", "plot", fun = function(plot, ...) { +ggplot_build <- function(plot, ...) { env <- try_prop(plot, "plot_env") if (!is.null(env)) { attach_plot_env(env) } - S7::S7_dispatch() -}) + UseMethod("ggplot_build") +} -S7::method(build_ggplot, class_ggplot_built) <- function(plot, ...) { +S7::method(ggplot_build, class_ggplot_built) <- function(plot, ...) { plot # This is a no-op } -S7::method(build_ggplot, class_ggplot) <- function(plot, ...) { +S7::method(ggplot_build, class_ggplot) <- function(plot, ...) { plot <- plot_clone(plot) if (length(plot@layers) == 0) { plot <- plot + geom_blank() @@ -136,29 +136,17 @@ S7::method(build_ggplot, class_ggplot) <- function(plot, ...) { build } -# TODO: the S3 generic should be phased out once S7 is adopted more widely -#' @rdname build_ggplot -#' @export -ggplot_build <- function(plot, ...) { - UseMethod("ggplot_build") -} - -#' @export -ggplot_build.default <- function(plot, ...) { - build_ggplot(plot) -} - #' @export -#' @rdname build_ggplot +#' @rdname ggplot_build get_layer_data <- function(plot = get_last_plot(), i = 1L) { ggplot_build(plot)@data[[i]] } #' @export -#' @rdname build_ggplot +#' @rdname ggplot_build layer_data <- get_layer_data #' @export -#' @rdname build_ggplot +#' @rdname ggplot_build get_panel_scales <- function(plot = get_last_plot(), i = 1L, j = 1L) { b <- ggplot_build(plot) @@ -172,11 +160,11 @@ get_panel_scales <- function(plot = get_last_plot(), i = 1L, j = 1L) { } #' @export -#' @rdname build_ggplot +#' @rdname ggplot_build layer_scales <- get_panel_scales #' @export -#' @rdname build_ggplot +#' @rdname ggplot_build get_layer_grob <- function(plot = get_last_plot(), i = 1L) { b <- ggplot_build(plot) @@ -184,7 +172,7 @@ get_layer_grob <- function(plot = get_last_plot(), i = 1L) { } #' @export -#' @rdname build_ggplot +#' @rdname ggplot_build layer_grob <- get_layer_grob #' Build a plot with all the usual bits and pieces. diff --git a/man/build_ggplot.Rd b/man/ggplot_build.Rd similarity index 96% rename from man/build_ggplot.Rd rename to man/ggplot_build.Rd index e5157679ee..1df8de8af1 100644 --- a/man/build_ggplot.Rd +++ b/man/ggplot_build.Rd @@ -1,7 +1,6 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/plot-build.R -\name{build_ggplot} -\alias{build_ggplot} +\name{ggplot_build} \alias{ggplot_build} \alias{get_layer_data} \alias{layer_data} @@ -11,8 +10,6 @@ \alias{layer_grob} \title{Build ggplot for rendering.} \usage{ -build_ggplot(plot, ...) - ggplot_build(plot, ...) get_layer_data(plot = get_last_plot(), i = 1L) From 1fda7a90335fd599a09dca37184659f56679f94e Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 09:20:23 +0200 Subject: [PATCH 02/10] remove `gtable_ggplot()` in favour of `ggplot_gtable()` --- NAMESPACE | 2 -- R/plot-build.R | 20 ++++---------------- man/{gtable_ggplot.Rd => ggplot_gtable.Rd} | 5 +---- 3 files changed, 5 insertions(+), 22 deletions(-) rename man/{gtable_ggplot.Rd => ggplot_gtable.Rd} (94%) diff --git a/NAMESPACE b/NAMESPACE index 973719699c..e512bd6e0b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -59,7 +59,6 @@ S3method(fortify,tbl_df) S3method(ggplot,"function") S3method(ggplot,default) S3method(ggplot_add,default) -S3method(ggplot_gtable,default) S3method(grid.draw,absoluteGrob) S3method(grobHeight,absoluteGrob) S3method(grobHeight,zeroGrob) @@ -443,7 +442,6 @@ export(ggproto) export(ggproto_parent) export(ggsave) export(ggtitle) -export(gtable_ggplot) export(guide_axis) export(guide_axis_logticks) export(guide_axis_stack) diff --git a/R/plot-build.R b/R/plot-build.R index aacda0d362..4ad5202f8e 100644 --- a/R/plot-build.R +++ b/R/plot-build.R @@ -196,12 +196,12 @@ layer_grob <- get_layer_grob #' @keywords internal #' @param data plot data generated by [ggplot_build()] #' @export -gtable_ggplot <- S7::new_generic("gtable_ggplot", "data", function(data) { +ggplot_gtable <- function(data) { attach_plot_env(data@plot@plot_env) - S7::S7_dispatch() -}) + UseMethod("ggplot_gtable") +} -S7::method(gtable_ggplot, class_ggplot_built) <- function(data) { +S7::method(ggplot_gtable, class_ggplot_built) <- function(data) { plot <- data@plot layout <- data@layout data <- data@data @@ -302,18 +302,6 @@ S7::method(gtable_ggplot, class_ggplot_built) <- function(data) { plot_table } -# TODO: the S3 generic should be phased out once S7 is adopted more widely -#' @rdname gtable_ggplot -#' @export -ggplot_gtable <- function(data) { - UseMethod("ggplot_gtable") -} - -#' @export -ggplot_gtable.default <- function(data) { - gtable_ggplot(data) -} - #' Generate a ggplot2 plot grob. #' #' @param x ggplot2 object diff --git a/man/gtable_ggplot.Rd b/man/ggplot_gtable.Rd similarity index 94% rename from man/gtable_ggplot.Rd rename to man/ggplot_gtable.Rd index 3d02793a54..5f8cbe9057 100644 --- a/man/gtable_ggplot.Rd +++ b/man/ggplot_gtable.Rd @@ -1,12 +1,9 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/plot-build.R -\name{gtable_ggplot} -\alias{gtable_ggplot} +\name{ggplot_gtable} \alias{ggplot_gtable} \title{Build a plot with all the usual bits and pieces.} \usage{ -gtable_ggplot(data) - ggplot_gtable(data) } \arguments{ From 2efa829bd42a02afc9b178415833f4aa18700b19 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 09:39:20 +0200 Subject: [PATCH 03/10] remove `draw_element()` in favour of `element_grob()` --- NAMESPACE | 2 -- R/theme-elements.R | 28 ++++++++---------------- man/{draw_element.Rd => element_grob.Rd} | 5 +---- 3 files changed, 10 insertions(+), 25 deletions(-) rename man/{draw_element.Rd => element_grob.Rd} (88%) diff --git a/NAMESPACE b/NAMESPACE index e512bd6e0b..4500be5d5d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -29,7 +29,6 @@ S3method(autolayer,default) S3method(autoplot,default) S3method(c,mapped_discrete) S3method(drawDetails,zeroGrob) -S3method(element_grob,default) S3method(format,ggproto) S3method(format,ggproto_method) S3method(format,rd_section_aesthetics) @@ -318,7 +317,6 @@ export(cut_width) export(datetime_scale) export(derive) export(discrete_scale) -export(draw_element) export(draw_key_abline) export(draw_key_blank) export(draw_key_boxplot) diff --git a/R/theme-elements.R b/R/theme-elements.R index 09f8c96a13..047e86f5bf 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -463,11 +463,13 @@ element_render <- function(theme, element, ..., name = NULL) { #' usually at least position. See the source code for individual methods. #' @keywords internal #' @export -draw_element <- S7::new_generic("draw_element", "element") +element_grob <- function(element, ...) { + UseMethod("element_grob") +} -S7::method(draw_element, element_blank) <- function(element, ...) zeroGrob() +S7::method(element_grob, element_blank) <- function(element, ...) zeroGrob() -S7::method(draw_element, element_rect) <- +S7::method(element_grob, element_rect) <- function(element, x = 0.5, y = 0.5, width = 1, height = 1, fill = NULL, colour = NULL, linewidth = NULL, linetype = NULL, linejoin = NULL, @@ -486,7 +488,7 @@ S7::method(draw_element, element_rect) <- rectGrob(x, y, width, height, gp = modify_list(element_gp, gp), ...) } -S7::method(draw_element, element_text) <- +S7::method(element_grob, element_text) <- function(element, label = "", x = NULL, y = NULL, family = NULL, face = NULL, colour = NULL, size = NULL, hjust = NULL, vjust = NULL, angle = NULL, lineheight = NULL, @@ -519,7 +521,7 @@ S7::method(draw_element, element_text) <- margin_x = margin_x, margin_y = margin_y, debug = element@debug, ...) } -S7::method(draw_element, element_line) <- +S7::method(element_grob, element_line) <- function(element, x = 0:1, y = 0:1, colour = NULL, linewidth = NULL, linetype = NULL, lineend = NULL, linejoin = NULL, arrow.fill = NULL, @@ -558,7 +560,7 @@ S7::method(draw_element, element_line) <- ) } -S7::method(draw_element, element_polygon) <- +S7::method(element_grob, element_polygon) <- function(element, x = c(0, 0.5, 1, 0.5), y = c(0.5, 1, 0.5, 0), fill = NULL, colour = NULL, linewidth = NULL, @@ -580,7 +582,7 @@ S7::method(draw_element, element_polygon) <- ) } -S7::method(draw_element, element_point) <- +S7::method(element_grob, element_point) <- function(element, x = 0.5, y = 0.5, colour = NULL, shape = NULL, fill = NULL, size = NULL, stroke = NULL, ..., @@ -594,18 +596,6 @@ S7::method(draw_element, element_point) <- default.units = default.units, ...) } -# TODO: the S3 generic should be phased out once S7 is adopted more widely -#' @rdname draw_element -#' @export -element_grob <- function(element, ...) { - UseMethod("element_grob") -} - -#' @export -element_grob.default <- function(element, ...) { - draw_element(element, ...) -} - #' Define and register new theme elements #' #' The underlying structure of a ggplot2 theme is defined via the element tree, which diff --git a/man/draw_element.Rd b/man/element_grob.Rd similarity index 88% rename from man/draw_element.Rd rename to man/element_grob.Rd index 0fe2510351..21fed0352a 100644 --- a/man/draw_element.Rd +++ b/man/element_grob.Rd @@ -1,12 +1,9 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/theme-elements.R -\name{draw_element} -\alias{draw_element} +\name{element_grob} \alias{element_grob} \title{Generate grid grob from theme element} \usage{ -draw_element(element, ...) - element_grob(element, ...) } \arguments{ From 6603eb505931c5487c1ca92bd07c0a550a74a87a Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 09:50:46 +0200 Subject: [PATCH 04/10] Use `S7::method()` for element getters/setters --- NAMESPACE | 6 ---- R/theme-elements.R | 70 ++++++++++++++++++++++------------------------ 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 4500be5d5d..2db5ac0835 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,25 +1,19 @@ # Generated by roxygen2: do not edit by hand -S3method("$","ggplot2::element") S3method("$","ggplot2::gg") S3method("$","ggplot2::theme") S3method("$",ggproto) S3method("$",ggproto_parent) -S3method("$<-","ggplot2::element") S3method("$<-","ggplot2::gg") S3method("$<-","ggplot2::mapping") -S3method("[","ggplot2::element") S3method("[","ggplot2::gg") S3method("[","ggplot2::mapping") S3method("[",mapped_discrete) -S3method("[<-","ggplot2::element") S3method("[<-","ggplot2::gg") S3method("[<-","ggplot2::mapping") S3method("[<-",mapped_discrete) -S3method("[[","ggplot2::element") S3method("[[","ggplot2::gg") S3method("[[",ggproto) -S3method("[[<-","ggplot2::element") S3method("[[<-","ggplot2::gg") S3method("[[<-","ggplot2::mapping") S3method(.DollarNames,ggproto) diff --git a/R/theme-elements.R b/R/theme-elements.R index 047e86f5bf..05ecfc4edb 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -383,44 +383,40 @@ rel <- function(x) { structure(x, class = "rel") } -#' @export -`$.ggplot2::element` <- function(x, i) { - # deprecate_soft0("4.1.0", I("`$i`"), I("`@i`")) - `[[`(S7::props(x), i) -} - -#' @export -`[.ggplot2::element` <- function(x, i) { - # deprecate_soft0("4.1.0", I("`[i]`"), I("`S7::props(, i)`")) - `[`(S7::props(x), i) -} - -#' @export -`[[.ggplot2::element` <- function(x, i) { - # deprecate_soft0("4.1.0", I("`[[i]]`"), I("`S7::prop(, i)`")) - `[[`(S7::props(x), i) -} - -#' @export -`$<-.ggplot2::element` <- function(x, i, value) { - # deprecate_soft0("4.1.0", I("`$i <- value`"), I("`@i <- value`")) - S7::props(x) <- `[[<-`(S7::props(x), i, value) - x -} - -#' @export -`[<-.ggplot2::element` <- function(x, i, value) { - # deprecate_soft0("4.1.0", I("`[i] <- value`"), I("`S7::props()[i] <- value`")) - S7::props(x) <- `[<-`(S7::props(x), i, value) - x -} +# Element getter methods +local({ + S7::method(`$`, element) <- function(x, i) { + # deprecate_soft0("4.1.0", I("`$i`"), I("`@i`")) + `[[`(S7::props(x), i) + } + S7::method(`[`, element) <- function(x, i) { + # deprecate_soft0("4.1.0", I("`[i]`"), I("`S7::props(, i)`")) + `[`(S7::props(x), i) + } + S7::method(`[[`, element) <- function(x, i) { + # deprecate_soft0("4.1.0", I("`[[i]]`"), I("`S7::prop(, i)`")) + `[[`(S7::props(x), i) + } +}) -#' @export -`[[<-.ggplot2::element` <- function(x, i, value) { - # deprecate_soft0("4.1.0", I("`[[i]] <- value`"), I("S7::prop(, i) <- value")) - S7::props(x) <- `[[<-`(S7::props(x), i, value) - x -} +# Element setter methods +local({ + S7::method(`$<-`, element) <- function(x, i, value) { + # deprecate_soft0("4.1.0", I("`$i <- value`"), I("`@i <- value`")) + S7::props(x) <- `[[<-`(S7::props(x), i, value) + x + } + S7::method(`[<-`, element) <- function(x, i, value) { + # deprecate_soft0("4.1.0", I("`[i] <- value`"), I("`S7::props()[i] <- value`")) + S7::props(x) <- `[<-`(S7::props(x), i, value) + x + } + S7::method(`[[<-`, element) <- function(x, i, value) { + # deprecate_soft0("4.1.0", I("`[[i]] <- value`"), I("S7::prop(, i) <- value")) + S7::props(x) <- `[[<-`(S7::props(x), i, value) + x + } +}) #' @export print.rel <- function(x, ...) print(noquote(paste(x, " *", sep = ""))) From b47faa0a7dbe32f0ee658bbe1dc6a101f4a1b506 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 10:06:45 +0200 Subject: [PATCH 05/10] Use `S7::method()` for gg getters/setters --- NAMESPACE | 6 ----- R/plot.R | 72 +++++++++++++++++++++++++------------------------------ 2 files changed, 32 insertions(+), 46 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 2db5ac0835..32d7a6a50b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,20 +1,14 @@ # Generated by roxygen2: do not edit by hand -S3method("$","ggplot2::gg") S3method("$","ggplot2::theme") S3method("$",ggproto) S3method("$",ggproto_parent) -S3method("$<-","ggplot2::gg") S3method("$<-","ggplot2::mapping") -S3method("[","ggplot2::gg") S3method("[","ggplot2::mapping") S3method("[",mapped_discrete) -S3method("[<-","ggplot2::gg") S3method("[<-","ggplot2::mapping") S3method("[<-",mapped_discrete) -S3method("[[","ggplot2::gg") S3method("[[",ggproto) -S3method("[[<-","ggplot2::gg") S3method("[[<-","ggplot2::mapping") S3method(.DollarNames,ggproto) S3method(as.data.frame,mapped_discrete) diff --git a/R/plot.R b/R/plot.R index 19511bcc46..1aea113eaf 100644 --- a/R/plot.R +++ b/R/plot.R @@ -231,49 +231,41 @@ S7::method(plot, class_ggplot) <- `print.ggplot2::ggplot` # The following extractors and subassignment operators are for a smooth # transition and should be deprecated in the release cycle after 4.0.0 -# TODO: should convert to proper S7 method once bug in S7 is resolved - -#' @export -`$.ggplot2::gg` <- function(x, i) { - if (!S7::prop_exists(x, i) && S7::prop_exists(x, "meta")) { - # This is a trick to bridge a gap between S3 and S7. We're allowing - # for arbitrary fields by reading/writing to the 'meta' field when the - # index does not point to an actual property. - # The proper way to go about this is to implement new fields as properties - # of a ggplot subclass. - S7::prop(x, "meta")[[i]] - } else { - `[[`(S7::props(x), i) +local({ + S7::method(`[[`, class_gg) <- S7::method(`$`, class_gg) <- + function(x, i) { + if (!S7::prop_exists(x, i) && S7::prop_exists(x, "meta")) { + # This is a trick to bridge a gap between S3 and S7. We're allowing + # for arbitrary fields by reading/writing to the 'meta' field when the + # index does not point to an actual property. + # The proper way to go about this is to implement new fields as properties + # of a ggplot subclass. + S7::prop(x, "meta")[[i]] + } else { + `[[`(S7::props(x), i) + } + } + S7::method(`[`, class_gg) <- function(x, i) { + `[`(S7::props(x), i) } -} +}) -#' @export -`$<-.ggplot2::gg` <- function(x, i, value) { - if (!S7::prop_exists(x, i) && S7::prop_exists(x, "meta")) { - # See explanation in `$.ggplot2::gg` - S7::prop(x, "meta")[[i]] <- value - } else { - S7::props(x) <- `[[<-`(S7::props(x), i, value) +local({ + S7::method(`$<-`, class_gg) <- S7::method(`[[<-`, class_gg) <- + function(x, i, value) { + if (!S7::prop_exists(x, i) && S7::prop_exists(x, "meta")) { + # See explanation in `$.ggplot2::gg` + S7::prop(x, "meta")[[i]] <- value + } else { + S7::props(x) <- `[[<-`(S7::props(x), i, value) + } + x + } + S7::method(`[<-`, class_gg) <- function(x, i, value) { + S7::props(x) <- `[<-`(S7::props(x), i, value) + x } - x -} - -#' @export -`[.ggplot2::gg` <- function(x, i) { - `[`(S7::props(x), i) -} - -#' @export -`[<-.ggplot2::gg` <- function(x, i, value) { - S7::props(x) <- `[<-`(S7::props(x), i, value) - x -} - -#' @export -`[[.ggplot2::gg` <- `$.ggplot2::gg` - -#' @export -`[[<-.ggplot2::gg` <- `$<-.ggplot2::gg` +}) #' @importFrom S7 convert # S7 currently attaches the S3 method to the calling environment which gives `ggplot2:::as.list` From 03157ef4c9c823f7091c516ca5988b18764c7877 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 10:38:54 +0200 Subject: [PATCH 06/10] Use `S7::method()` for class_mapping getters/setters --- DESCRIPTION | 2 +- NAMESPACE | 4 ---- R/aes.R | 32 +++++++++++++------------------- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 1deed8f79e..043254db43 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -93,10 +93,10 @@ Collate: 'aes-group-order.R' 'aes-linetype-size-shape.R' 'aes-position.R' + 'all-classes.R' 'compat-plyr.R' 'utilities.R' 'aes.R' - 'all-classes.R' 'annotation-borders.R' 'utilities-checks.R' 'legend-draw.R' diff --git a/NAMESPACE b/NAMESPACE index 32d7a6a50b..333896bb06 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,13 +3,9 @@ S3method("$","ggplot2::theme") S3method("$",ggproto) S3method("$",ggproto_parent) -S3method("$<-","ggplot2::mapping") -S3method("[","ggplot2::mapping") S3method("[",mapped_discrete) -S3method("[<-","ggplot2::mapping") S3method("[<-",mapped_discrete) S3method("[[",ggproto) -S3method("[[<-","ggplot2::mapping") S3method(.DollarNames,ggproto) S3method(as.data.frame,mapped_discrete) S3method(as.list,ggproto) diff --git a/R/aes.R b/R/aes.R index 5c55cee556..6699b1e7e9 100644 --- a/R/aes.R +++ b/R/aes.R @@ -1,4 +1,4 @@ -#' @include utilities.R compat-plyr.R +#' @include utilities.R compat-plyr.R all-classes.R NULL #' Construct aesthetic mappings @@ -147,25 +147,19 @@ new_aesthetic <- function(x, env = globalenv()) { invisible(x) } -# TODO: should convert to proper S7 method once bug in S7 is resolved -#' @export -"[.ggplot2::mapping" <- function(x, i, ...) { - class_mapping(NextMethod()) -} -# If necessary coerce replacements to quosures for compatibility -#' @export -"[[<-.ggplot2::mapping" <- function(x, i, value) { - class_mapping(NextMethod()) -} -#' @export -"$<-.ggplot2::mapping" <- function(x, i, value) { - class_mapping(NextMethod()) -} -#' @export -"[<-.ggplot2::mapping" <- function(x, i, value) { - class_mapping(NextMethod()) -} +local({ + S7::method(`[`, class_mapping) <- function(x, i, ...) { + class_mapping(`[`(S7::S7_data(x), i, ...)) + } + S7::method(`$<-`, class_mapping) <- S7::method(`[[<-`, class_mapping) <- + function(x, i, value) { + class_mapping(`[[<-`(S7::S7_data(x), i, value)) + } + S7::method(`[<-`, class_mapping) <- function(x, i, value) { + class_mapping(`[<-`(S7::S7_data(x), i, value)) + } +}) #' Standardise aesthetic names #' From 2a672a1e00047917b2a2c6e17d0f22eb6a56cb3e Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 10:39:22 +0200 Subject: [PATCH 07/10] Use `S7::method()` for class_theme getter --- NAMESPACE | 1 - R/theme.R | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 333896bb06..362da52029 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -S3method("$","ggplot2::theme") S3method("$",ggproto) S3method("$",ggproto_parent) S3method("[",mapped_discrete) diff --git a/R/theme.R b/R/theme.R index e6ee33d1a8..dd0e61df1c 100644 --- a/R/theme.R +++ b/R/theme.R @@ -1050,10 +1050,11 @@ combine_s3_elements <- function(e1, e2) { return(e1) } -#' @export -`$.ggplot2::theme` <- function(x, ...) { - .subset2(x, ...) -} +local({ + S7::method(`$`, class_theme) <- function(x, ...) { + .subset2(x, ...) + } +}) #' @export `print.ggplot2::theme` <- function(x, ...) utils::str(x) From a7f91527f963fc1ea110d9e419c9f83476c2b8f0 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 10:45:59 +0200 Subject: [PATCH 08/10] Use `S7::method(print)` for S7 classes --- NAMESPACE | 4 ---- R/aes.R | 26 ++++++++++---------- R/plot.R | 58 ++++++++++++++++++++++----------------------- R/theme-elements.R | 7 ++++-- R/theme.R | 6 ++--- man/print.ggplot.Rd | 6 +---- 6 files changed, 50 insertions(+), 57 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 362da52029..d49f0234b4 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -72,10 +72,6 @@ S3method(predictdf,default) S3method(predictdf,glm) S3method(predictdf,locfit) S3method(predictdf,loess) -S3method(print,"ggplot2::ggplot") -S3method(print,"ggplot2::mapping") -S3method(print,"ggplot2::theme") -S3method(print,element) S3method(print,ggplot2_bins) S3method(print,ggproto) S3method(print,ggproto_method) diff --git a/R/aes.R b/R/aes.R index 6699b1e7e9..16dc22aadd 100644 --- a/R/aes.R +++ b/R/aes.R @@ -131,22 +131,22 @@ new_aesthetic <- function(x, env = globalenv()) { } #' @export -# TODO: should convert to proper S7 method once bug in S7 is resolved -`print.ggplot2::mapping` <- function(x, ...) { - cat("Aesthetic mapping: \n") - - if (length(x) == 0) { - cat("\n") - } else { - values <- vapply(x, quo_label, character(1)) - bullets <- paste0("* ", format(paste0("`", names(x), "`")), " -> ", values, "\n") +local({ + S7::method(print, class_mapping) <- function(x, ...) { + cat("Aesthetic mapping: \n") - cat(bullets, sep = "") - } + if (length(x) == 0) { + cat("\n") + } else { + values <- vapply(x, quo_label, character(1)) + bullets <- paste0("* ", format(paste0("`", names(x), "`")), " -> ", values, "\n") - invisible(x) -} + cat(bullets, sep = "") + } + invisible(x) + } +}) local({ S7::method(`[`, class_mapping) <- function(x, i, ...) { diff --git a/R/plot.R b/R/plot.R index 1aea113eaf..135bd20b4b 100644 --- a/R/plot.R +++ b/R/plot.R @@ -179,10 +179,8 @@ is.ggplot <- function(x) { #' @param ... other arguments not used by this method #' @keywords hplot #' @return Invisibly returns the original plot. -#' @export -#' @method print ggplot2::ggplot #' @name print.ggplot -#' @aliases print.ggplot2::ggplot plot.ggplot2::ggplot +#' @aliases plot.ggplot #' @examples #' colours <- c("class", "drv", "fl") #' @@ -196,38 +194,38 @@ is.ggplot <- function(x) { #' print(ggplot(mpg, aes(displ, hwy, colour = .data[[colour]])) + #' geom_point()) #' } -# TODO: should convert to proper S7 method once bug in S7 is resolved -`print.ggplot2::ggplot` <- function(x, newpage = is.null(vp), vp = NULL, ...) { - set_last_plot(x) - if (newpage) grid.newpage() - - # Record dependency on 'ggplot2' on the display list - # (AFTER grid.newpage()) - grDevices::recordGraphics( - requireNamespace("ggplot2", quietly = TRUE), - list(), - getNamespace("ggplot2") - ) +local({ + S7::method(print, class_ggplot) <- S7::method(plot, class_ggplot) <- + function(x, newpage = is.null(vp), vp = NULL, ...) { + set_last_plot(x) + if (newpage) grid.newpage() - data <- ggplot_build(x) + # Record dependency on 'ggplot2' on the display list + # (AFTER grid.newpage()) + grDevices::recordGraphics( + requireNamespace("ggplot2", quietly = TRUE), + list(), + getNamespace("ggplot2") + ) - gtable <- ggplot_gtable(data) - if (is.null(vp)) { - grid.draw(gtable) - } else { - if (is.character(vp)) seekViewport(vp) else pushViewport(vp) - grid.draw(gtable) - upViewport() - } + data <- ggplot_build(x) - if (isTRUE(getOption("BrailleR.VI")) && rlang::is_installed("BrailleR")) { - print(asNamespace("BrailleR")$VI(x)) - } + gtable <- ggplot_gtable(data) + if (is.null(vp)) { + grid.draw(gtable) + } else { + if (is.character(vp)) seekViewport(vp) else pushViewport(vp) + grid.draw(gtable) + upViewport() + } - invisible(x) -} + if (isTRUE(getOption("BrailleR.VI")) && rlang::is_installed("BrailleR")) { + print(asNamespace("BrailleR")$VI(x)) + } -S7::method(plot, class_ggplot) <- `print.ggplot2::ggplot` + invisible(x) + } +}) # The following extractors and subassignment operators are for a smooth # transition and should be deprecated in the release cycle after 4.0.0 diff --git a/R/theme-elements.R b/R/theme-elements.R index 05ecfc4edb..9288956e4b 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -354,8 +354,11 @@ element_geom <- S7::new_class( fill = NULL, colour = NULL ) -#' @export -print.element <- function(x, ...) utils::str(x) +local({ + S7::method(print, element) <- function(x, ...) { + utils::str(x) + } +}) #' @export #' @param type For testing elements: the type of element to expect. One of diff --git a/R/theme.R b/R/theme.R index dd0e61df1c..63e410fb20 100644 --- a/R/theme.R +++ b/R/theme.R @@ -1054,7 +1054,7 @@ local({ S7::method(`$`, class_theme) <- function(x, ...) { .subset2(x, ...) } + S7::method(print, class_theme) <- function(x, ...) { + utils::str(x) + } }) - -#' @export -`print.ggplot2::theme` <- function(x, ...) utils::str(x) diff --git a/man/print.ggplot.Rd b/man/print.ggplot.Rd index 49b2b2dca7..ab8a86858b 100644 --- a/man/print.ggplot.Rd +++ b/man/print.ggplot.Rd @@ -2,12 +2,8 @@ % Please edit documentation in R/plot.R \name{print.ggplot} \alias{print.ggplot} -\alias{print.ggplot2::ggplot} -\alias{plot.ggplot2::ggplot} +\alias{plot.ggplot} \title{Explicitly draw plot} -\usage{ -\method{print}{`ggplot2::ggplot`}(x, newpage = is.null(vp), vp = NULL, ...) -} \arguments{ \item{x}{plot to display} From eae4374239c6d76af673ac3d47458ae1773c6304 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Fri, 4 Jul 2025 13:31:29 +0200 Subject: [PATCH 09/10] revert replacement functions --- NAMESPACE | 9 +++++++++ R/aes.R | 20 +++++++++++++------- R/plot.R | 33 ++++++++++++++++++--------------- R/theme-elements.R | 37 ++++++++++++++++++++----------------- 4 files changed, 60 insertions(+), 39 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index d49f0234b4..7a10c295d4 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,9 +2,18 @@ S3method("$",ggproto) S3method("$",ggproto_parent) +S3method("$<-","ggplot2::element") +S3method("$<-","ggplot2::gg") +S3method("$<-","ggplot2::mapping") S3method("[",mapped_discrete) +S3method("[<-","ggplot2::element") +S3method("[<-","ggplot2::gg") +S3method("[<-","ggplot2::mapping") S3method("[<-",mapped_discrete) S3method("[[",ggproto) +S3method("[[<-","ggplot2::element") +S3method("[[<-","ggplot2::gg") +S3method("[[<-","ggplot2::mapping") S3method(.DollarNames,ggproto) S3method(as.data.frame,mapped_discrete) S3method(as.list,ggproto) diff --git a/R/aes.R b/R/aes.R index 16dc22aadd..c1bb7570f1 100644 --- a/R/aes.R +++ b/R/aes.R @@ -152,15 +152,21 @@ local({ S7::method(`[`, class_mapping) <- function(x, i, ...) { class_mapping(`[`(S7::S7_data(x), i, ...)) } - S7::method(`$<-`, class_mapping) <- S7::method(`[[<-`, class_mapping) <- - function(x, i, value) { - class_mapping(`[[<-`(S7::S7_data(x), i, value)) - } - S7::method(`[<-`, class_mapping) <- function(x, i, value) { - class_mapping(`[<-`(S7::S7_data(x), i, value)) - } }) +#' @export +`[[<-.ggplot2::mapping` <- function(x, i, value) { + class_mapping(`[[<-`(S7::S7_data(x), i, value)) +} + +#' @export +`$<-.ggplot2::mapping` <- `[[<-.ggplot2::mapping` + +#' @export +`[<-.ggplot2::mapping` <- function(x, i, value) { + class_mapping(`[<-`(S7::S7_data(x), i, value)) +} + #' Standardise aesthetic names #' #' This function standardises aesthetic names by converting `color` to `colour` diff --git a/R/plot.R b/R/plot.R index 135bd20b4b..1b84a1e1b2 100644 --- a/R/plot.R +++ b/R/plot.R @@ -248,22 +248,25 @@ local({ } }) -local({ - S7::method(`$<-`, class_gg) <- S7::method(`[[<-`, class_gg) <- - function(x, i, value) { - if (!S7::prop_exists(x, i) && S7::prop_exists(x, "meta")) { - # See explanation in `$.ggplot2::gg` - S7::prop(x, "meta")[[i]] <- value - } else { - S7::props(x) <- `[[<-`(S7::props(x), i, value) - } - x - } - S7::method(`[<-`, class_gg) <- function(x, i, value) { - S7::props(x) <- `[<-`(S7::props(x), i, value) - x +#' @export +`[<-.ggplot2::gg` <- function(x, i, value) { + S7::props(x) <- `[<-`(S7::props(x), i, value) + x +} + +#' @export +`$<-.ggplot2::gg` <- function(x, i, value) { + if (!S7::prop_exists(x, i) && S7::prop_exists(x, "meta")) { + # See explanation in accessor + S7::prop(x, "meta")[[i]] <- value + } else { + S7::props(x) <- `[[<-`(S7::props(x), i, value) } -}) + x +} + +#' @export +`[[<-.ggplot2::gg` <- `$<-.ggplot2::gg` #' @importFrom S7 convert # S7 currently attaches the S3 method to the calling environment which gives `ggplot2:::as.list` diff --git a/R/theme-elements.R b/R/theme-elements.R index 9288956e4b..d0211b1f34 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -403,23 +403,26 @@ local({ }) # Element setter methods -local({ - S7::method(`$<-`, element) <- function(x, i, value) { - # deprecate_soft0("4.1.0", I("`$i <- value`"), I("`@i <- value`")) - S7::props(x) <- `[[<-`(S7::props(x), i, value) - x - } - S7::method(`[<-`, element) <- function(x, i, value) { - # deprecate_soft0("4.1.0", I("`[i] <- value`"), I("`S7::props()[i] <- value`")) - S7::props(x) <- `[<-`(S7::props(x), i, value) - x - } - S7::method(`[[<-`, element) <- function(x, i, value) { - # deprecate_soft0("4.1.0", I("`[[i]] <- value`"), I("S7::prop(, i) <- value")) - S7::props(x) <- `[[<-`(S7::props(x), i, value) - x - } -}) +#' @export +`$<-.ggplot2::element` <- function(x, i, value) { + # deprecate_soft0("4.1.0", I("`$i <- value`"), I("`@i <- value`")) + S7::props(x) <- `[[<-`(S7::props(x), i, value) + x +} + +#' @export +`[<-.ggplot2::element` <- function(x, i, value) { + # deprecate_soft0("4.1.0", I("`[i] <- value`"), I("`S7::props()[i] <- value`")) + S7::props(x) <- `[<-`(S7::props(x), i, value) + x +} + +#' @export +`[[<-.ggplot2::element` <- function(x, i, value) { + # deprecate_soft0("4.1.0", I("`[[i]] <- value`"), I("S7::prop(, i) <- value")) + S7::props(x) <- `[[<-`(S7::props(x), i, value) + x +} #' @export print.rel <- function(x, ...) print(noquote(paste(x, " *", sep = ""))) From a5756a8dd5074b1112b4f8d27c67933237d33714 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Mon, 7 Jul 2025 10:23:41 +0200 Subject: [PATCH 10/10] damn me and my stupid decisions sometimes --- R/plot-build.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/R/plot-build.R b/R/plot-build.R index 4ad5202f8e..8c1c1a0e8c 100644 --- a/R/plot-build.R +++ b/R/plot-build.R @@ -37,7 +37,9 @@ S7::method(ggplot_build, class_ggplot_built) <- function(plot, ...) { plot # This is a no-op } -S7::method(ggplot_build, class_ggplot) <- function(plot, ...) { +# The build_ggplot is a temporary concession to {thematic} after we put in +# a compatibility PR that uses this function +build_ggplot <- S7::method(ggplot_build, class_ggplot) <- function(plot, ...) { plot <- plot_clone(plot) if (length(plot@layers) == 0) { plot <- plot + geom_blank()