Skip to content

Commit 90d644f

Browse files
committed
double dispatch for ggplot_add()
1 parent c37317b commit 90d644f

File tree

4 files changed

+81
-93
lines changed

4 files changed

+81
-93
lines changed

NAMESPACE

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,6 @@ S3method(get_alt_text,ggplot_built)
5454
S3method(get_alt_text,gtable)
5555
S3method(ggplot,"function")
5656
S3method(ggplot,default)
57-
S3method(ggplot_add,"NULL")
58-
S3method(ggplot_add,"function")
59-
S3method(ggplot_add,Coord)
60-
S3method(ggplot_add,Facet)
61-
S3method(ggplot_add,Guides)
62-
S3method(ggplot_add,Layer)
63-
S3method(ggplot_add,Scale)
64-
S3method(ggplot_add,by)
65-
S3method(ggplot_add,data.frame)
66-
S3method(ggplot_add,default)
67-
S3method(ggplot_add,list)
6857
S3method(ggplot_build,ggplot)
6958
S3method(ggplot_build,ggplot_built)
7059
S3method(ggplot_gtable,ggplot_built)

R/plot-construction.R

Lines changed: 81 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#' @include plot.R
2+
NULL
3+
14
#' Add components to a plot
25
#'
36
#' `+` is the key to constructing sophisticated ggplot2 graphics. It
@@ -52,7 +55,6 @@
5255
e2name <- deparse(substitute(e2))
5356

