From 3b5480500477d3b67c3bca9e21423d56de05f64e Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 18 Jun 2025 23:18:55 +0200 Subject: [PATCH 01/11] include `class_guide` for completeness --- R/all-classes.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/all-classes.R b/R/all-classes.R index 23fb806578..a35dbbc4b1 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -14,6 +14,7 @@ class_gtable <- S7::new_S3_class("gtable") # they are their own thing. class_scale <- S7::new_S3_class("Scale") class_guides <- S7::new_S3_class("Guides") +class_guide <- S7::new_S3_class("Guide") class_coord <- S7::new_S3_class("Coord") class_facet <- S7::new_S3_class("Facet") class_layer <- S7::new_S3_class("Layer") From af99012a2eeb277b48f412b2bd2862e5af1b26d6 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 18 Jun 2025 23:19:20 +0200 Subject: [PATCH 02/11] structure indicators --- R/all-classes.R | 14 ++++++++++++++ man/class_labels.Rd | 3 +++ 2 files changed, 17 insertions(+) diff --git a/R/all-classes.R b/R/all-classes.R index a35dbbc4b1..ff7988c798 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -23,6 +23,8 @@ class_scales_list <- S7::new_S3_class("ScalesList") # User facing classes ----------------------------------------------------- +## Theme ------------------------------------------------------------------- + #' The theme class #' #' The theme class holds information on how non-data elements of the plot @@ -51,6 +53,8 @@ class_theme <- S7::new_class( } ) +## Labels ------------------------------------------------------------------ + #' The labels class #' #' The labels class holds a list with label information to display as titles @@ -59,6 +63,10 @@ class_theme <- S7::new_class( #' #' @param labels A named list. #' +#' @details +#' All members of `labels` are expected to be named and unique. +#' +#' #' @keywords internal #' @export class_labels <- S7::new_class( @@ -80,6 +88,8 @@ class_labels <- S7::new_class( } ) +## Mapping ----------------------------------------------------------------- + #' The mapping class #' #' The mapping class holds a list of quoted expressions @@ -102,6 +112,8 @@ class_mapping <- S7::new_class( } ) +## ggplot ------------------------------------------------------------------ + #' The ggplot class #' #' The ggplot class collects the needed information to render a plot. @@ -165,6 +177,8 @@ class_ggplot <- S7::new_class( } ) +## Built ggplot ------------------------------------------------------------ + #' The ggplot built class #' #' The ggplot built class is an intermediate class and represents a processed diff --git a/man/class_labels.Rd b/man/class_labels.Rd index 57788e666d..80d6408c6c 100644 --- a/man/class_labels.Rd +++ b/man/class_labels.Rd @@ -14,4 +14,7 @@ The labels class holds a list with label information to display as titles of plot components. The preferred way to construct an object of the labels class is to use the \code{\link[=labs]{labs()}} function. } +\details{ +All members of \code{labels} are expected to be named and unique. +} \keyword{internal} From a219cb9c2d22d8ac1a0b7aee070cc1e5b24f4ac3 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Wed, 18 Jun 2025 23:28:07 +0200 Subject: [PATCH 03/11] export & write documentation --- R/all-classes.R | 161 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 11 deletions(-) diff --git a/R/all-classes.R b/R/all-classes.R index ff7988c798..4e28119ab4 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -1,26 +1,165 @@ -# S3 classes -------------------------------------------------------------- +# Docs ------------------------------------------------------------- -# Meta classes: -# TODO: These should be replaced once R 4.3.0 is the minimum version as `+` -# dispatch should work as intended. -class_gg <- S7::new_class("gg", abstract = TRUE) -class_S3_gg <- S7::new_S3_class("gg") +#' Class definitions +#' +#' The S7 object oriented programming system requires class definitions. +#' Here, we provide definitions of classes that are home to ggplot2. +#' +#' @section S7 classes: +#' +#' A general advice the S7 package gives is to name class definition objects +#' the same as the class name, which then becomes the constructor for the class. +#' The classes listed below deviate from that advice for historical reasons, +#' because some constructors like `ggplot()` are also S3 generics with methods. +#' The have the `class_`-prefix to indicate their role. +#' +#' * [`class_ggplot`] is an S7 class used for objects generated by [ggplot()]. +#' * [`class_ggplot_built`] is an S7 class used for objects generated by +#' [ggplot_build()]. +#' * [`class_mapping`] is an S7 class used for objects generated by [aes()]. +#' * [`class_theme`] is an S7 class used for objects generated by [theme()]. +#' * [`class_labels`] is an S7 class used for objects generated by [labs()]. +#' +#' @section Theme elements: +#' +#' The theme elements follow the advice of the S7 package that the class names +#' are also the class definitions and constructors. +#' +#' * [`element`] is an abstract S7 class used to invoke similar behaviour among +#' theme element objects. +#' * [`element_blank`] is an S7 class for not drawing theme elements. +#' * [`element_rect`] is an S7 class for drawing rectangles. +#' * [`element_line`] is an S7 class for drawing lines. +#' * [`element_text`] is an S7 class for rendering text. +#' * [`element_polygon`] is an S7 class for drawing polygons. +#' * [`element_point`] is an S7 class for drawing points. +#' * [`element_geom`] is an S7 class holding geom defaults. +#' * [`margin`] is an S7 class for declaring margins. +#' +#' @section ggproto classes: +#' +#' The ggproto classes are S3 classes of the type environment that form the +#' backbone of most systems in ggplot2 and are in particular crucial to the +#' extension system. +#' +#' @section S3 classes: +#' +#' Some simple classes remain S3. +#' +#' @name class_definitions +NULL + +#' @rdname class_definitions +#' @section S7 classes: +#' * `class_gg` is an abstract S7 class to used invoke similar behaviour among +#' ggplot objects. +#' @export +#' @format NULL +#' @usage NULL +class_gg <- S7::new_class("gg", abstract = TRUE) + +# ggproto classes --------------------------------------------------------- -# Proper S3 classes we need awareness for +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_ggproto` is an S3 class used for the objects generated by +#' [ggproto()] which are of the type environment. +#' @export +#' @format NULL +#' @usage NULL class_ggproto <- S7::new_S3_class("ggproto") -class_gtable <- S7::new_S3_class("gtable") -# The important ggproto classes that we treat as S3 classes in S7 even though -# they are their own thing. -class_scale <- S7::new_S3_class("Scale") +# We don't own this class, so we don't export or describe it +class_gtable <- S7::new_S3_class("gtable") + +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_scale` is a subclass of `class_ggproto` and is more described in +#' the [Scale] documentation. +#' @export +#' @format NULL +#' @usage NULL +class_scale <- S7::new_S3_class("Scale") + +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_guides` is a subclass of `class_ggproto` and is considered an +#' internal class. +#' @export +#' @format NULL +#' @usage NULL class_guides <- S7::new_S3_class("Guides") + +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_guide` is a subclass of `class_ggproto` and is more described in the +#' [Guide] documentation. +#' @export +#' @format NULL +#' @usage NULL class_guide <- S7::new_S3_class("Guide") + +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_coord` is a subclass of `class_ggproto` and is more described in the +#' [Coord] documentation. +#' @export +#' @format NULL +#' @usage NULL class_coord <- S7::new_S3_class("Coord") + + +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_facet` is a subclass of `class_ggproto` and is more described in the +#' [Facet] documentation. +#' @export +#' @format NULL +#' @usage NULL class_facet <- S7::new_S3_class("Facet") + +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_layer` is a subclass of `class_ggproto` and is used for the objects +#' generated by [layer()]. The class itself is considered internal and is +#' described in more detail in the [Layer] documentation. +#' @export +#' @format NULL +#' @usage NULL class_layer <- S7::new_S3_class("Layer") + +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_layout` is a subclass of `class_ggproto` and is considered an +#' internal class. It is described in more detail in the [Layout] +#' documentation. +#' @export +#' @format NULL +#' @usage NULL class_layout <- S7::new_S3_class("Layout") + +#' @rdname class_definitions +#' @section ggproto classes: +#' * `class_scales_list` is a subclass of `class_ggproto` and is considered an +#' internal class. +#' @export +#' @format NULL +#' @usage NULL class_scales_list <- S7::new_S3_class("ScalesList") +# S3 classes -------------------------------------------------------------- + +#' @rdname class_definitions +#' @section S3 classes: +#' * `r lifecycle::badge("superseded")` `class_S3_gg` is a temporary S3 class +#' until R 4.3.0 is the minimum supported version. It is exported and +#' listed here for completeness, but its use is heavily discouraged. It +#' is superseded by `class_gg`. +#' @export +#' @format NULL +#' @usage NULL +class_S3_gg <- S7::new_S3_class("gg") + # User facing classes ----------------------------------------------------- ## Theme ------------------------------------------------------------------- From 5be9fc6e5b73de8c044c6e1b5204e89602a83a21 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 19 Jun 2025 09:00:22 +0200 Subject: [PATCH 04/11] tmp --- R/all-classes.R | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/R/all-classes.R b/R/all-classes.R index 4e28119ab4..7634f33feb 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -44,7 +44,8 @@ #' #' @section S3 classes: #' -#' Some simple classes remain S3. +#' Some simple classes remain S3, primarily because they aren't meant to be +#' recycled into new classes. #' #' @name class_definitions NULL @@ -160,6 +161,38 @@ class_scales_list <- S7::new_S3_class("ScalesList") #' @usage NULL class_S3_gg <- S7::new_S3_class("gg") +#' @rdname class_definitions +#' @section S3 classes: +#' * `class_rel` is an S3 class used in [element] properties. +#' @export +#' @format NULL +#' @usage NULL +class_rel <- S7::new_S3_class("rel") + +#' @rdname class_definitions +#' @section S3 classes: +#' * `class_zero_grob` is an S3 class used to indicate empty drawings. +#' @export +#' @format NULL +#' @usage NULL +class_zero_grob <- S7::new_S3_class("zeroGrob") + +#' @rdname class_definitions +#' @section S3 classes: +#' * `class_waiver` is an S3 sentinel value class used in various places. +#' @export +#' @format NULL +#' @usage NULL +class_waiver <- S7::new_S3_class("waiver") + +#' @rdname class_definitions +#' @section S3 classes: +#' * `class_derive` is an S3 sentinel value class used primarily in [sec_axis()]. +#' @export +#' @format NULL +#' @usage NULL +class_derive <- S7::new_S3_class("derive") + # User facing classes ----------------------------------------------------- ## Theme ------------------------------------------------------------------- From fda521e3eade9c1fdbe83d9900f3b6d8bed5723e Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 3 Jul 2025 12:12:52 +0200 Subject: [PATCH 05/11] roxygenate --- NAMESPACE | 15 ++++ man/class_definitions.Rd | 168 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 man/class_definitions.Rd diff --git a/NAMESPACE b/NAMESPACE index 5893c8bb5a..284d21da05 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -295,11 +295,26 @@ export(borders) export(build_ggplot) export(calc_element) export(check_device) +export(class_S3_gg) +export(class_coord) +export(class_derive) +export(class_facet) +export(class_gg) export(class_ggplot) export(class_ggplot_built) +export(class_ggproto) +export(class_guide) +export(class_guides) export(class_labels) +export(class_layer) +export(class_layout) export(class_mapping) +export(class_rel) +export(class_scale) +export(class_scales_list) export(class_theme) +export(class_waiver) +export(class_zero_grob) export(combine_vars) export(complete_theme) export(continuous_scale) diff --git a/man/class_definitions.Rd b/man/class_definitions.Rd new file mode 100644 index 0000000000..a7f5262845 --- /dev/null +++ b/man/class_definitions.Rd @@ -0,0 +1,168 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/all-classes.R +\docType{data} +\name{class_definitions} +\alias{class_definitions} +\alias{class_gg} +\alias{class_ggproto} +\alias{class_scale} +\alias{class_guides} +\alias{class_guide} +\alias{class_coord} +\alias{class_facet} +\alias{class_layer} +\alias{class_layout} +\alias{class_scales_list} +\alias{class_S3_gg} +\alias{class_rel} +\alias{class_zero_grob} +\alias{class_waiver} +\alias{class_derive} +\title{Class definitions} +\description{ +The S7 object oriented programming system requires class definitions. +Here, we provide definitions of classes that are home to ggplot2. +} +\section{S7 classes}{ + + +A general advice the S7 package gives is to name class definition objects +the same as the class name, which then becomes the constructor for the class. +The classes listed below deviate from that advice for historical reasons, +because some constructors like \code{ggplot()} are also S3 generics with methods. +The have the \code{class_}-prefix to indicate their role. +\itemize{ +\item \code{\link{class_ggplot}} is an S7 class used for objects generated by \code{\link[=ggplot]{ggplot()}}. +\item \code{\link{class_ggplot_built}} is an S7 class used for objects generated by +\code{\link[=ggplot_build]{ggplot_build()}}. +\item \code{\link{class_mapping}} is an S7 class used for objects generated by \code{\link[=aes]{aes()}}. +\item \code{\link{class_theme}} is an S7 class used for objects generated by \code{\link[=theme]{theme()}}. +\item \code{\link{class_labels}} is an S7 class used for objects generated by \code{\link[=labs]{labs()}}. +} + + +\itemize{ +\item \code{class_gg} is an abstract S7 class to used invoke similar behaviour among +ggplot objects. +} +} + +\section{Theme elements}{ + + +The theme elements follow the advice of the S7 package that the class names +are also the class definitions and constructors. +\itemize{ +\item \code{\link{element}} is an abstract S7 class used to invoke similar behaviour among +theme element objects. +\item \code{\link{element_blank}} is an S7 class for not drawing theme elements. +\item \code{\link{element_rect}} is an S7 class for drawing rectangles. +\item \code{\link{element_line}} is an S7 class for drawing lines. +\item \code{\link{element_text}} is an S7 class for rendering text. +\item \code{\link{element_polygon}} is an S7 class for drawing polygons. +\item \code{\link{element_point}} is an S7 class for drawing points. +\item \code{\link{element_geom}} is an S7 class holding geom defaults. +\item \code{\link{margin}} is an S7 class for declaring margins. +} +} + +\section{ggproto classes}{ + + +The ggproto classes are S3 classes of the type environment that form the +backbone of most systems in ggplot2 and are in particular crucial to the +extension system. + + +\itemize{ +\item \code{class_ggproto} is an S3 class used for the objects generated by +\code{\link[=ggproto]{ggproto()}} which are of the type environment. +} + + +\itemize{ +\item \code{class_scale} is a subclass of \code{class_ggproto} and is more described in +the \link{Scale} documentation. +} + + +\itemize{ +\item \code{class_guides} is a subclass of \code{class_ggproto} and is considered an +internal class. +} + + +\itemize{ +\item \code{class_guide} is a subclass of \code{class_ggproto} and is more described in the +\link{Guide} documentation. +} + + +\itemize{ +\item \code{class_coord} is a subclass of \code{class_ggproto} and is more described in the +\link{Coord} documentation. +} + + +\itemize{ +\item \code{class_facet} is a subclass of \code{class_ggproto} and is more described in the +\link{Facet} documentation. +} + + +\itemize{ +\item \code{class_layer} is a subclass of \code{class_ggproto} and is used for the objects +generated by \code{\link[=layer]{layer()}}. The class itself is considered internal and is +described in more detail in the \link{Layer} documentation. +} + + +\itemize{ +\item \code{class_layout} is a subclass of \code{class_ggproto} and is considered an +internal class. It is described in more detail in the \link{Layout} +documentation. +} + + +\itemize{ +\item \code{class_scales_list} is a subclass of \code{class_ggproto} and is considered an +internal class. +} +} + +\section{S3 classes}{ + + +Some simple classes remain S3, primarily because they aren't meant to be +recycled into new classes. + + +\itemize{ +\item \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} \code{class_S3_gg} is a temporary S3 class +until R 4.3.0 is the minimum supported version. It is exported and +listed here for completeness, but its use is heavily discouraged. It +is superseded by \code{class_gg}. +} + + +\itemize{ +\item \code{class_rel} is an S3 class used in \link{element} properties. +} + + +\itemize{ +\item \code{class_zero_grob} is an S3 class used to indicate empty drawings. +} + + +\itemize{ +\item \code{class_waiver} is an S3 sentinel value class used in various places. +} + + +\itemize{ +\item \code{class_derive} is an S3 sentinel value class used primarily in \code{\link[=sec_axis]{sec_axis()}}. +} +} + +\keyword{datasets} From 9ae0cb78edd4e7dd2af8f436890c7b9da7f8532b Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 3 Jul 2025 13:57:05 +0200 Subject: [PATCH 06/11] All constructors have `...` as argument. --- R/all-classes.R | 40 ++++++++++++++++++++++++++++----------- R/margins.R | 4 ++-- R/theme-elements.R | 16 +++++++++------- man/class_ggplot.Rd | 5 ++++- man/class_ggplot_built.Rd | 4 +++- man/class_labels.Rd | 6 ++++-- man/class_mapping.Rd | 4 +++- man/class_theme.Rd | 4 +++- man/element.Rd | 22 ++++++++++++++------- 9 files changed, 72 insertions(+), 33 deletions(-) diff --git a/R/all-classes.R b/R/all-classes.R index 7634f33feb..a33d256b59 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -207,6 +207,7 @@ class_derive <- S7::new_S3_class("derive") #' @param complete A boolean value stating whether a theme is complete. #' @param validate A boolean value stating whether a theme should still be #' validated. +#' @param ... Reserved for future expansion. #' #' @keywords internal #' @export @@ -216,7 +217,7 @@ class_theme <- S7::new_class( complete = S7::class_logical, validate = S7::class_logical ), - constructor = function(elements, complete, validate) { + constructor = function(elements, complete, validate, ...) { S7::new_object( elements, complete = complete, @@ -234,6 +235,7 @@ class_theme <- S7::new_class( #' class is to use the [`labs()`] function. #' #' @param labels A named list. +#' @param ... Reserved for future expansion. #' #' @details #' All members of `labels` are expected to be named and unique. @@ -243,7 +245,9 @@ class_theme <- S7::new_class( #' @export class_labels <- S7::new_class( "labels", parent = class_S3_gg, - constructor = function(labels) S7::new_object(labels), + constructor = function(labels, ...) { + S7::new_object(labels) + }, validator = function(self) { if (!is.list(self)) { return("labels must be a list.") @@ -270,12 +274,13 @@ class_labels <- S7::new_class( #' #' @param x A list of quosures and constants. #' @param env An environment for symbols that are not quosures or constants. +#' @param ... Reserved for future expansion. #' #' @keywords internal #' @export class_mapping <- S7::new_class( "mapping", parent = class_S3_gg, - constructor = function(x, env = globalenv()) { + constructor = function(x, env = globalenv(), ...) { check_object(x, is.list, "a {.cls list}") x <- lapply(x, new_aesthetic, env = env) x <- S7::new_object(x) @@ -306,6 +311,7 @@ class_mapping <- S7::new_class( #' @param meta A list for additional metadata. This will be deprecated in the #' future. #' @param plot_env An environment. +#' @param ... Reserved for future expansion. #' #' @keywords internal #' @export @@ -325,12 +331,21 @@ class_ggplot <- S7::new_class( meta = S7::class_list, plot_env = S7::class_environment ), - constructor = function(data = waiver(), layers = list(), scales = NULL, - guides = NULL, mapping = aes(), theme = NULL, - coordinates = coord_cartesian(default = TRUE), - facet = facet_null(), layout = NULL, - labels = labs(), meta = list(), - plot_env = parent.frame()) { + constructor = function( + data = waiver(), + layers = list(), + scales = NULL, + guides = NULL, + mapping = aes(), + theme = NULL, + coordinates = coord_cartesian(default = TRUE), + facet = facet_null(), + layout = NULL, + labels = labs(), + meta = list(), + plot_env = parent.frame(), + ... + ) { S7::new_object( S7::S7_object(), data = data, @@ -362,6 +377,7 @@ class_ggplot <- S7::new_class( #' @param data A list of plain data frames; one for each layer. #' @param layout A Layout ggproto object. #' @param plot A completed ggplot class object. +#' @param ... Reserved for future expansion. #' #' @keywords internal #' @export @@ -372,7 +388,7 @@ class_ggplot_built <- S7::new_class( layout = class_layout, plot = class_ggplot ), - constructor = function(data = NULL, layout = NULL, plot = NULL) { + constructor = function(data = NULL, layout = NULL, plot = NULL, ...) { if (is.null(data) || is.null(layout) || is.null(plot)) { cli::cli_abort( "The {.cls ggplot_built} class should be constructed by {.fn ggplot_build}." @@ -380,7 +396,9 @@ class_ggplot_built <- S7::new_class( } S7::new_object( S7::S7_object(), - data = data, layout = layout, plot = plot + data = data, + layout = layout, + plot = plot ) } ) diff --git a/R/margins.R b/R/margins.R index 15a27520a1..8f8624d500 100644 --- a/R/margins.R +++ b/R/margins.R @@ -7,7 +7,7 @@ #' @export margin <- S7::new_class( "margin", parent = S7::new_S3_class(c("simpleUnit", "unit", "unit_v2")), - constructor = function(t = 0, r = 0, b = 0, l = 0, unit = "pt") { + constructor = function(t = 0, r = 0, b = 0, l = 0, unit = "pt", ...) { lens <- c(length(t), length(r), length(b), length(l)) if (any(lens != 1)) { incorrect <- c("t", "r", "b", "l")[lens != 1] @@ -41,7 +41,7 @@ margin_part <- function(t = NA, r = NA, b = NA, l = NA, unit = "pt") { #' @rdname element #' @export margin_auto <- function(t = 0, r = t, b = t, l = r, unit = "pt") { - margin(t = t, r = r, b = b, l = l, unit) + margin(t = t, r = r, b = b, l = l, unit = unit) } as_margin <- function(x, x_arg = caller_arg(x), call = caller_env()) { diff --git a/R/theme-elements.R b/R/theme-elements.R index 09f8c96a13..1ea630acdb 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -33,6 +33,8 @@ #' a blank element among its parents will cause this element to be blank as #' well. If `FALSE` any blank parent element will be ignored when #' calculating final element state. +#' @param ... Reserved for future expansion. +#' #' @return An object of class `element`, `rel`, or `margin`. #' @details #' The `element_polygon()` and `element_point()` functions are not rendered @@ -137,7 +139,7 @@ element_rect <- S7::new_class( "inherit.blank")], constructor = function(fill = NULL, colour = NULL, linewidth = NULL, linetype = NULL, color = NULL, linejoin = NULL, - inherit.blank = FALSE, size = deprecated()){ + inherit.blank = FALSE, size = deprecated(), ...){ if (lifecycle::is_present(size)) { deprecate_warn0("3.4.0", "element_rect(size)", "element_rect(linewidth)") linewidth <- size @@ -171,7 +173,7 @@ element_line <- S7::new_class( constructor = function(colour = NULL, linewidth = NULL, linetype = NULL, lineend = NULL, color = NULL, linejoin = NULL, arrow = NULL, arrow.fill = NULL, - inherit.blank = FALSE, size = deprecated()) { + inherit.blank = FALSE, size = deprecated(), ...) { if (lifecycle::is_present(size)) { deprecate_warn0("3.4.0", "element_line(size)", "element_line(linewidth)") linewidth <- size @@ -225,7 +227,7 @@ element_text <- S7::new_class( constructor = function(family = NULL, face = NULL, colour = NULL, size = NULL, hjust = NULL, vjust = NULL, angle = NULL, lineheight = NULL, color = NULL, margin = NULL, - debug = NULL, inherit.blank = FALSE) { + debug = NULL, inherit.blank = FALSE, ...) { n <- max( length(family), length(face), length(colour), length(size), length(hjust), length(vjust), length(angle), length(lineheight) @@ -269,7 +271,7 @@ element_polygon <- S7::new_class( )], constructor = function(fill = NULL, colour = NULL, linewidth = NULL, linetype = NULL, color = NULL, linejoin = NULL, - inherit.blank = FALSE) { + inherit.blank = FALSE, ...) { colour <- color %||% colour S7::new_object( S7::S7_object(), @@ -290,7 +292,7 @@ element_point <- S7::new_class( c("linewidth" = "stroke") ), constructor = function(colour = NULL, shape = NULL, size = NULL, fill = NULL, - stroke = NULL, color = NULL, inherit.blank = FALSE) { + stroke = NULL, color = NULL, inherit.blank = FALSE, ...) { S7::new_object( S7::S7_object(), colour = color %||% colour, fill = fill, shape = shape, size = size, @@ -327,8 +329,8 @@ element_geom <- S7::new_class( linetype = NULL, bordertype = NULL, family = NULL, fontsize = NULL, pointsize = NULL, pointshape = NULL, - colour = NULL, color = NULL, fill = NULL) { - + colour = NULL, color = NULL, fill = NULL, + ...) { if (!is.null(fontsize)) { fontsize <- fontsize / .pt } diff --git a/man/class_ggplot.Rd b/man/class_ggplot.Rd index 05b4f3e0df..4372587f78 100644 --- a/man/class_ggplot.Rd +++ b/man/class_ggplot.Rd @@ -16,7 +16,8 @@ class_ggplot( layout = NULL, labels = labs(), meta = list(), - plot_env = parent.frame() + plot_env = parent.frame(), + ... ) } \arguments{ @@ -46,6 +47,8 @@ functions.} future.} \item{plot_env}{An environment.} + +\item{...}{Reserved for future expansion.} } \description{ The ggplot class collects the needed information to render a plot. diff --git a/man/class_ggplot_built.Rd b/man/class_ggplot_built.Rd index 4e87451998..5502005484 100644 --- a/man/class_ggplot_built.Rd +++ b/man/class_ggplot_built.Rd @@ -4,7 +4,7 @@ \alias{class_ggplot_built} \title{The ggplot built class} \usage{ -class_ggplot_built(data = NULL, layout = NULL, plot = NULL) +class_ggplot_built(data = NULL, layout = NULL, plot = NULL, ...) } \arguments{ \item{data}{A list of plain data frames; one for each layer.} @@ -12,6 +12,8 @@ class_ggplot_built(data = NULL, layout = NULL, plot = NULL) \item{layout}{A Layout ggproto object.} \item{plot}{A completed ggplot class object.} + +\item{...}{Reserved for future expansion.} } \description{ The ggplot built class is an intermediate class and represents a processed diff --git a/man/class_labels.Rd b/man/class_labels.Rd index 80d6408c6c..9c94e05f13 100644 --- a/man/class_labels.Rd +++ b/man/class_labels.Rd @@ -4,10 +4,12 @@ \alias{class_labels} \title{The labels class} \usage{ -class_labels(labels) +class_labels(labels, ...) } \arguments{ \item{labels}{A named list.} + +\item{...}{Reserved for future expansion.} } \description{ The labels class holds a list with label information to display as titles @@ -15,6 +17,6 @@ of plot components. The preferred way to construct an object of the labels class is to use the \code{\link[=labs]{labs()}} function. } \details{ -All members of \code{labels} are expected to be named and unique. +All members of \code{labels} are expected to be named and names should be unique. } \keyword{internal} diff --git a/man/class_mapping.Rd b/man/class_mapping.Rd index 63f75456d3..8d62fc46a8 100644 --- a/man/class_mapping.Rd +++ b/man/class_mapping.Rd @@ -4,12 +4,14 @@ \alias{class_mapping} \title{The mapping class} \usage{ -class_mapping(x, env = globalenv()) +class_mapping(x, env = globalenv(), ...) } \arguments{ \item{x}{A list of quosures and constants.} \item{env}{An environment for symbols that are not quosures or constants.} + +\item{...}{Reserved for future expansion.} } \description{ The mapping class holds a list of quoted expressions diff --git a/man/class_theme.Rd b/man/class_theme.Rd index ab3a03ef1d..0bdf7f63de 100644 --- a/man/class_theme.Rd +++ b/man/class_theme.Rd @@ -4,7 +4,7 @@ \alias{class_theme} \title{The theme class} \usage{ -class_theme(elements, complete, validate) +class_theme(elements, complete, validate, ...) } \arguments{ \item{elements}{A named list containing theme elements.} @@ -13,6 +13,8 @@ class_theme(elements, complete, validate) \item{validate}{A boolean value stating whether a theme should still be validated.} + +\item{...}{Reserved for future expansion.} } \description{ The theme class holds information on how non-data elements of the plot diff --git a/man/element.Rd b/man/element.Rd index 8411711999..a1a528921d 100644 --- a/man/element.Rd +++ b/man/element.Rd @@ -15,7 +15,7 @@ \alias{rel} \title{Theme elements} \usage{ -margin(t = 0, r = 0, b = 0, l = 0, unit = "pt") +margin(t = 0, r = 0, b = 0, l = 0, unit = "pt", ...) margin_part(t = NA, r = NA, b = NA, l = NA, unit = "pt") @@ -33,7 +33,8 @@ element_rect( color = NULL, linejoin = NULL, inherit.blank = FALSE, - size = deprecated() + size = deprecated(), + ... ) element_line( @@ -46,7 +47,8 @@ element_line( arrow = NULL, arrow.fill = NULL, inherit.blank = FALSE, - size = deprecated() + size = deprecated(), + ... ) element_text( @@ -61,7 +63,8 @@ element_text( color = NULL, margin = NULL, debug = NULL, - inherit.blank = FALSE + inherit.blank = FALSE, + ... ) element_polygon( @@ -71,7 +74,8 @@ element_polygon( linetype = NULL, color = NULL, linejoin = NULL, - inherit.blank = FALSE + inherit.blank = FALSE, + ... ) element_point( @@ -81,7 +85,8 @@ element_point( fill = NULL, stroke = NULL, color = NULL, - inherit.blank = FALSE + inherit.blank = FALSE, + ... ) element_geom( @@ -98,7 +103,8 @@ element_geom( pointshape = NULL, colour = NULL, color = NULL, - fill = NULL + fill = NULL, + ... ) rel(x) @@ -109,6 +115,8 @@ rel(x) \item{unit}{Default units of dimensions. Defaults to "pt" so it can be most easily scaled with the text.} +\item{...}{Reserved for future expansion.} + \item{fill}{Fill colour. \code{fill_alpha()} can be used to set the transparency of the fill.} From 898c944bc523615115abdceff5abe04600465d5a Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 3 Jul 2025 13:57:23 +0200 Subject: [PATCH 07/11] warn about `...` when not empty --- R/all-classes.R | 7 ++++++- R/margins.R | 1 + R/theme-elements.R | 6 ++++++ R/utilities.R | 10 ++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/R/all-classes.R b/R/all-classes.R index a33d256b59..a43c41f6a9 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -218,6 +218,7 @@ class_theme <- S7::new_class( validate = S7::class_logical ), constructor = function(elements, complete, validate, ...) { + warn_dots_empty() S7::new_object( elements, complete = complete, @@ -238,7 +239,7 @@ class_theme <- S7::new_class( #' @param ... Reserved for future expansion. #' #' @details -#' All members of `labels` are expected to be named and unique. +#' All members of `labels` are expected to be named and names should be unique. #' #' #' @keywords internal @@ -246,6 +247,7 @@ class_theme <- S7::new_class( class_labels <- S7::new_class( "labels", parent = class_S3_gg, constructor = function(labels, ...) { + warn_dots_empty() S7::new_object(labels) }, validator = function(self) { @@ -281,6 +283,7 @@ class_labels <- S7::new_class( class_mapping <- S7::new_class( "mapping", parent = class_S3_gg, constructor = function(x, env = globalenv(), ...) { + warn_dots_empty() check_object(x, is.list, "a {.cls list}") x <- lapply(x, new_aesthetic, env = env) x <- S7::new_object(x) @@ -346,6 +349,7 @@ class_ggplot <- S7::new_class( plot_env = parent.frame(), ... ) { + warn_dots_empty() S7::new_object( S7::S7_object(), data = data, @@ -389,6 +393,7 @@ class_ggplot_built <- S7::new_class( plot = class_ggplot ), constructor = function(data = NULL, layout = NULL, plot = NULL, ...) { + warn_dots_empty() if (is.null(data) || is.null(layout) || is.null(plot)) { cli::cli_abort( "The {.cls ggplot_built} class should be constructed by {.fn ggplot_build}." diff --git a/R/margins.R b/R/margins.R index 8f8624d500..af52156d5d 100644 --- a/R/margins.R +++ b/R/margins.R @@ -8,6 +8,7 @@ margin <- S7::new_class( "margin", parent = S7::new_S3_class(c("simpleUnit", "unit", "unit_v2")), constructor = function(t = 0, r = 0, b = 0, l = 0, unit = "pt", ...) { + warn_dots_empty() lens <- c(length(t), length(r), length(b), length(l)) if (any(lens != 1)) { incorrect <- c("t", "r", "b", "l")[lens != 1] diff --git a/R/theme-elements.R b/R/theme-elements.R index 1ea630acdb..be246c1dfe 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -140,6 +140,7 @@ element_rect <- S7::new_class( constructor = function(fill = NULL, colour = NULL, linewidth = NULL, linetype = NULL, color = NULL, linejoin = NULL, inherit.blank = FALSE, size = deprecated(), ...){ + warn_dots_empty() if (lifecycle::is_present(size)) { deprecate_warn0("3.4.0", "element_rect(size)", "element_rect(linewidth)") linewidth <- size @@ -174,6 +175,7 @@ element_line <- S7::new_class( lineend = NULL, color = NULL, linejoin = NULL, arrow = NULL, arrow.fill = NULL, inherit.blank = FALSE, size = deprecated(), ...) { + warn_dots_empty() if (lifecycle::is_present(size)) { deprecate_warn0("3.4.0", "element_line(size)", "element_line(linewidth)") linewidth <- size @@ -228,6 +230,7 @@ element_text <- S7::new_class( size = NULL, hjust = NULL, vjust = NULL, angle = NULL, lineheight = NULL, color = NULL, margin = NULL, debug = NULL, inherit.blank = FALSE, ...) { + warn_dots_empty() n <- max( length(family), length(face), length(colour), length(size), length(hjust), length(vjust), length(angle), length(lineheight) @@ -272,6 +275,7 @@ element_polygon <- S7::new_class( constructor = function(fill = NULL, colour = NULL, linewidth = NULL, linetype = NULL, color = NULL, linejoin = NULL, inherit.blank = FALSE, ...) { + warn_dots_empty() colour <- color %||% colour S7::new_object( S7::S7_object(), @@ -293,6 +297,7 @@ element_point <- S7::new_class( ), constructor = function(colour = NULL, shape = NULL, size = NULL, fill = NULL, stroke = NULL, color = NULL, inherit.blank = FALSE, ...) { + warn_dots_empty() S7::new_object( S7::S7_object(), colour = color %||% colour, fill = fill, shape = shape, size = size, @@ -331,6 +336,7 @@ element_geom <- S7::new_class( pointsize = NULL, pointshape = NULL, colour = NULL, color = NULL, fill = NULL, ...) { + warn_dots_empty() if (!is.null(fontsize)) { fontsize <- fontsize / .pt } diff --git a/R/utilities.R b/R/utilities.R index ec375b723e..348430fd12 100644 --- a/R/utilities.R +++ b/R/utilities.R @@ -850,6 +850,16 @@ warn_dots_used <- function(env = caller_env(), call = caller_env()) { ) } +warn_dots_empty <- function(env = caller_env(), call = caller_env()) { + check_dots_empty( + env = env, call = call, + error = function(cnd) { + msg <- gsub("\n", "\f", cnd_message(cnd)) + cli::cli_warn(msg, call = call) + } + ) +} + # TODO: Replace me if rlang/#1730 gets implemented # Similar to `rlang::check_installed()` but returns boolean and misses # features such as versions, comparisons and using {pak}. From 519b4e9f5742ff0c0beaaa9af973eef169c3b990 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 3 Jul 2025 14:21:07 +0200 Subject: [PATCH 08/11] simplify test --- man/continuous_scale.Rd | 2 +- tests/testthat/test-theme.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/continuous_scale.Rd b/man/continuous_scale.Rd index 76d7492ba6..f834d6cd00 100644 --- a/man/continuous_scale.Rd +++ b/man/continuous_scale.Rd @@ -17,7 +17,7 @@ continuous_scale( rescaler = rescale, oob = censor, expand = waiver(), - na.value = NA_real_, + na.value = NA, transform = "identity", trans = deprecated(), guide = "legend", diff --git a/tests/testthat/test-theme.R b/tests/testthat/test-theme.R index af5a304cdb..889304ce64 100644 --- a/tests/testthat/test-theme.R +++ b/tests/testthat/test-theme.R @@ -146,7 +146,7 @@ test_that("calculating theme element inheritance works", { # Check that inheritance from derived class works element_dummyrect <- S7::new_class( "element_dummyrect", parent = element_rect, - properties = c(element_rect@properties, list(dummy = S7::class_any)) + properties = list(dummy = S7::class_any) ) e <- calc_element( From f2d78adbd10a8c6a155b6036791bc2c0b466ea3d Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 3 Jul 2025 14:23:44 +0200 Subject: [PATCH 09/11] bump version per @schloerke's request --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 1deed8f79e..9e9bf500ce 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: ggplot2 Title: Create Elegant Data Visualisations Using the Grammar of Graphics -Version: 3.5.2.9001 +Version: 3.5.2.9002 Authors@R: c( person("Hadley", "Wickham", , "hadley@posit.co", role = "aut", comment = c(ORCID = "0000-0003-4757-117X")), From 28033f6ad57e79add5547e37249709f67bd1a7f9 Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 3 Jul 2025 15:51:15 +0200 Subject: [PATCH 10/11] mark docpage as internal --- R/all-classes.R | 1 + man/class_definitions.Rd | 1 + 2 files changed, 2 insertions(+) diff --git a/R/all-classes.R b/R/all-classes.R index a43c41f6a9..19bdad6ab3 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -48,6 +48,7 @@ #' recycled into new classes. #' #' @name class_definitions +#' @keywords internal NULL #' @rdname class_definitions diff --git a/man/class_definitions.Rd b/man/class_definitions.Rd index a7f5262845..3b638cf6d9 100644 --- a/man/class_definitions.Rd +++ b/man/class_definitions.Rd @@ -166,3 +166,4 @@ is superseded by \code{class_gg}. } \keyword{datasets} +\keyword{internal} From 728f4e86c776af24120490dd0a2b1493c14ce21a Mon Sep 17 00:00:00 2001 From: Teun van den Brand Date: Thu, 3 Jul 2025 17:02:05 +0200 Subject: [PATCH 11/11] more strategic placement of `...`, thanks for the suggestion @schloerke! --- R/all-classes.R | 18 +++++++++--------- man/class_ggplot.Rd | 8 ++++---- man/class_ggplot_built.Rd | 6 +++--- man/class_mapping.Rd | 6 +++--- man/class_theme.Rd | 6 +++--- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/R/all-classes.R b/R/all-classes.R index 19bdad6ab3..23fe36cd78 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -205,10 +205,10 @@ class_derive <- S7::new_S3_class("derive") #' is through the [`theme()`] function. #' #' @param elements A named list containing theme elements. +#' @param ... Reserved for future expansion. #' @param complete A boolean value stating whether a theme is complete. #' @param validate A boolean value stating whether a theme should still be #' validated. -#' @param ... Reserved for future expansion. #' #' @keywords internal #' @export @@ -218,7 +218,7 @@ class_theme <- S7::new_class( complete = S7::class_logical, validate = S7::class_logical ), - constructor = function(elements, complete, validate, ...) { + constructor = function(elements, ..., complete, validate) { warn_dots_empty() S7::new_object( elements, @@ -276,14 +276,14 @@ class_labels <- S7::new_class( #' constructed using the [`aes()`] function. #' #' @param x A list of quosures and constants. -#' @param env An environment for symbols that are not quosures or constants. #' @param ... Reserved for future expansion. +#' @param env An environment for symbols that are not quosures or constants. #' #' @keywords internal #' @export class_mapping <- S7::new_class( "mapping", parent = class_S3_gg, - constructor = function(x, env = globalenv(), ...) { + constructor = function(x, ..., env = globalenv()) { warn_dots_empty() check_object(x, is.list, "a {.cls list}") x <- lapply(x, new_aesthetic, env = env) @@ -301,6 +301,7 @@ class_mapping <- S7::new_class( #' This class can be constructed using the [`ggplot()`] function. #' #' @param data A property containing any data coerced by [`fortify()`]. +#' @param ... Reserved for future expansion. #' @param layers A list of layer instances created by [`layer()`]. #' @param scales A ScalesList ggproto object. #' @param guides A Guides ggproto object created by [`guides()`]. @@ -315,7 +316,6 @@ class_mapping <- S7::new_class( #' @param meta A list for additional metadata. This will be deprecated in the #' future. #' @param plot_env An environment. -#' @param ... Reserved for future expansion. #' #' @keywords internal #' @export @@ -337,6 +337,7 @@ class_ggplot <- S7::new_class( ), constructor = function( data = waiver(), + ..., layers = list(), scales = NULL, guides = NULL, @@ -347,8 +348,7 @@ class_ggplot <- S7::new_class( layout = NULL, labels = labs(), meta = list(), - plot_env = parent.frame(), - ... + plot_env = parent.frame() ) { warn_dots_empty() S7::new_object( @@ -379,10 +379,10 @@ class_ggplot <- S7::new_class( #' instantiated directly. The class can be rendered to a gtable object by #' calling the [`ggplot_gtable()`] function on a ggplot built class object. #' +#' @param ... Reserved for future expansion. #' @param data A list of plain data frames; one for each layer. #' @param layout A Layout ggproto object. #' @param plot A completed ggplot class object. -#' @param ... Reserved for future expansion. #' #' @keywords internal #' @export @@ -393,7 +393,7 @@ class_ggplot_built <- S7::new_class( layout = class_layout, plot = class_ggplot ), - constructor = function(data = NULL, layout = NULL, plot = NULL, ...) { + constructor = function(..., data = NULL, layout = NULL, plot = NULL) { warn_dots_empty() if (is.null(data) || is.null(layout) || is.null(plot)) { cli::cli_abort( diff --git a/man/class_ggplot.Rd b/man/class_ggplot.Rd index 4372587f78..13e7de84c1 100644 --- a/man/class_ggplot.Rd +++ b/man/class_ggplot.Rd @@ -6,6 +6,7 @@ \usage{ class_ggplot( data = waiver(), + ..., layers = list(), scales = NULL, guides = NULL, @@ -16,13 +17,14 @@ class_ggplot( layout = NULL, labels = labs(), meta = list(), - plot_env = parent.frame(), - ... + plot_env = parent.frame() ) } \arguments{ \item{data}{A property containing any data coerced by \code{\link[=fortify]{fortify()}}.} +\item{...}{Reserved for future expansion.} + \item{layers}{A list of layer instances created by \code{\link[=layer]{layer()}}.} \item{scales}{A ScalesList ggproto object.} @@ -47,8 +49,6 @@ functions.} future.} \item{plot_env}{An environment.} - -\item{...}{Reserved for future expansion.} } \description{ The ggplot class collects the needed information to render a plot. diff --git a/man/class_ggplot_built.Rd b/man/class_ggplot_built.Rd index 5502005484..a52e45a0be 100644 --- a/man/class_ggplot_built.Rd +++ b/man/class_ggplot_built.Rd @@ -4,16 +4,16 @@ \alias{class_ggplot_built} \title{The ggplot built class} \usage{ -class_ggplot_built(data = NULL, layout = NULL, plot = NULL, ...) +class_ggplot_built(..., data = NULL, layout = NULL, plot = NULL) } \arguments{ +\item{...}{Reserved for future expansion.} + \item{data}{A list of plain data frames; one for each layer.} \item{layout}{A Layout ggproto object.} \item{plot}{A completed ggplot class object.} - -\item{...}{Reserved for future expansion.} } \description{ The ggplot built class is an intermediate class and represents a processed diff --git a/man/class_mapping.Rd b/man/class_mapping.Rd index 8d62fc46a8..715174a092 100644 --- a/man/class_mapping.Rd +++ b/man/class_mapping.Rd @@ -4,14 +4,14 @@ \alias{class_mapping} \title{The mapping class} \usage{ -class_mapping(x, env = globalenv(), ...) +class_mapping(x, ..., env = globalenv()) } \arguments{ \item{x}{A list of quosures and constants.} -\item{env}{An environment for symbols that are not quosures or constants.} - \item{...}{Reserved for future expansion.} + +\item{env}{An environment for symbols that are not quosures or constants.} } \description{ The mapping class holds a list of quoted expressions diff --git a/man/class_theme.Rd b/man/class_theme.Rd index 0bdf7f63de..e5c5db2d75 100644 --- a/man/class_theme.Rd +++ b/man/class_theme.Rd @@ -4,17 +4,17 @@ \alias{class_theme} \title{The theme class} \usage{ -class_theme(elements, complete, validate, ...) +class_theme(elements, ..., complete, validate) } \arguments{ \item{elements}{A named list containing theme elements.} +\item{...}{Reserved for future expansion.} + \item{complete}{A boolean value stating whether a theme is complete.} \item{validate}{A boolean value stating whether a theme should still be validated.} - -\item{...}{Reserved for future expansion.} } \description{ The theme class holds information on how non-data elements of the plot