Skip to content

Commit 548e7d0

Browse files
committed
Merge branch 'master' into v3.2.0-rc
2 parents f4c97e8 + b560662 commit 548e7d0

18 files changed

+603
-64
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ quickly as possible. The guide is divided into two main pieces:
66
1. Filing a bug report or feature request in an issue.
77
1. Suggesting a change via a pull request.
88

9-
Please note that ggplot2 is released with a [Contributor Code of Conduct](.github/CODE_OF_CONDUCT.md). By contributing to this project,
9+
Please note that ggplot2 is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to this project,
1010
you agree to abide by its terms.
1111

1212
## Issues

R/aes.r

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ NULL
88
#' [ggplot2()] and in individual layers.
99
#'
1010
#' This function also standardises aesthetic names by converting `color` to `colour`
11-
#' (also in substrings, e.g. `point_color` to `point_colour`) and translating old style
12-
#' R names to ggplot names (eg. `pch` to `shape`, `cex` to `size`).
11+
#' (also in substrings, e.g., `point_color` to `point_colour`) and translating old style
12+
#' R names to ggplot names (e.g., `pch` to `shape` and `cex` to `size`).
1313
#'
1414
#' @section Quasiquotation:
1515
#'
@@ -22,9 +22,13 @@ NULL
2222
#' programming vignette](http://dplyr.tidyverse.org/articles/programming.html)
2323
#' to learn more about these techniques.
2424
#'
25-
#' @param x,y,... List of name value pairs giving aesthetics to map to
26-
#' variables. The names for x and y aesthetics are typically omitted because
27-
#' they are so common; all other aesthetics must be named.
25+
#' @param x,y,... List of name-value pairs in the form `aesthetic = variable`
26+
#' describing which variables in the layer data should be mapped to which
27+
#' aesthetics used by the paired geom/stat. The expression `variable` is
28+
#' evaluated within the layer data, so there is no need to refer to
29+
#' the original dataset (i.e., use `ggplot(df, aes(variable))`
30+
#' instead of `ggplot(df, aes(df$variable))`). The names for x and y aesthetics
31+
#' are typically omitted because they are so common; all other aesthetics must be named.
2832
#' @seealso [vars()] for another quoting function designed for
2933
#' faceting specifications.
3034
#' @return A list with class `uneval`. Components of the list are either
@@ -334,3 +338,55 @@ mapped_aesthetics <- function(x) {
334338
is_null <- vapply(x, is.null, logical(1))
335339
names(x)[!is_null]
336340
}
341+
342+
343+
#' Check a mapping for discouraged usage
344+
#'
345+
#' Checks that `$` and `[[` are not used when the target *is* the data
346+
#'
347+
#' @param mapping A mapping created with [aes()]
348+
#' @param data The data to be mapped from
349+
#'
350+
#' @noRd
351+
warn_for_aes_extract_usage <- function(mapping, data) {
352+
lapply(mapping, function(quosure) {
353+
warn_for_aes_extract_usage_expr(get_expr(quosure), data, get_env(quosure))
354+
})
355+
}
356+
357+
warn_for_aes_extract_usage_expr <- function(x, data, env = emptyenv()) {
358+
if (is_call(x, "[[") || is_call(x, "$")) {
359+
if (extract_target_is_likely_data(x, data, env)) {
360+
good_usage <- alternative_aes_extract_usage(x)
361+
warning(
362+
"Use of `", format(x), "` is discouraged. ",
363+
"Use `", good_usage, "` instead.",
364+
call. = FALSE
365+
)
366+
}
367+
} else if (is.call(x)) {
368+
lapply(x, warn_for_aes_extract_usage_expr, data, env)
369+
}
370+
}
371+
372+
alternative_aes_extract_usage <- function(x) {
373+
if (is_call(x, "[[")) {
374+
good_call <- call2("[[", quote(.data), x[[3]])
375+
format(good_call)
376+
} else if (is_call(x, "$")) {
377+
as.character(x[[3]])
378+
} else {
379+
stop("Don't know how to get alternative usage for `", format(x), "`", call. = FALSE)
380+
}
381+
}
382+
383+
extract_target_is_likely_data <- function(x, data, env) {
384+
if (!is.name(x[[2]])) {
385+
return(FALSE)
386+
}
387+
388+
tryCatch({
389+
data_eval <- eval_tidy(x[[2]], data, env)
390+
identical(data_eval, data)
391+
}, error = function(err) FALSE)
392+
}