5457
if (is.theme(e1)) add_theme(e1, e2, e2name)
55-
else if (is.ggplot(e1)) add_ggplot(e1, e2, e2name)
5658
else if (is.ggproto(e1)) {
5759
cli::cli_abort(c(
5860
"Cannot add {.cls ggproto} objects together.",
@@ -61,10 +63,15 @@
6163
}
6264
}
6365

66+
S7::method(`+`, list(class_ggplot, S7::class_any)) <- function(e1, e2) {
67+
e2name <- deparse(substitute(e2, env = caller_env(2)))
68+
add_ggplot(e1, e2, e2name)
69+
}
70+
6471

6572
#' @rdname gg-add
6673
#' @export
67-
"%+%" <- `+.gg`
74+
"%+%" <- function(e1, e2) e1 + e2
6875

6976
add_ggplot <- function(p, object, objectname) {
7077
if (is.null(object)) return(p)
@@ -110,88 +117,88 @@ add_ggplot <- function(p, object, objectname) {
110117
#'
111118
#' # clean-up
112119
#' rm(ggplot_add.element_text)
113-
ggplot_add <- function(object, plot, object_name) {
114-
UseMethod("ggplot_add")
115-
}
116-
#' @export
117-
ggplot_add.default <- function(object, plot, object_name) {
118-
cli::cli_abort("Can't add {.var {object_name}} to a {.cls ggplot} object.")
119-
}
120-
#' @export
121-
ggplot_add.NULL <- function(object, plot, object_name) {
122-
plot
123-
}
124-
#' @export
125-
ggplot_add.data.frame <- function(object, plot, object_name) {
126-
plot@data <- object
127-
plot
128-
}
129-
#' @export
130-
ggplot_add.function <- function(object, plot, object_name) {
131-
cli::cli_abort(c(
132-
"Can't add {.var {object_name}} to a {.cls ggplot} object",
133-
"i" = "Did you forget to add parentheses, as in {.fn {object_name}}?"
134-
))
135-
}
120+
ggplot_add <- S7::new_generic("ggplot_add", c("object", "plot"))
136121

137-
#' @export
138-
ggplot_add.Scale <- function(object, plot, object_name) {
139-
plot@scales$add(object)
140-
plot
141-
}
142-
S7::method(ggplot_add, labs) <- function(object, plot, object_name) {
143-
update_labels(plot, object)
144-
}
145-
#' @export
146-
ggplot_add.Guides <- function(object, plot, object_name) {
147-
if (is.guides(plot@guides)) {
148-
# We clone the guides object to prevent modify-in-place of guides
122+
S7::method(ggplot_add, list(S7::class_any, class_ggplot)) <-
123+
function(object, plot, object_name, ...) {
124+
cli::cli_abort("Can't add {.var {object_name}} to a {.cls ggplot} object.")
125+
}
126+
127+
S7::method(ggplot_add, list(S7::class_function, class_ggplot)) <-
128+
function(object, plot, object_name, ...) {
129+
cli::cli_abort(c(
130+
"Can't add {.var {object_name}} to a {.cls ggplot} object",
131+
"i" = "Did you forget to add parentheses, as in {.fn {object_name}}?"
132+
))
133+
}
134+
135+
S7::method(ggplot_add, list(NULL, class_ggplot)) <-
136+
function(object, plot, ...) { plot }
137+
138+
S7::method(ggplot_add, list(S7::class_data.frame, class_ggplot)) <-
139+
function(object, plot, ...) { S7::set_props(plot, data = object) }
140+
141+
S7::method(ggplot_add, list(class_scale, class_ggplot)) <-
142+
function(object, plot, ...) {
143+
plot@scales$add(object)
144+
plot
145+
}
146+
147+
S7::method(ggplot_add, list(labs, class_ggplot)) <-
148+
function(object, plot, ...) { update_labels(plot, object) }
149+
150+
S7::method(ggplot_add, list(class_guides, class_ggplot)) <-
151+
function(object, plot, ...) {
149152
old <- plot@guides
150153
new <- ggproto(NULL, old)
151154
new$add(object)
152155
plot@guides <- new
153-
} else {
154-
plot@guides <- object
156+
plot
155157
}
156-
plot
157-
}
158-
S7::method(ggplot_add, mapping) <- function(object, plot, object_name) {
159-
plot@mapping <- mapping(defaults(object, plot@mapping))
160-
plot
161-
}
162-
#' @export
163-
ggplot_add.Coord <- function(object, plot, object_name) {
164-
if (!isTRUE(plot@coordinates$default)) {
165-
cli::cli_inform("Coordinate system already present. Adding new coordinate system, which will replace the existing one.")
158+
159+
S7::method(ggplot_add, list(mapping, class_ggplot)) <-
160+
function(object, plot, ...) {
161+
S7::set_props(plot, mapping = mapping(defaults(object, plot@mapping)))
166162
}
167163

168-
plot@coordinates <- object
169-
plot
170-
}
171-
#' @export
172-
ggplot_add.Facet <- function(object, plot, object_name) {
173-
plot@facet <- object
174-
plot
175-
}
176-
#' @export
177-
ggplot_add.list <- function(object, plot, object_name) {
178-
for (o in object) {
179-
plot <- ggplot_add(o, plot, object_name)
164+
S7::method(ggplot_add, list(theme, class_ggplot)) <-
165+
function(object, plot, ...) {
166+
S7::set_props(plot, theme = add_theme(plot@theme, object))
180167
}
181-
plot
182-
}
183-
#' @export
184-
ggplot_add.by <- function(object, plot, object_name) {
185-
ggplot_add.list(object, plot, object_name)
186-
}
187168

188-
#' @export
189-
ggplot_add.Layer <- function(object, plot, object_name) {
190-
layers_names <- new_layer_names(object, names2(plot@layers))
191-
plot@layers <- append(plot@layers, object)
192-
names(plot@layers) <- layers_names
193-
plot
194-
}
169+
S7::method(ggplot_add, list(class_coord, class_ggplot)) <-
170+
function(object, plot, ...) {
171+
if (!isTRUE(plot@coordinates$default)) {
172+
cli::cli_inform(c(
173+
"Coordinate system already present.",
174+
i = "Adding new coordinate system, which will replace the existing one."
175+
))
176+
}
177+
S7::set_props(plot, coordinates = object)
178+
}
179+
180+
S7::method(ggplot_add, list(class_facet, class_ggplot)) <-
181+
function(object, plot, ...) { S7::set_props(plot, facet = object) }
182+
183+
S7::method(ggplot_add, list(class_layer, class_ggplot)) <-
184+
function(object, plot, ...) {
185+
layers_names <- new_layer_names(object, names2(plot@layers))
186+
object <- setNames(append(plot@layers, object), layers_names)
187+
S7::set_props(plot, layers = object)
188+
}
189+
190+
S7::method(ggplot_add, list(S7::class_list, class_ggplot)) <-
191+
function(object, plot, object_name, ...) {
192+
for (o in object) {
193+
plot <- ggplot_add(o, plot, object_name)
194+
}
195+
plot
196+
}
197+
198+
S7::method(ggplot_add, list(S7::new_S3_class("by"), class_ggplot)) <-
199+
function(object, plot, object_name, ...) {
200+
ggplot_add(unclass(object), plot, object_name)
201+
}
195202

196203
new_layer_names <- function(layer, existing) {
197204

R/theme.R

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -565,11 +565,6 @@ theme <- S7::new_class(
565565
constructor = theme
566566
)
567567

568-
S7::method(ggplot_add, theme) <- function(object, plot, object_name, ...) {
569-
plot$theme <- add_theme(plot$theme, object)
570-
plot
571-
}
572-
573568
#' @export
574569
#' @rdname is_tests
575570
is.theme <- function(x) S7::S7_inherits(x, theme)

tests/testthat/_snaps/prohibited-functions.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@
5252
$geom_violin
5353
[1] "draw_quantiles"
5454
55-
$ggplot_add
56-
[1] "object_name"
57-
5855
$ggproto
5956
[1] "_class" "_inherit"
6057

0 commit comments

Comments
 (0)