Skip to content

Commit d57ce4c

Browse files
teunbrandthomasp85
andauthored
Reimplement classes in S7 (#6364)
* add S7 as import * custom properties for theme elements * convert theme elements to S7 classes * adapt element definitions * convert element_grob to S7 generic * replace merge_element by S7 * implement `$.element` for backward compatibility * Use S7 properties * fix `inherits()` issues * fix misc issues * Revert "implement `$.element` for backward compatibility" This reverts commit b038e8f. * don't rely on `element$prop` * move element properties * convert `margin` to S7 * I liked index properties as an idea but apparently they print badly * adapt failing example * import S7 * convert theme to S7 * Reimplement S3 <uneval> into S7 <mapping> * convert labels to S7 * make S7 class_ggplot * Use `@` as accessor * double dispatch for `ggplot_add()` * Write methods for external generics as S7 * backward compatibility for ggplot class * Implement <ggplot_built> as S7 * implement `as.gtable` methods * rename mapping to class_mapping * refine class_ggplot_built and related functions * also access ggplot_built slots with normal extractors * resolve gnarlyness in S3/S7 method conflicts * fix esoteric 'promise already under evaluation' error * fix series of minor issues * export theme as class * export labels class * collect classes in one place * revert @include decisions * Make S7 generic of `get_alt_text()` * backport `@` * exempt classes from pkgdown * lol at my incompetence * allow variant error messages * workaround for old R versions * update pkgdown index * backport `@` * S7-aware `is_theme_element()` * utility for grabbing props * use classic extractors and subassignment * fallback for `register_theme_elements()` * contingencies for `inherits(x, <S7>)` on old R versions * use `is_theme()` * sprinkle notes * bump staged deprecations * add linejoins * Disable `ggtext::element_markdown()` example * fix failing tests * redocument * fix doc links * soft-deprecate `%+%` * simplify logic block * don't evaluate code temporarily in FAQ example * run revdepcheck * recover from S3 mappings * enable classic subsetting for ggplot_built * fix typo * prevent NSE shenannigans * avoid `%+%` in test code * add 'meta' property to track arbitrary fields * document new property * fix stretchy guide bug * backward compatibility for `ggplot_add()` * backward compatibility for `ggplot_add()` * notes for the future * backward compatibility for `ggplot_gtable()` * backwards compatibility for `element_grob()` * keep theme class * add news bullet * redirect other news * add `italic`/`fontweight`/`fontwidth` properties (#6458) * contingencies for old elements * left out null/blank handling to from methods to generic * also merge s3 elements * revdepcheck * remove outdated duplicate * append old element classes * append old uneval class * append old ggplot classes * allow for numeric `face` * Symmetry between `$` and `[[` methods * Revert `ggplot()` constructor to S3 * fallback for unit margins * repair invalid theme * make `rotate_just()` resilient for mixed S3/S7 classes * redocument/snapshot * revdepcheck * contend with vector input * unify mapping validation * more carefullyl extract margins * try to prevent cyclical `+` * include snapshots * protection against vectorised input * fix typo * add `as.list()` method * be fussy about margin input length * tiny version bump * allow numeric colour * defend against insanity --------- Co-authored-by: Thomas Lin Pedersen <[email protected]>
1 parent f7da3b4 commit d57ce4c

File tree

107 files changed

+37697
-14184
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+37697
-14184
lines changed

DESCRIPTION

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: ggplot2
22
Title: Create Elegant Data Visualisations Using the Grammar of Graphics
3-
Version: 3.5.2.9000
3+
Version: 3.5.2.9001
44
Authors@R: c(
55
person("Hadley", "Wickham", , "[email protected]", role = "aut",
66
comment = c(ORCID = "0000-0003-4757-117X")),
@@ -40,6 +40,7 @@ Imports:
4040
isoband,
4141
lifecycle (> 1.0.1),
4242
rlang (>= 1.1.0),
43+
S7,
4344
scales (>= 1.4.0),
4445
stats,
4546
vctrs (>= 0.6.0),
@@ -95,6 +96,7 @@ Collate:
9596
'compat-plyr.R'
9697
'utilities.R'
9798
'aes.R'
99+
'all-classes.R'
98100
'annotation-borders.R'
99101
'utilities-checks.R'
100102
'legend-draw.R'
@@ -181,6 +183,8 @@ Collate:
181183
'grob-dotstack.R'
182184
'grob-null.R'
183185
'grouping.R'
186+
'properties.R'
187+
'margins.R'
184188
'theme-elements.R'
185189
'guide-.R'
186190
'guide-axis.R'
@@ -204,7 +208,6 @@ Collate:
204208
'layer-sf.R'
205209
'layout.R'
206210
'limits.R'
207-
'margins.R'
208211
'performance.R'
209212
'plot-build.R'
210213
'plot-construction.R'

NAMESPACE

Lines changed: 36 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,35 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
S3method("$","ggplot2::element")
4+
S3method("$","ggplot2::gg")
5+
S3method("$","ggplot2::theme")
36
S3method("$",ggproto)
47
S3method("$",ggproto_parent)
5-
S3method("$",theme)
6-
S3method("$<-",uneval)
7-
S3method("+",gg)
8+
S3method("$<-","ggplot2::element")
9+
S3method("$<-","ggplot2::gg")
10+
S3method("$<-","ggplot2::mapping")
11+
S3method("[","ggplot2::element")
12+
S3method("[","ggplot2::gg")
13+
S3method("[","ggplot2::mapping")
814
S3method("[",mapped_discrete)
9-
S3method("[",uneval)
15+
S3method("[<-","ggplot2::element")
16+
S3method("[<-","ggplot2::gg")
17+
S3method("[<-","ggplot2::mapping")
1018
S3method("[<-",mapped_discrete)
11-
S3method("[<-",uneval)
19+
S3method("[[","ggplot2::element")
20+
S3method("[[","ggplot2::gg")
1221
S3method("[[",ggproto)
13-
S3method("[[<-",uneval)
22+
S3method("[[<-","ggplot2::element")
23+
S3method("[[<-","ggplot2::gg")
24+
S3method("[[<-","ggplot2::mapping")
1425
S3method(.DollarNames,ggproto)
1526
S3method(as.data.frame,mapped_discrete)
16-
S3method(as.gtable,ggplot)
17-
S3method(as.gtable,ggplot_built)
1827
S3method(as.list,ggproto)
1928
S3method(autolayer,default)
2029
S3method(autoplot,default)
2130
S3method(c,mapped_discrete)
2231
S3method(drawDetails,zeroGrob)
23-
S3method(element_grob,element_blank)
24-
S3method(element_grob,element_line)
25-
S3method(element_grob,element_point)
26-
S3method(element_grob,element_polygon)
27-
S3method(element_grob,element_rect)
28-
S3method(element_grob,element_text)
32+
S3method(element_grob,default)
2933
S3method(format,ggproto)
3034
S3method(format,ggproto_method)
3135
S3method(format,rd_section_aesthetics)
@@ -52,30 +56,12 @@ S3method(fortify,sfg)
5256
S3method(fortify,summary.glht)
5357
S3method(fortify,tbl)
5458
S3method(fortify,tbl_df)
55-
S3method(get_alt_text,ggplot)
56-
S3method(get_alt_text,ggplot_built)
57-
S3method(get_alt_text,gtable)
5859
S3method(ggplot,"function")
5960
S3method(ggplot,default)
60-
S3method(ggplot_add,"NULL")
61-
S3method(ggplot_add,"function")
62-
S3method(ggplot_add,Coord)
63-
S3method(ggplot_add,Facet)
64-
S3method(ggplot_add,Guides)
65-
S3method(ggplot_add,Layer)
66-
S3method(ggplot_add,Scale)
67-
S3method(ggplot_add,by)
68-
S3method(ggplot_add,data.frame)
6961
S3method(ggplot_add,default)
70-
S3method(ggplot_add,labels)
71-
S3method(ggplot_add,list)
72-
S3method(ggplot_add,theme)
73-
S3method(ggplot_add,uneval)
74-
S3method(ggplot_build,ggplot)
75-
S3method(ggplot_build,ggplot_built)
76-
S3method(ggplot_gtable,ggplot_built)
62+
S3method(ggplot_build,default)
63+
S3method(ggplot_gtable,default)
7764
S3method(grid.draw,absoluteGrob)
78-
S3method(grid.draw,ggplot)
7965
S3method(grobHeight,absoluteGrob)
8066
S3method(grobHeight,zeroGrob)
8167
S3method(grobWidth,absoluteGrob)
@@ -98,27 +84,22 @@ S3method(limits,numeric)
9884
S3method(makeContext,dotstackGrob)
9985
S3method(make_constructor,Geom)
10086
S3method(make_constructor,Stat)
101-
S3method(merge_element,default)
102-
S3method(merge_element,element)
103-
S3method(merge_element,element_blank)
104-
S3method(merge_element,margin)
10587
S3method(pattern_alpha,GridPattern)
10688
S3method(pattern_alpha,GridTilingPattern)
10789
S3method(pattern_alpha,default)
10890
S3method(pattern_alpha,list)
109-
S3method(plot,ggplot)
11091
S3method(predictdf,default)
11192
S3method(predictdf,glm)
11293
S3method(predictdf,locfit)
11394
S3method(predictdf,loess)
95+
S3method(print,"ggplot2::ggplot")
96+
S3method(print,"ggplot2::mapping")
97+
S3method(print,"ggplot2::theme")
11498
S3method(print,element)
115-
S3method(print,ggplot)
11699
S3method(print,ggplot2_bins)
117100
S3method(print,ggproto)
118101
S3method(print,ggproto_method)
119102
S3method(print,rel)
120-
S3method(print,theme)
121-
S3method(print,uneval)
122103
S3method(scale_type,Date)
123104
S3method(scale_type,POSIXt)
124105
S3method(scale_type,character)
@@ -132,7 +113,6 @@ S3method(scale_type,logical)
132113
S3method(scale_type,numeric)
133114
S3method(scale_type,ordered)
134115
S3method(scale_type,sfc)
135-
S3method(summary,ggplot)
136116
S3method(vec_cast,character.mapped_discrete)
137117
S3method(vec_cast,double.mapped_discrete)
138118
S3method(vec_cast,factor.mapped_discrete)
@@ -288,6 +268,7 @@ export(StatSummaryBin)
288268
export(StatSummaryHex)
289269
export(StatUnique)
290270
export(StatYdensity)
271+
export(add_gg)
291272
export(aes)
292273
export(aes_)
293274
export(aes_all)
@@ -311,8 +292,14 @@ export(autoplot)
311292
export(benchplot)
312293
export(binned_scale)
313294
export(borders)
295+
export(build_ggplot)
314296
export(calc_element)
315297
export(check_device)
298+
export(class_ggplot)
299+
export(class_ggplot_built)
300+
export(class_labels)
301+
export(class_mapping)
302+
export(class_theme)
316303
export(combine_vars)
317304
export(complete_theme)
318305
export(continuous_scale)
@@ -334,6 +321,7 @@ export(cut_width)
334321
export(datetime_scale)
335322
export(derive)
336323
export(discrete_scale)
324+
export(draw_element)
337325
export(draw_key_abline)
338326
export(draw_key_blank)
339327
export(draw_key_boxplot)
@@ -353,6 +341,7 @@ export(draw_key_vline)
353341
export(draw_key_vpath)
354342
export(dup_axis)
355343
export(el_def)
344+
export(element)
356345
export(element_blank)
357346
export(element_geom)
358347
export(element_grob)
@@ -456,6 +445,7 @@ export(ggproto)
456445
export(ggproto_parent)
457446
export(ggsave)
458447
export(ggtitle)
448+
export(gtable_ggplot)
459449
export(guide_axis)
460450
export(guide_axis_logticks)
461451
export(guide_axis_stack)
@@ -762,6 +752,7 @@ export(transform_position)
762752
export(translate_shape_string)
763753
export(unit)
764754
export(update_geom_defaults)
755+
export(update_ggplot)
765756
export(update_labels)
766757
export(update_stat_defaults)
767758
export(update_theme)
@@ -773,11 +764,13 @@ export(xlim)
773764
export(ylab)
774765
export(ylim)
775766
export(zeroGrob)
767+
if (getRversion() < "4.3.0") importFrom("S7", "@")
776768
import(grid)
777769
import(gtable)
778770
import(rlang)
779771
import(scales)
780772
import(vctrs)
773+
importFrom(S7,convert)
781774
importFrom(grid,arrow)
782775
importFrom(grid,unit)
783776
importFrom(lifecycle,deprecated)

NEWS.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Breaking changes
66

7+
* The S3 parts of ggplot2 have been replaced with S7 bits (#6352).
78
* (breaking) `geom_violin(quantiles)` now has actual quantiles based on
89
the data, rather than inferred quantiles based on the computed density. The
910
`quantiles` parameter that replaces `draw_quantiles` now belongs to
@@ -20,9 +21,10 @@
2021
* Moved mgcv from Imports to Suggests
2122
* Moved tibble from Imports to Suggests
2223
* Removed glue dependency
23-
* Default labels are derived in `ggplot_build()` rather than
24-
in `ggplot_add.Layer()`. This may affect code that accessed the `plot$labels`
25-
field (@teunbrand, #5894).
24+
* Default labels are derived in `build_ggplot()` (previously `ggplot_build()`)
25+
rather than in the layer method of `update_ggplot()`
26+
(previously `ggplot_add.Layer()`). This may affect code that accessed the
27+
`plot$labels` property (@teunbrand, #5894).
2628

2729
### Lifecycle changes
2830

R/aes.R

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ NULL
4646
#' 'AsIs' variables.
4747
#'
4848
#' @family aesthetics documentation
49-
#' @return A list with class `uneval`. Components of the list are either
50-
#' quosures or constants.
49+
#' @return An S7 object representing a list with class `mapping`. Components of
50+
#' the list are either quosures or constants.
5151
#' @export
5252
#' @examples
5353
#' aes(x = mpg, y = wt)
@@ -105,13 +105,12 @@ aes <- function(x, y, ...) {
105105
inject(aes(!!!args))
106106
})
107107

108-
aes <- new_aes(args, env = parent.frame())
109-
rename_aes(aes)
108+
class_mapping(rename_aes(args), env = parent.frame())
110109
}
111110

112111
#' @export
113112
#' @rdname is_tests
114-
is_mapping <- function(x) inherits(x, "uneval")
113+
is_mapping <- function(x) S7::S7_inherits(x, class_mapping)
115114

116115
# Wrap symbolic objects in quosures but pull out constants out of
117116
# quosures for backward-compatibility
@@ -130,14 +129,10 @@ new_aesthetic <- function(x, env = globalenv()) {
130129

131130
x
132131
}
133-
new_aes <- function(x, env = globalenv()) {
134-
check_object(x, is.list, "a {.cls list}")
135-
x <- lapply(x, new_aesthetic, env = env)
136-
structure(x, class = "uneval")
137-
}
138132

139133
#' @export
140-
print.uneval <- function(x, ...) {
134+
# TODO: should convert to proper S7 method once bug in S7 is resolved
135+
`print.ggplot2::mapping` <- function(x, ...) {
141136
cat("Aesthetic mapping: \n")
142137

143138
if (length(x) == 0) {
@@ -152,26 +147,24 @@ print.uneval <- function(x, ...) {
152147
invisible(x)
153148
}
154149

150+
# TODO: should convert to proper S7 method once bug in S7 is resolved
155151
#' @export
156-
"[.uneval" <- function(x, i, ...) {
157-
new_aes(NextMethod())
152+
"[.ggplot2::mapping" <- function(x, i, ...) {
153+
class_mapping(NextMethod())
158154
}
159155

160156
# If necessary coerce replacements to quosures for compatibility
161157
#' @export
162-
"[[<-.uneval" <- function(x, i, value) {
163-
new_aes(NextMethod())
158+
"[[<-.ggplot2::mapping" <- function(x, i, value) {
159+
class_mapping(NextMethod())
164160
}
165161
#' @export
166-
"$<-.uneval" <- function(x, i, value) {
167-
# Can't use NextMethod() because of a bug in R 3.1
168-
x <- unclass(x)
169-
x[[i]] <- value
170-
new_aes(x)
162+
"$<-.ggplot2::mapping" <- function(x, i, value) {
163+
class_mapping(NextMethod())
171164
}
172165
#' @export
173-
"[<-.uneval" <- function(x, i, value) {
174-
new_aes(NextMethod())
166+
"[<-.ggplot2::mapping" <- function(x, i, value) {
167+
class_mapping(NextMethod())
175168
}
176169

177170
#' Standardise aesthetic names
@@ -212,8 +205,7 @@ substitute_aes <- function(x, fun = standardise_aes_symbols, ...) {
212205
x <- lapply(x, function(aesthetic) {
213206
as_quosure(fun(quo_get_expr(aesthetic), ...), env = environment(aesthetic))
214207
})
215-
class(x) <- "uneval"
216-
x
208+
class_mapping(x)
217209
}
218210
# x is a quoted expression from inside aes()
219211
standardise_aes_symbols <- function(x) {
@@ -311,7 +303,7 @@ aes_ <- function(x, y, ...) {
311303
}
312304
}
313305
mapping <- lapply(mapping, as_quosure_aes)
314-
structure(rename_aes(mapping), class = "uneval")
306+
class_mapping(rename_aes(mapping))
315307
}
316308

317309
#' @rdname aes_
@@ -337,7 +329,7 @@ aes_string <- function(x, y, ...) {
337329
new_aesthetic(x, env = caller_env)
338330
})
339331

340-
structure(rename_aes(mapping), class = "uneval")
332+
class_mapping(rename_aes(mapping))
341333
}
342334

343335
#' @export
@@ -358,10 +350,9 @@ aes_all <- function(vars) {
358350

359351
# Quosure the symbols in the empty environment because they can only
360352
# refer to the data mask
361-
structure(
362-
lapply(vars, function(x) new_quosure(as.name(x), emptyenv())),
363-
class = c("unlabelled_uneval", "uneval")
364-
)
353+
x <- class_mapping(lapply(vars, function(x) new_quosure(as.name(x), emptyenv())))
354+
class(x) <- union("unlabelled", class(x))
355+
x
365356
}
366357

367358
#' Automatic aesthetic mapping

0 commit comments

Comments
 (0)