Skip to content

Commit 3c16f9c

Browse files
thomasp85hadley
authored andcommitted
Allow addition of custom objects (#2309)
`add_to_ggplot()` generic for extending `+` to other classes
1 parent 4825054 commit 3c16f9c

File tree

4 files changed

+125
-40
lines changed

4 files changed

+125
-40
lines changed

NAMESPACE

+13
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ S3method(fortify,summary.glht)
3737
S3method(fortify,tbl)
3838
S3method(ggplot,data.frame)
3939
S3method(ggplot,default)
40+
S3method(ggplot_add,"NULL")
41+
S3method(ggplot_add,Coord)
42+
S3method(ggplot_add,Facet)
43+
S3method(ggplot_add,Layer)
44+
S3method(ggplot_add,Scale)
45+
S3method(ggplot_add,data.frame)
46+
S3method(ggplot_add,default)
47+
S3method(ggplot_add,guides)
48+
S3method(ggplot_add,labels)
49+
S3method(ggplot_add,list)
50+
S3method(ggplot_add,theme)
51+
S3method(ggplot_add,uneval)
4052
S3method(grid.draw,absoluteGrob)
4153
S3method(grid.draw,ggplot)
4254
S3method(grobHeight,absoluteGrob)
@@ -314,6 +326,7 @@ export(geom_vline)
314326
export(gg_dep)
315327
export(ggplot)
316328
export(ggplotGrob)
329+
export(ggplot_add)
317330
export(ggplot_build)
318331
export(ggplot_gtable)
319332
export(ggproto)

NEWS.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# ggplot2 2.2.1.9000
22

3+
* Custom objects can now be added using `+` if a `ggplot_add` method has been
4+
defined for the class of the object (@thomasp85).
5+
36
* Fix bug in secondary axis that would lead to incorrectly placed ticks with
47
strong transforms (@thomasp85, #1992)
58

R/plot-construction.r

+86-40
Original file line numberDiff line numberDiff line change
@@ -60,46 +60,92 @@ add_ggplot <- function(p, object, objectname) {
6060
if (is.null(object)) return(p)
6161

6262
p <- plot_clone(p)
63-
if (is.data.frame(object)) {
64-
p$data <- object
65-
} else if (is.theme(object)) {
66-
p$theme <- update_theme(p$theme, object)
67-
} else if (inherits(object, "Scale")) {
68-
p$scales$add(object)
69-
} else if (inherits(object, "labels")) {
70-
p <- update_labels(p, object)
71-
} else if (inherits(object, "guides")) {
72-
p <- update_guides(p, object)
73-
} else if (inherits(object, "uneval")) {
74-
p$mapping <- defaults(object, p$mapping)
75-
# defaults() doesn't copy class, so copy it.
76-
class(p$mapping) <- class(object)
77-
78-
labels <- lapply(object, deparse)
79-
names(labels) <- names(object)
80-
p <- update_labels(p, labels)
81-
} else if (is.Coord(object)) {
82-
p$coordinates <- object
83-
p
84-
} else if (is.facet(object)) {
85-
p$facet <- object
86-
p
87-
} else if (is.list(object)) {
88-
for (o in object) {
89-
p <- p %+% o
90-
}
91-
} else if (is.layer(object)) {
92-
p$layers <- append(p$layers, object)
93-
94-
# Add any new labels
95-
mapping <- make_labels(object$mapping)
96-
default <- make_labels(object$stat$default_aes)
97-
new_labels <- defaults(mapping, default)
98-
p$labels <- defaults(p$labels, new_labels)
99-
} else {
100-
stop("Don't know how to add ", objectname, " to a plot",
101-
call. = FALSE)
102-
}
63+
p <- ggplot_add(object, p, objectname)
10364
set_last_plot(p)
10465
p
10566
}
67+
#' Add custom objects to ggplot
68+
#'
69+
#' This generic allows you to add your own methods for adding custom objects to
70+
#' a ggplot with [+.gg].
71+
#'
72+
#' @param object An object to add to the plot
73+
#' @param plot The ggplot object to add `object` to
74+
#' @param object_name The name of the object to add
75+
#'
76+
#' @return A modified ggplot object
77+
#'
78+
#' @keywords internal
79+
#' @export
80+
ggplot_add <- function(object, plot, object_name) {
81+
UseMethod("ggplot_add")
82+
}
83+
#' @export
84+
ggplot_add.default <- function(object, plot, object_name) {
85+
stop("Don't know how to add ", object_name, " to a plot", call. = FALSE)
86+
}
87+
#' @export
88+
ggplot_add.NULL <- function(object, plot, object_name) {
89+
plot
90+
}
91+
#' @export
92+
ggplot_add.data.frame <- function(object, plot, object_name) {
93+
plot$data <- object
94+
plot
95+
}
96+
#' @export
97+
ggplot_add.theme <- function(object, plot, object_name) {
98+
plot$theme <- update_theme(plot$theme, object)
99+
plot
100+
}
101+
#' @export
102+
ggplot_add.Scale <- function(object, plot, object_name) {
103+
plot$scales$add(object)
104+
plot
105+
}
106+
#' @export
107+
ggplot_add.labels <- function(object, plot, object_name) {
108+
update_labels(plot, object)
109+
}
110+
#' @export
111+
ggplot_add.guides <- function(object, plot, object_name) {
112+
update_guides(plot, object)
113+
}
114+
#' @export
115+
ggplot_add.uneval <- function(object, plot, object_name) {
116+
plot$mapping <- defaults(object, plot$mapping)
117+
# defaults() doesn't copy class, so copy it.
118+
class(plot$mapping) <- class(object)
119+
120+
labels <- lapply(object, deparse)
121+
names(labels) <- names(object)
122+
update_labels(plot, labels)
123+
}
124+
#' @export
125+
ggplot_add.Coord <- function(object, plot, object_name) {
126+
plot$coordinates <- object
127+
plot
128+
}
129+
#' @export
130+
ggplot_add.Facet <- function(object, plot, object_name) {
131+
plot$facet <- object
132+
plot
133+
}
134+
#' @export
135+
ggplot_add.list <- function(object, plot, object_name) {
136+
for (o in object) {
137+
plot <- plot %+% o
138+
}
139+
plot
140+
}
141+
#' @export
142+
ggplot_add.Layer <- function(object, plot, object_name) {
143+
plot$layers <- append(plot$layers, object)
144+
145+
# Add any new labels
146+
mapping <- make_labels(object$mapping)
147+
default <- make_labels(object$stat$default_aes)
148+
new_labels <- defaults(mapping, default)
149+
plot$labels <- defaults(plot$labels, new_labels)
150+
plot
151+
}

man/ggplot_add.Rd

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)