R/coord-.r

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ expand_default <- function(scale, discrete = c(0, 0.6, 0, 0.6), continuous = c(0
158158
# generated
159159
render_axis <- function(panel_params, axis, scale, position, theme) {
160160
if (axis == "primary") {
161-
guide_axis(panel_params[[paste0(scale, ".major")]], panel_params[[paste0(scale, ".labels")]], position, theme)
161+
draw_axis(panel_params[[paste0(scale, ".major")]], panel_params[[paste0(scale, ".labels")]], position, theme)
162162
} else if (axis == "secondary" && !is.null(panel_params[[paste0(scale, ".sec.major")]])) {
163-
guide_axis(panel_params[[paste0(scale, ".sec.major")]], panel_params[[paste0(scale, ".sec.labels")]], position, theme)
163+
draw_axis(panel_params[[paste0(scale, ".sec.major")]], panel_params[[paste0(scale, ".sec.labels")]], position, theme)
164164
} else {
165165
zeroGrob()
166166
}

R/coord-map.r

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,8 @@ CoordMap <- ggproto("CoordMap", Coord,
289289
pos <- self$transform(x_intercept, panel_params)
290290

291291
axes <- list(
292-
top = guide_axis(pos$x, panel_params$x.labels, "top", theme),
293-
bottom = guide_axis(pos$x, panel_params$x.labels, "bottom", theme)
292+
top = draw_axis(pos$x, panel_params$x.labels, "top", theme),
293+
bottom = draw_axis(pos$x, panel_params$x.labels, "bottom", theme)
294294
)
295295
axes[[which(arrange == "secondary")]] <- zeroGrob()
296296
axes
@@ -313,8 +313,8 @@ CoordMap <- ggproto("CoordMap", Coord,
313313
pos <- self$transform(x_intercept, panel_params)
314314

315315
axes <- list(
316-
left = guide_axis(pos$y, panel_params$y.labels, "left", theme),
317-
right = guide_axis(pos$y, panel_params$y.labels, "right", theme)
316+
left = draw_axis(pos$y, panel_params$y.labels, "left", theme),
317+
right = draw_axis(pos$y, panel_params$y.labels, "right", theme)
318318
)
319319
axes[[which(arrange == "secondary")]] <- zeroGrob()
320320
axes

R/coord-polar.r

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ CoordPolar <- ggproto("CoordPolar", Coord,
190190
render_axis_h = function(panel_params, theme) {
191191
list(
192192
top = zeroGrob(),
193-
bottom = guide_axis(NA, "", "bottom", theme)
193+
bottom = draw_axis(NA, "", "bottom", theme)
194194
)
195195
},
196196

R/coord-sf.R

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
243243
tick_labels <- c(ticks1$degree_label, ticks2$degree_label)
244244

245245
if (length(tick_positions) > 0) {
246-
top <- guide_axis(
246+
top <- draw_axis(
247247
tick_positions,
248248
tick_labels,
249-
position = "top",
249+
axis_position = "top",
250250
theme = theme
251251
)
252252
} else {
@@ -279,10 +279,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
279279
tick_labels <- c(ticks1$degree_label, ticks2$degree_label)
280280

281281
if (length(tick_positions) > 0) {
282-
bottom <- guide_axis(
282+
bottom <- draw_axis(
283283
tick_positions,
284284
tick_labels,
285-
position = "bottom",
285+
axis_position = "bottom",
286286
theme = theme
287287
)
288288
} else {
@@ -321,10 +321,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
321321
tick_labels <- c(ticks1$degree_label, ticks2$degree_label)
322322

323323
if (length(tick_positions) > 0) {
324-
right <- guide_axis(
324+
right <- draw_axis(
325325
tick_positions,
326326
tick_labels,
327-
position = "right",
327+
axis_position = "right",
328328
theme = theme
329329
)
330330
} else {
@@ -357,10 +357,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
357357
tick_labels <- c(ticks1$degree_label, ticks2$degree_label)
358358

359359
if (length(tick_positions) > 0) {
360-
left <- guide_axis(
360+
left <- draw_axis(
361361
tick_positions,
362362
tick_labels,
363-
position = "left",
363+
axis_position = "left",
364364
theme = theme
365365
)
366366
} else {

R/facet-.r

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ combine_vars <- function(data, env = emptyenv(), vars = NULL, drop = TRUE) {
563563
if (drop) {
564564
new <- unique_combs(new)
565565
}
566-
base <- rbind(base, df.grid(old, new))
566+
base <- unique(rbind(base, df.grid(old, new)))
567567
}
568568

569569
if (empty(base)) {

R/geom-abline.r

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,20 @@ geom_abline <- function(mapping = NULL, data = NULL,
7676
show.legend = NA) {
7777

7878
# If nothing set, default to y = x
79-
if (missing(mapping) && missing(slope) && missing(intercept)) {
79+
if (is.null(mapping) && missing(slope) && missing(intercept)) {
8080
slope <- 1
8181
intercept <- 0
8282
}
8383

8484
# Act like an annotation
8585
if (!missing(slope) || !missing(intercept)) {
8686

87-
# Warn if supplied mapping is going to be overwritten
88-
if (!missing(mapping)) {
89-
warning(paste0("Using `intercept` and/or `slope` with `mapping` may",
90-
" not have the desired result as mapping is overwritten",
91-
" if either of these is specified\n"
92-
)
93-
)
87+
# Warn if supplied mapping and/or data is going to be overwritten
88+
if (!is.null(mapping)) {
89+
warn_overwritten_args("geom_abline()", "mapping", c("slope", "intercept"))
90+
}
91+
if (!is.null(data)) {
92+
warn_overwritten_args("geom_abline()", "data", c("slope", "intercept"))
9493
}
9594

9695
if (missing(slope)) slope <- 1
@@ -141,3 +140,34 @@ GeomAbline <- ggproto("GeomAbline", Geom,
141140

142141
draw_key = draw_key_abline
143142
)
143+
144+
warn_overwritten_args <- function(fun_name, overwritten_arg, provided_args, plural_join = " and/or ") {
145+
overwritten_arg_text <- paste0("`", overwritten_arg, "`")
146+
147+
n_provided_args <- length(provided_args)
148+
if (n_provided_args == 1) {
149+
provided_arg_text <- paste0("`", provided_args, "`")
150+
verb <- "was"
151+
} else if (n_provided_args == 2) {
152+
provided_arg_text <- paste0("`", provided_args, "`", collapse = plural_join)
153+
verb <- "were"
154+
} else {
155+
provided_arg_text <- paste0(
156+
paste0("`", provided_args[-n_provided_args], "`", collapse = ", "),
157+
",", plural_join,
158+
"`", provided_args[n_provided_args], "`"
159+
)
160+
verb <- "were"
161+
}
162+
163+
warning(
164+
sprintf(
165+
"%s: Ignoring %s because %s %s provided.",
166+
fun_name,
167+
overwritten_arg_text,
168+
provided_arg_text,
169+
verb
170+
),
171+
call. = FALSE
172+
)
173+
}

R/geom-hline.r

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ geom_hline <- function(mapping = NULL, data = NULL,
1111

1212
# Act like an annotation
1313
if (!missing(yintercept)) {
14-
# Warn if supplied mapping is going to be overwritten
15-
if (!missing(mapping)) {
16-
warning(paste0("Using both `yintercept` and `mapping` may not have the",
17-
" desired result as mapping is overwritten if",
18-
" `yintercept` is specified\n"
19-
)
20-
)
14+
# Warn if supplied mapping and/or data is going to be overwritten
15+
if (!is.null(mapping)) {
16+
warn_overwritten_args("geom_hline()", "mapping", "yintercept")
2117
}
18+
if (!is.null(data)) {
19+
warn_overwritten_args("geom_hline()", "data", "yintercept")
20+
}
21+
2222
data <- new_data_frame(list(yintercept = yintercept))
2323
mapping <- aes(yintercept = yintercept)
2424
show.legend <- FALSE

R/geom-vline.r

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ geom_vline <- function(mapping = NULL, data = NULL,
1111

1212
# Act like an annotation
1313
if (!missing(xintercept)) {
14-
# Warn if supplied mapping is going to be overwritten
15-
if (!missing(mapping)) {
16-
warning(paste0("Using both `xintercept` and `mapping` may not have the",
17-
" desired result as mapping is overwritten if",
18-
" `xintercept` is specified\n"
19-
)
20-
)
14+
# Warn if supplied mapping and/or data is going to be overwritten
15+
if (!is.null(mapping)) {
16+
warn_overwritten_args("geom_vline()", "mapping", "xintercept")
2117
}
18+
if (!is.null(data)) {
19+
warn_overwritten_args("geom_vline()", "data", "xintercept")
20+
}
21+
2222
data <- new_data_frame(list(xintercept = xintercept))
2323
mapping <- aes(xintercept = xintercept)
2424
show.legend <- FALSE

R/layer.r

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,14 @@ Layer <- ggproto("Layer", NULL,
238238

239239
scales_add_defaults(plot$scales, data, aesthetics, plot$plot_env)
240240

241-
# Evaluate and check aesthetics
241+
# Evaluate aesthetics
242242
evaled <- lapply(aesthetics, eval_tidy, data = data)
243243
evaled <- compact(evaled)
244244

245+
# Check for discouraged usage in mapping
246+
warn_for_aes_extract_usage(aesthetics, data[setdiff(names(data), "PANEL")])
247+
248+
# Check aesthetic values
245249
nondata_cols <- check_nondata_cols(evaled)
246250
if (length(nondata_cols) > 0) {
247251
msg <- paste0(

R/theme.r

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -612,21 +612,38 @@ merge_element.element <- function(new, old) {
612612
new
613613
}
614614

615-
# Combine the properties of two elements
616-
#
617-
# @param e1 An element object
618-
# @param e2 An element object which e1 inherits from
615+
#' Combine the properties of two elements
616+
#'
617+
#' @param e1 An element object
618+
#' @param e2 An element object from which e1 inherits
619+
#'
620+
#' @noRd
621+
#'
619622
combine_elements <- function(e1, e2) {
620623

621624
# If e2 is NULL, nothing to inherit
622-
if (is.null(e2) || inherits(e1, "element_blank")) return(e1)
625+
if (is.null(e2) || inherits(e1, "element_blank")) {
626+
return(e1)
627+
}
628+
623629
# If e1 is NULL inherit everything from e2
624-
if (is.null(e1)) return(e2)
630+
if (is.null(e1)) {
631+
return(e2)
632+
}
633+
634+
# If neither of e1 or e2 are element_* objects, return e1
635+
if (!inherits(e1, "element") && !inherits(e2, "element")) {
636+
return(e1)
637+
}
638+
625639
# If e2 is element_blank, and e1 inherits blank inherit everything from e2,
626640
# otherwise ignore e2
627641
if (inherits(e2, "element_blank")) {
628-
if (e1$inherit.blank) return(e2)
629-
else return(e1)
642+
if (e1$inherit.blank) {
643+
return(e2)
644+
} else {
645+
return(e1)
646+
}
630647
}
631648

632649
# If e1 has any NULL properties, inherit them from e2

man/aes.Rd

Lines changed: 9 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)