From fde313e704a213853e326dde23534e388bc5effe Mon Sep 17 00:00:00 2001 From: Claus Wilke Date: Tue, 10 Jul 2018 23:45:34 -0500 Subject: [PATCH 1/6] more consistent support of US spelling for colour aesthetics. --- R/aes.r | 27 ++++++++++++++++++++++----- R/scale-.r | 4 ++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/R/aes.r b/R/aes.r index 502ed2ae6e..e7ce61fa95 100644 --- a/R/aes.r +++ b/R/aes.r @@ -144,12 +144,29 @@ print.uneval <- function(x, ...) { } # Rename American or old-style aesthetics name -rename_aes <- function(x) { - # Convert prefixes to full names - full <- match(names(x), ggplot_global$all_aesthetics) - names(x)[!is.na(full)] <- ggplot_global$all_aesthetics[full[!is.na(full)]] +# x is a vector of aes names, such as c("colour", "size", "shape") +standardize_aes_names <- function(x) { + # convert US to UK spelling of colour + x <- sub("color", "colour", x, fixed = TRUE) + + # convert old-style aesthetics names to ggplot version + plyr::revalue(x, ggplot2:::ggplot_global$base_to_ggplot, warn_missing = FALSE) +} - plyr::rename(x, ggplot_global$base_to_ggplot, warn_missing = FALSE) +# x is a list of aesthetic mappings, as generated by aes() +rename_aes <- function(x) { + names(x) <- standardize_aes_names(names(x)) + duplicated_names <- names(x)[duplicated(names(x))] + if (length(duplicated_names) > 0L) { + duplicated_names_message <- paste0( + "`", duplicated_names, "`", collapse = ", " + ) + warning( + "Standardization of aesthetics has created duplicates for the ", + "following: ", duplicated_names_message, call. = FALSE + ) + } + x } # Look up the scale that should be used for a given aesthetic diff --git a/R/scale-.r b/R/scale-.r index 8c390a0918..fead26dfef 100644 --- a/R/scale-.r +++ b/R/scale-.r @@ -556,6 +556,8 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = waiver(), rescaler = rescale, oob = censor, expand = waiver(), na.value = NA_real_, trans = "identity", guide = "legend", position = "left", super = ScaleContinuous) { + aesthetics <- standardize_aes_names(aesthetics) + check_breaks_labels(breaks, labels) position <- match.arg(position, c("left", "right", "top", "bottom")) @@ -622,6 +624,8 @@ discrete_scale <- function(aesthetics, scale_name, palette, name = waiver(), na.translate = TRUE, na.value = NA, drop = TRUE, guide = "legend", position = "left", super = ScaleDiscrete) { + aesthetics <- standardize_aes_names(aesthetics) + check_breaks_labels(breaks, labels) position <- match.arg(position, c("left", "right", "top", "bottom")) From b89eb833d3f712bb7a34ea880b10abb3793524b9 Mon Sep 17 00:00:00 2001 From: Claus Wilke Date: Wed, 11 Jul 2018 01:08:33 -0500 Subject: [PATCH 2/6] update docs, add regression tests --- NAMESPACE | 1 + R/aes.r | 23 +++++++++++------ R/scale-.r | 4 +-- man/aes.Rd | 6 ++--- man/ggtheme.Rd | 49 ++++++++++++++++++++++++++++-------- man/scale_viridis.Rd | 2 +- man/standardise_aes_names.Rd | 20 +++++++++++++++ tests/testthat/test-aes.r | 13 ++++++++++ 8 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 man/standardise_aes_names.Rd diff --git a/NAMESPACE b/NAMESPACE index f09568dd1c..e14b3233d1 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -506,6 +506,7 @@ export(scale_y_time) export(sec_axis) export(set_last_plot) export(should_stop) +export(standardise_aes_names) export(stat) export(stat_bin) export(stat_bin2d) diff --git a/R/aes.r b/R/aes.r index e7ce61fa95..0d3b04fe71 100644 --- a/R/aes.r +++ b/R/aes.r @@ -7,9 +7,9 @@ NULL #' properties (aesthetics) of geoms. Aesthetic mappings can be set in #' [ggplot2()] and in individual layers. #' -#' This function also standardises aesthetic names by performing partial -#' matching, converting color to colour, and translating old style R names to -#' ggplot names (e.g. pch to shape, cex to size). +#' This function also standardises aesthetic names by converting `color` to `colour` +#' (also in substrings, e.g. `point_color` to `point_colour`) and translating old style +#' R names to ggplot names (eg. `pch` to `shape`, `cex` to `size`). #' #' @section Quasiquotation: #' @@ -143,9 +143,16 @@ print.uneval <- function(x, ...) { new_aes(NextMethod()) } -# Rename American or old-style aesthetics name -# x is a vector of aes names, such as c("colour", "size", "shape") -standardize_aes_names <- function(x) { +#' Standardise aesthetic names +#' +#' This function standardises aesthetic names by converting `color` to `colour` +#' (also in substrings, e.g. `point_color` to `point_colour`) and translating old style +#' R names to ggplot names (eg. `pch` to `shape`, `cex` to `size`). +#' @param x Character vector of aesthetics names, such as `c("colour", "size", "shape")`. +#' @return Character vector of standardised names. +#' @keywords internal +#' @export +standardise_aes_names <- function(x) { # convert US to UK spelling of colour x <- sub("color", "colour", x, fixed = TRUE) @@ -155,14 +162,14 @@ standardize_aes_names <- function(x) { # x is a list of aesthetic mappings, as generated by aes() rename_aes <- function(x) { - names(x) <- standardize_aes_names(names(x)) + names(x) <- standardise_aes_names(names(x)) duplicated_names <- names(x)[duplicated(names(x))] if (length(duplicated_names) > 0L) { duplicated_names_message <- paste0( "`", duplicated_names, "`", collapse = ", " ) warning( - "Standardization of aesthetics has created duplicates for the ", + "Standardisation of aesthetics has created duplicates for the ", "following: ", duplicated_names_message, call. = FALSE ) } diff --git a/R/scale-.r b/R/scale-.r index fead26dfef..2662daf320 100644 --- a/R/scale-.r +++ b/R/scale-.r @@ -556,7 +556,7 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = waiver(), rescaler = rescale, oob = censor, expand = waiver(), na.value = NA_real_, trans = "identity", guide = "legend", position = "left", super = ScaleContinuous) { - aesthetics <- standardize_aes_names(aesthetics) + aesthetics <- standardise_aes_names(aesthetics) check_breaks_labels(breaks, labels) @@ -624,7 +624,7 @@ discrete_scale <- function(aesthetics, scale_name, palette, name = waiver(), na.translate = TRUE, na.value = NA, drop = TRUE, guide = "legend", position = "left", super = ScaleDiscrete) { - aesthetics <- standardize_aes_names(aesthetics) + aesthetics <- standardise_aes_names(aesthetics) check_breaks_labels(breaks, labels) diff --git a/man/aes.Rd b/man/aes.Rd index e4c6b7b446..0f207c4fef 100644 --- a/man/aes.Rd +++ b/man/aes.Rd @@ -21,9 +21,9 @@ properties (aesthetics) of geoms. Aesthetic mappings can be set in \code{\link[=ggplot2]{ggplot2()}} and in individual layers. } \details{ -This function also standardises aesthetic names by performing partial -matching, converting color to colour, and translating old style R names to -ggplot names (e.g. pch to shape, cex to size). +This function also standardises aesthetic names by converting \code{color} to \code{colour} +(also in substrings, e.g. \code{point_color} to \code{point_colour}) and translating old style +R names to ggplot names (eg. \code{pch} to \code{shape}, \code{cex} to \code{size}). } \section{Quasiquotation}{ diff --git a/man/ggtheme.Rd b/man/ggtheme.Rd index a54289cec5..2a1c1bee64 100644 --- a/man/ggtheme.Rd +++ b/man/ggtheme.Rd @@ -97,14 +97,43 @@ for new features.} } } \examples{ -p <- ggplot(mtcars) + geom_point(aes(x = wt, y = mpg, - colour = factor(gear))) + facet_wrap(~am) -p + theme_gray() # the default -p + theme_bw() -p + theme_linedraw() -p + theme_light() -p + theme_dark() -p + theme_minimal() -p + theme_classic() -p + theme_void() +mtcars2 <- within(mtcars, { + vs <- factor(vs, labels = c("V-shaped", "Straight")) + am <- factor(am, labels = c("Automatic", "Manual")) + cyl <- factor(cyl) + gear <- factor(gear) +}) + +p1 <- ggplot(mtcars2) + + geom_point(aes(x = wt, y = mpg, colour = gear)) + + labs(title = "Fuel economy declines as weight increases", + subtitle = "(1973-74)", + caption = "Data from the 1974 Motor Trend US magazine.", + tag = "Figure 1", + x = "Weight (1000 lbs)", + y = "Fuel economy (mpg)", + colour = "Gears") + +p1 + theme_gray() # the default +p1 + theme_bw() +p1 + theme_linedraw() +p1 + theme_light() +p1 + theme_dark() +p1 + theme_minimal() +p1 + theme_classic() +p1 + theme_void() + +# Theme examples with panels +\donttest{ +p2 <- p1 + facet_grid(vs ~ am) + +p2 + theme_gray() # the default +p2 + theme_bw() +p2 + theme_linedraw() +p2 + theme_light() +p2 + theme_dark() +p2 + theme_minimal() +p2 + theme_classic() +p2 + theme_void() +} } diff --git a/man/scale_viridis.Rd b/man/scale_viridis.Rd index 3a375deeb1..0066028de0 100644 --- a/man/scale_viridis.Rd +++ b/man/scale_viridis.Rd @@ -50,7 +50,7 @@ same time, via \code{aesthetics = c("colour", "fill")}.} \item{values}{if colours should not be evenly positioned along the gradient this vector gives the position (between 0 and 1) for each colour in the -\code{colours} vector. See \code{\link{rescale}} for a convience function +\code{colours} vector. See \code{\link[=rescale]{rescale()}} for a convience function to map an arbitrary range to between 0 and 1.} \item{space}{colour space in which to calculate gradient. Must be "Lab" - diff --git a/man/standardise_aes_names.Rd b/man/standardise_aes_names.Rd new file mode 100644 index 0000000000..1c9302a56d --- /dev/null +++ b/man/standardise_aes_names.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/aes.r +\name{standardise_aes_names} +\alias{standardise_aes_names} +\title{Standardise aesthetic names} +\usage{ +standardise_aes_names(x) +} +\arguments{ +\item{x}{Character vector of aesthetics names, such as \code{c("colour", "size", "shape")}.} +} +\value{ +Character vector of standardised names. +} +\description{ +This function standardises aesthetic names by converting \code{color} to \code{colour} +(also in substrings, e.g. \code{point_color} to \code{point_colour}) and translating old style +R names to ggplot names (eg. \code{pch} to \code{shape}, \code{cex} to \code{size}). +} +\keyword{internal} diff --git a/tests/testthat/test-aes.r b/tests/testthat/test-aes.r index d167b6628f..e2bd38abf4 100644 --- a/tests/testthat/test-aes.r +++ b/tests/testthat/test-aes.r @@ -98,6 +98,19 @@ test_that("labelling doesn't cause error if aesthetic is NULL", { expect_null(p$labels$x) }) +test_that("aes standardises aesthetic names", { + # test a few common cases + expect_identical(aes(color = x), aes(colour = x)) + expect_identical(aes(pch = x), aes(shape = x)) + + # US to British spelling in substrings + expect_identical(aes(point_color = x), aes(point_colour = x)) + expect_identical(aes(color_point = x), aes(colour_point = x)) + + # warning when standardisation creates duplicates + expect_warning(aes(color = x, colour = y), "has created duplicates") +}) + # Visual tests ------------------------------------------------------------ From 948f10016a3641074adf333f02e1eb7ed9a125db Mon Sep 17 00:00:00 2001 From: Claus Wilke Date: Wed, 11 Jul 2018 12:12:42 +0100 Subject: [PATCH 3/6] Add news item. Closes #2649 --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 19cdf00f9b..90881da3e3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,10 @@ feed data columns into `aes()` or into parameters of geoms or stats. However, doing so remains discouraged (@clauswilke). +* Aesthetic names are now consistently standardised both in `aes()` and in the + `aesthetics` argument of scale functions. Also, the US spelling "color" + is now always internally converted to "colour", even when part of a longer + aesthetic name (e.g., `point_color`) (@clauswilke, #2649). # ggplot2 3.0.0 From 1e5d36fb436f72326b30e3fc1a2381942138d512 Mon Sep 17 00:00:00 2001 From: Claus Wilke Date: Wed, 11 Jul 2018 12:32:29 +0100 Subject: [PATCH 4/6] remove spurious namespace prefix --- R/aes.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/aes.r b/R/aes.r index 0d3b04fe71..3a13a925aa 100644 --- a/R/aes.r +++ b/R/aes.r @@ -157,7 +157,7 @@ standardise_aes_names <- function(x) { x <- sub("color", "colour", x, fixed = TRUE) # convert old-style aesthetics names to ggplot version - plyr::revalue(x, ggplot2:::ggplot_global$base_to_ggplot, warn_missing = FALSE) + plyr::revalue(x, ggplot_global$base_to_ggplot, warn_missing = FALSE) } # x is a list of aesthetic mappings, as generated by aes() From 941d5863a2f98e08b0b21736cb1f7ac2894856f7 Mon Sep 17 00:00:00 2001 From: Claus Wilke Date: Thu, 12 Jul 2018 15:03:24 +0200 Subject: [PATCH 5/6] improved error message for duplicated aesthetics --- R/aes.r | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/R/aes.r b/R/aes.r index 3a13a925aa..5b1c1114c7 100644 --- a/R/aes.r +++ b/R/aes.r @@ -165,12 +165,9 @@ rename_aes <- function(x) { names(x) <- standardise_aes_names(names(x)) duplicated_names <- names(x)[duplicated(names(x))] if (length(duplicated_names) > 0L) { - duplicated_names_message <- paste0( - "`", duplicated_names, "`", collapse = ", " - ) + duplicated_message <- paste0(unique(duplicated_names), collapse = ", ") warning( - "Standardisation of aesthetics has created duplicates for the ", - "following: ", duplicated_names_message, call. = FALSE + "Duplicated aesthetics after name standardisation: ", duplicated_message, call. = FALSE ) } x From 057110c1802dafc444639b3efb2307be51b36f26 Mon Sep 17 00:00:00 2001 From: Claus Wilke Date: Thu, 12 Jul 2018 15:51:37 +0200 Subject: [PATCH 6/6] fix unit test --- tests/testthat/test-aes.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-aes.r b/tests/testthat/test-aes.r index e2bd38abf4..fd36cbc1f0 100644 --- a/tests/testthat/test-aes.r +++ b/tests/testthat/test-aes.r @@ -108,7 +108,7 @@ test_that("aes standardises aesthetic names", { expect_identical(aes(color_point = x), aes(colour_point = x)) # warning when standardisation creates duplicates - expect_warning(aes(color = x, colour = y), "has created duplicates") + expect_warning(aes(color = x, colour = y), "Duplicated aesthetics") })