From ece924d5bd6982515be7ba71df3da84600bc5218 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 16 Dec 2019 11:07:52 +0100 Subject: [PATCH 01/11] First stab at renaming size->linewidth for line-based geoms --- R/geom-abline.r | 7 ++-- R/geom-bar.r | 1 + R/geom-boxplot.r | 7 ++-- R/geom-col.r | 1 + R/geom-contour.r | 2 +- R/geom-crossbar.r | 8 ++--- R/geom-curve.r | 4 +-- R/geom-density2d.r | 2 +- R/geom-errorbar.r | 5 +-- R/geom-errorbarh.r | 5 +-- R/geom-hex.r | 9 +++-- R/geom-hline.r | 5 ++- R/geom-linerange.r | 3 +- R/geom-map.r | 2 +- R/geom-path.r | 13 ++++--- R/geom-pointrange.r | 4 +-- R/geom-polygon.r | 10 ++++-- R/geom-quantile.r | 2 +- R/geom-rect.r | 8 +++-- R/geom-ribbon.r | 9 ++--- R/geom-rug.r | 6 +++- R/geom-segment.r | 12 ++++--- R/geom-sf.R | 4 ++- R/geom-smooth.r | 2 +- R/geom-spoke.r | 1 + R/geom-tile.r | 3 +- R/geom-violin.r | 3 +- R/geom-vline.r | 5 ++- R/legend-draw.r | 24 ++++++------- R/scale-linewidth.R | 84 +++++++++++++++++++++++++++++++++++++++++++++ 30 files changed, 189 insertions(+), 62 deletions(-) create mode 100644 R/scale-linewidth.R diff --git a/R/geom-abline.r b/R/geom-abline.r index a0ef5058b5..6c539fc95f 100644 --- a/R/geom-abline.r +++ b/R/geom-abline.r @@ -22,7 +22,7 @@ NULL #' @section Aesthetics: #' These geoms are drawn using with [geom_line()] so support the #' same aesthetics: `alpha`, `colour`, `linetype` and -#' `size`. They also each have aesthetics that control the position of +#' `linewidth`. They also each have aesthetics that control the position of #' the line: #' #' - `geom_vline()`: `xintercept` @@ -124,6 +124,9 @@ geom_abline <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomAbline <- ggproto("GeomAbline", Geom, + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, draw_panel = function(data, panel_params, coord) { ranges <- coord$backtransform_range(panel_params) @@ -135,7 +138,7 @@ GeomAbline <- ggproto("GeomAbline", Geom, GeomSegment$draw_panel(unique(data), panel_params, coord) }, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA), + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = c("slope", "intercept"), draw_key = draw_key_abline diff --git a/R/geom-bar.r b/R/geom-bar.r index cff012f926..b584a0b235 100644 --- a/R/geom-bar.r +++ b/R/geom-bar.r @@ -134,6 +134,7 @@ GeomBar <- ggproto("GeomBar", GeomRect, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% diff --git a/R/geom-boxplot.r b/R/geom-boxplot.r index 8273a854f8..e6b7e38173 100644 --- a/R/geom-boxplot.r +++ b/R/geom-boxplot.r @@ -174,6 +174,7 @@ GeomBoxplot <- ggproto("GeomBoxplot", Geom, }, setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% @@ -222,7 +223,7 @@ GeomBoxplot <- ggproto("GeomBoxplot", Geom, common <- list( colour = data$colour, - size = data$size, + linewidth = data$linewidth, linetype = data$linetype, fill = alpha(data$fill, data$alpha), group = data$group @@ -284,8 +285,8 @@ GeomBoxplot <- ggproto("GeomBoxplot", Geom, draw_key = draw_key_boxplot, - default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = 0.5, - alpha = NA, shape = 19, linetype = "solid"), + default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = NULL, + alpha = NA, shape = 19, linetype = "solid", linewidth = 0.5), required_aes = c("x|y", "lower|xlower", "upper|xupper", "middle|xmiddle", "ymin|xmin", "ymax|xmax") ) diff --git a/R/geom-col.r b/R/geom-col.r index be91cfc480..68eb613650 100644 --- a/R/geom-col.r +++ b/R/geom-col.r @@ -45,6 +45,7 @@ GeomCol <- ggproto("GeomCol", GeomRect, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% diff --git a/R/geom-contour.r b/R/geom-contour.r index eb9e477c44..0503e87c31 100644 --- a/R/geom-contour.r +++ b/R/geom-contour.r @@ -118,7 +118,7 @@ GeomContour <- ggproto("GeomContour", GeomPath, default_aes = aes( weight = 1, colour = "#3366FF", - size = 0.5, + linewidth = 0.5, linetype = 1, alpha = NA ) diff --git a/R/geom-crossbar.r b/R/geom-crossbar.r index 05fa058460..e216a6e755 100644 --- a/R/geom-crossbar.r +++ b/R/geom-crossbar.r @@ -40,7 +40,7 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, GeomErrorbar$setup_data(data, params) }, - default_aes = aes(colour = "black", fill = NA, size = 0.5, linetype = 1, + default_aes = aes(colour = "black", fill = NA, linewidth = 0.5, linetype = 1, alpha = NA), required_aes = c("x", "y", "ymin|xmin", "ymax|xmax"), @@ -50,7 +50,7 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, draw_panel = function(data, panel_params, coord, fatten = 2.5, width = NULL, flipped_aes = FALSE) { data <- flip_data(data, flipped_aes) - middle <- transform(data, x = xmin, xend = xmax, yend = y, size = size * fatten, alpha = NA) + middle <- transform(data, x = xmin, xend = xmax, yend = y, linewidth = linewidth * fatten, alpha = NA) has_notch <- !is.null(data$ynotchlower) && !is.null(data$ynotchupper) && !is.na(data$ynotchlower) && !is.na(data$ynotchupper) @@ -77,7 +77,7 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, ), alpha = rep(data$alpha, 11), colour = rep(data$colour, 11), - size = rep(data$size, 11), + linewidth = rep(data$linewidth, 11), linetype = rep(data$linetype, 11), fill = rep(data$fill, 11), group = rep(seq_len(nrow(data)), 11) @@ -89,7 +89,7 @@ GeomCrossbar <- ggproto("GeomCrossbar", Geom, y = c(data$ymax, data$ymin, data$ymin, data$ymax, data$ymax), alpha = rep(data$alpha, 5), colour = rep(data$colour, 5), - size = rep(data$size, 5), + linewidth = rep(data$linewidth, 5), linetype = rep(data$linetype, 5), fill = rep(data$fill, 5), group = rep(seq_len(nrow(data)), 5) # each bar forms it's own group diff --git a/R/geom-curve.r b/R/geom-curve.r index e9faa3730b..d21b73b793 100644 --- a/R/geom-curve.r +++ b/R/geom-curve.r @@ -40,7 +40,7 @@ geom_curve <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomCurve <- ggproto("GeomCurve", GeomSegment, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA), + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), draw_panel = function(data, panel_params, coord, curvature = 0.5, angle = 90, ncp = 5, arrow = NULL, arrow.fill = NULL, lineend = "butt", na.rm = FALSE) { @@ -61,7 +61,7 @@ GeomCurve <- ggproto("GeomCurve", GeomSegment, gp = gpar( col = alpha(trans$colour, trans$alpha), fill = alpha(arrow.fill, trans$alpha), - lwd = trans$size * .pt, + lwd = trans$linewidth * .pt, lty = trans$linetype, lineend = lineend), arrow = arrow diff --git a/R/geom-density2d.r b/R/geom-density2d.r index b96275604d..5a5f1c0e25 100644 --- a/R/geom-density2d.r +++ b/R/geom-density2d.r @@ -82,5 +82,5 @@ geom_density2d <- geom_density_2d #' @usage NULL #' @export GeomDensity2d <- ggproto("GeomDensity2d", GeomPath, - default_aes = aes(colour = "#3366FF", size = 0.5, linetype = 1, alpha = NA) + default_aes = aes(colour = "#3366FF", linewidth = 0.5, linetype = 1, alpha = NA) ) diff --git a/R/geom-errorbar.r b/R/geom-errorbar.r index 4840d75d10..07683155ec 100644 --- a/R/geom-errorbar.r +++ b/R/geom-errorbar.r @@ -28,7 +28,7 @@ geom_errorbar <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomErrorbar <- ggproto("GeomErrorbar", Geom, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, width = 0.5, + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, width = 0.5, alpha = NA), draw_key = draw_key_path, @@ -42,6 +42,7 @@ GeomErrorbar <- ggproto("GeomErrorbar", Geom, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% @@ -61,7 +62,7 @@ GeomErrorbar <- ggproto("GeomErrorbar", Geom, y = y, colour = rep(data$colour, each = 8), alpha = rep(data$alpha, each = 8), - size = rep(data$size, each = 8), + linewidth = rep(data$linewidth, each = 8), linetype = rep(data$linetype, each = 8), group = rep(1:(nrow(data)), each = 8), row.names = 1:(nrow(data) * 8) diff --git a/R/geom-errorbarh.r b/R/geom-errorbarh.r index e23898d12e..e6ecad3d01 100644 --- a/R/geom-errorbarh.r +++ b/R/geom-errorbarh.r @@ -48,7 +48,7 @@ geom_errorbarh <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomErrorbarh <- ggproto("GeomErrorbarh", Geom, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, height = 0.5, + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, height = 0.5, alpha = NA), draw_key = draw_key_path, @@ -56,6 +56,7 @@ GeomErrorbarh <- ggproto("GeomErrorbarh", Geom, required_aes = c("xmin", "xmax", "y"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$height <- data$height %||% params$height %||% (resolution(data$y, FALSE) * 0.9) @@ -70,7 +71,7 @@ GeomErrorbarh <- ggproto("GeomErrorbarh", Geom, y = as.vector(rbind(data$ymin, data$ymax, NA, data$y, data$y, NA, data$ymin, data$ymax)), colour = rep(data$colour, each = 8), alpha = rep(data$alpha, each = 8), - size = rep(data$size, each = 8), + linewidth = rep(data$linewidth, each = 8), linetype = rep(data$linetype, each = 8), group = rep(1:(nrow(data)), each = 8), row.names = 1:(nrow(data) * 8) diff --git a/R/geom-hex.r b/R/geom-hex.r index e669914264..c81387d135 100644 --- a/R/geom-hex.r +++ b/R/geom-hex.r @@ -54,7 +54,10 @@ geom_hex <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomHex <- ggproto("GeomHex", Geom, - draw_group = function(data, panel_params, coord) { + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, + draw_group = function(data, panel_params, coord) { if (!inherits(coord, "CoordCartesian")) { stop("geom_hex() only works with Cartesian coordinates", call. = FALSE) } @@ -65,7 +68,7 @@ GeomHex <- ggproto("GeomHex", Geom, gp = gpar( col = coords$colour, fill = alpha(coords$fill, coords$alpha), - lwd = coords$size * .pt, + lwd = coords$linewidth * .pt, lty = coords$linetype ) )) @@ -76,7 +79,7 @@ GeomHex <- ggproto("GeomHex", Geom, default_aes = aes( colour = NA, fill = "grey50", - size = 0.5, + linewidth = 0.5, linetype = 1, alpha = NA ), diff --git a/R/geom-hline.r b/R/geom-hline.r index d242f74b08..c971b2f098 100644 --- a/R/geom-hline.r +++ b/R/geom-hline.r @@ -54,8 +54,11 @@ GeomHline <- ggproto("GeomHline", Geom, GeomSegment$draw_panel(unique(data), panel_params, coord) }, + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA), + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = "yintercept", draw_key = draw_key_path diff --git a/R/geom-linerange.r b/R/geom-linerange.r index f6307062af..b174d739a7 100644 --- a/R/geom-linerange.r +++ b/R/geom-linerange.r @@ -91,7 +91,7 @@ geom_linerange <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomLinerange <- ggproto("GeomLinerange", Geom, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA), + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), draw_key = draw_key_vpath, @@ -109,6 +109,7 @@ GeomLinerange <- ggproto("GeomLinerange", Geom, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data }, diff --git a/R/geom-map.r b/R/geom-map.r index cc77923621..dc646a04c9 100644 --- a/R/geom-map.r +++ b/R/geom-map.r @@ -113,7 +113,7 @@ GeomMap <- ggproto("GeomMap", GeomPolygon, polygonGrob(coords$x, coords$y, default.units = "native", id = grob_id, gp = gpar( col = data$colour, fill = alpha(data$fill, data$alpha), - lwd = data$size * .pt + lwd = data$linewidth * .pt ) ) }, diff --git a/R/geom-path.r b/R/geom-path.r index 0f02f2f045..a4723e8d5d 100644 --- a/R/geom-path.r +++ b/R/geom-path.r @@ -130,7 +130,7 @@ geom_path <- function(mapping = NULL, data = NULL, GeomPath <- ggproto("GeomPath", Geom, required_aes = c("x", "y"), - default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA), + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), handle_na = function(data, params) { # Drop missing values at the start or end of a line - can't drop in the @@ -169,7 +169,7 @@ GeomPath <- ggproto("GeomPath", Geom, linetype <- unique(df$linetype) new_data_frame(list( solid = identical(linetype, 1) || identical(linetype, "solid"), - constant = nrow(unique(df[, c("alpha", "colour","size", "linetype")])) == 1 + constant = nrow(unique(df[, c("alpha", "colour","linewidth", "linetype")])) == 1 ), n = 1) }) solid_lines <- all(attr$solid) @@ -193,7 +193,7 @@ GeomPath <- ggproto("GeomPath", Geom, gp = gpar( col = alpha(munched$colour, munched$alpha)[!end], fill = alpha(munched$colour, munched$alpha)[!end], - lwd = munched$size[!end] * .pt, + lwd = munched$linewidth[!end] * .pt, lty = munched$linetype[!end], lineend = lineend, linejoin = linejoin, @@ -208,7 +208,7 @@ GeomPath <- ggproto("GeomPath", Geom, gp = gpar( col = alpha(munched$colour, munched$alpha)[start], fill = alpha(munched$colour, munched$alpha)[start], - lwd = munched$size[start] * .pt, + lwd = munched$linewidth[start] * .pt, lty = munched$linetype[start], lineend = lineend, linejoin = linejoin, @@ -218,6 +218,10 @@ GeomPath <- ggproto("GeomPath", Geom, } }, + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, + draw_key = draw_key_path ) @@ -273,6 +277,7 @@ GeomLine <- ggproto("GeomLine", GeomPath, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data <- data[order(data$PANEL, data$group, data$x), ] diff --git a/R/geom-pointrange.r b/R/geom-pointrange.r index 5b018c1253..7b2d71cd0c 100644 --- a/R/geom-pointrange.r +++ b/R/geom-pointrange.r @@ -30,8 +30,8 @@ geom_pointrange <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomPointrange <- ggproto("GeomPointrange", Geom, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, shape = 19, - fill = NA, alpha = NA, stroke = 1), + default_aes = aes(colour = "black", size = 0.5, linewidth = 0.5, linetype = 1, + shape = 19, fill = NA, alpha = NA, stroke = 1), draw_key = draw_key_pointrange, diff --git a/R/geom-polygon.r b/R/geom-polygon.r index f8ed81bae9..17c26ff605 100644 --- a/R/geom-polygon.r +++ b/R/geom-polygon.r @@ -130,7 +130,7 @@ GeomPolygon <- ggproto("GeomPolygon", Geom, gp = gpar( col = first_rows$colour, fill = alpha(first_rows$fill, first_rows$alpha), - lwd = first_rows$size * .pt, + lwd = first_rows$linewidth * .pt, lty = first_rows$linetype ) ) @@ -158,7 +158,7 @@ GeomPolygon <- ggproto("GeomPolygon", Geom, gp = gpar( col = first_rows$colour, fill = alpha(first_rows$fill, first_rows$alpha), - lwd = first_rows$size * .pt, + lwd = first_rows$linewidth * .pt, lty = first_rows$linetype ) ) @@ -167,7 +167,11 @@ GeomPolygon <- ggproto("GeomPolygon", Geom, }, - default_aes = aes(colour = "NA", fill = "grey20", size = 0.5, linetype = 1, + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, + + default_aes = aes(colour = "NA", fill = "grey20", linewidth = 0.5, linetype = 1, alpha = NA, subgroup = NULL), handle_na = function(data, params) { diff --git a/R/geom-quantile.r b/R/geom-quantile.r index 85729b42d0..21c7c85aa8 100644 --- a/R/geom-quantile.r +++ b/R/geom-quantile.r @@ -62,7 +62,7 @@ geom_quantile <- function(mapping = NULL, data = NULL, #' @include geom-path.r GeomQuantile <- ggproto("GeomQuantile", GeomPath, default_aes = defaults( - aes(weight = 1, colour = "#3366FF", size = 0.5), + aes(weight = 1, colour = "#3366FF", linewidth = 0.5), GeomPath$default_aes ) ) diff --git a/R/geom-rect.r b/R/geom-rect.r index 95cf0383e6..97528b875a 100644 --- a/R/geom-rect.r +++ b/R/geom-rect.r @@ -28,7 +28,7 @@ geom_rect <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomRect <- ggproto("GeomRect", Geom, - default_aes = aes(colour = NA, fill = "grey35", size = 0.5, linetype = 1, + default_aes = aes(colour = NA, fill = "grey35", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = c("xmin", "xmax", "ymin", "ymax"), @@ -58,7 +58,7 @@ GeomRect <- ggproto("GeomRect", Geom, gp = gpar( col = coords$colour, fill = alpha(coords$fill, coords$alpha), - lwd = coords$size * .pt, + lwd = coords$linewidth * .pt, lty = coords$linetype, linejoin = linejoin, # `lineend` is a workaround for Windows and intentionally kept unexposed @@ -69,6 +69,10 @@ GeomRect <- ggproto("GeomRect", Geom, } }, + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, + draw_key = draw_key_polygon ) diff --git a/R/geom-ribbon.r b/R/geom-ribbon.r index cff9e1dbb1..1a979fcebf 100644 --- a/R/geom-ribbon.r +++ b/R/geom-ribbon.r @@ -66,7 +66,7 @@ geom_ribbon <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomRibbon <- ggproto("GeomRibbon", Geom, - default_aes = aes(colour = NA, fill = "grey20", size = 0.5, linetype = 1, + default_aes = aes(colour = NA, fill = "grey20", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = c("x|y", "ymin|xmin", "ymax|xmax"), @@ -79,6 +79,7 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) @@ -103,7 +104,7 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, data <- data[order(data$group), ] # Check that aesthetics are constant - aes <- unique(data[c("colour", "fill", "size", "linetype", "alpha")]) + aes <- unique(data[c("colour", "fill", "linewidth", "linetype", "alpha")]) if (nrow(aes) > 1) { stop("Aesthetics can not vary with a ribbon") } @@ -137,7 +138,7 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, gp = gpar( fill = alpha(aes$fill, aes$alpha), col = aes$colour, - lwd = aes$size * .pt, + lwd = aes$linewidth * .pt, lty = aes$linetype) )) } @@ -169,7 +170,7 @@ geom_area <- function(mapping = NULL, data = NULL, stat = "identity", #' @usage NULL #' @export GeomArea <- ggproto("GeomArea", GeomRibbon, - default_aes = aes(colour = NA, fill = "grey20", size = 0.5, linetype = 1, + default_aes = aes(colour = NA, fill = "grey20", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = c("x", "y"), diff --git a/R/geom-rug.r b/R/geom-rug.r index cbf7cbfe65..adf9a87832 100644 --- a/R/geom-rug.r +++ b/R/geom-rug.r @@ -145,7 +145,11 @@ GeomRug <- ggproto("GeomRug", Geom, gTree(children = do.call("gList", rugs)) }, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA), + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, + + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), draw_key = draw_key_path ) diff --git a/R/geom-segment.r b/R/geom-segment.r index 2fd48da8a0..80559b6f2f 100644 --- a/R/geom-segment.r +++ b/R/geom-segment.r @@ -100,14 +100,16 @@ geom_segment <- function(mapping = NULL, data = NULL, #' @export GeomSegment <- ggproto("GeomSegment", Geom, required_aes = c("x", "y", "xend", "yend"), - non_missing_aes = c("linetype", "size", "shape"), - default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA), - + non_missing_aes = c("linetype", "linewidth", "shape"), + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, draw_panel = function(data, panel_params, coord, arrow = NULL, arrow.fill = NULL, lineend = "butt", linejoin = "round", na.rm = FALSE) { data <- remove_missing(data, na.rm = na.rm, - c("x", "y", "xend", "yend", "linetype", "size", "shape"), + c("x", "y", "xend", "yend", "linetype", "linewidth", "shape"), name = "geom_segment") if (empty(data)) return(zeroGrob()) @@ -119,7 +121,7 @@ GeomSegment <- ggproto("GeomSegment", Geom, gp = gpar( col = alpha(coord$colour, coord$alpha), fill = alpha(arrow.fill, coord$alpha), - lwd = coord$size * .pt, + lwd = coord$linewidth * .pt, lty = coord$linetype, lineend = lineend, linejoin = linejoin diff --git a/R/geom-sf.R b/R/geom-sf.R index 546b31a15c..e5a160c8b1 100644 --- a/R/geom-sf.R +++ b/R/geom-sf.R @@ -92,6 +92,7 @@ GeomSf <- ggproto("GeomSf", Geom, colour = NULL, fill = NULL, size = NULL, + linewidth = NULL, linetype = 1, alpha = NA, stroke = 0.5 @@ -171,10 +172,11 @@ sf_grob <- function(x, lineend = "butt", linejoin = "round", linemitre = 10, na. fill <- x$fill %||% defaults$fill[type_ind] fill <- alpha(fill, alpha) size <- x$size %||% defaults$size[type_ind] + linewidth <- x$linewidth %||% defaults$linewidth[type_ind] point_size <- ifelse(is_collection, x$size %||% defaults$point_size[type_ind], size) stroke <- (x$stroke %||% defaults$stroke[1]) * .stroke / 2 fontsize <- point_size * .pt + stroke - lwd <- ifelse(is_point, stroke, size * .pt) + lwd <- ifelse(is_point, stroke, linewidth * .pt) pch <- x$shape %||% defaults$shape[type_ind] lty <- x$linetype %||% defaults$linetype[type_ind] gp <- gpar( diff --git a/R/geom-smooth.r b/R/geom-smooth.r index 05bd1a8f29..ad26963832 100644 --- a/R/geom-smooth.r +++ b/R/geom-smooth.r @@ -158,6 +158,6 @@ GeomSmooth <- ggproto("GeomSmooth", Geom, required_aes = c("x", "y"), optional_aes = c("ymin", "ymax"), - default_aes = aes(colour = "#3366FF", fill = "grey60", size = 1, + default_aes = aes(colour = "#3366FF", fill = "grey60", linewidth = 1, linetype = 1, weight = 1, alpha = 0.4) ) diff --git a/R/geom-spoke.r b/R/geom-spoke.r index 2b6801a51e..dd790d3d16 100644 --- a/R/geom-spoke.r +++ b/R/geom-spoke.r @@ -55,6 +55,7 @@ stat_spoke <- function(...) { #' @export GeomSpoke <- ggproto("GeomSpoke", GeomSegment, setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$radius <- data$radius %||% params$radius data$angle <- data$angle %||% params$angle diff --git a/R/geom-tile.r b/R/geom-tile.r index 8c31e32148..1cbec247c5 100644 --- a/R/geom-tile.r +++ b/R/geom-tile.r @@ -87,6 +87,7 @@ GeomTile <- ggproto("GeomTile", GeomRect, extra_params = c("na.rm"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$width <- data$width %||% params$width %||% resolution(data$x, FALSE) data$height <- data$height %||% params$height %||% resolution(data$y, FALSE) @@ -96,7 +97,7 @@ GeomTile <- ggproto("GeomTile", GeomRect, ) }, - default_aes = aes(fill = "grey20", colour = NA, size = 0.1, linetype = 1, + default_aes = aes(fill = "grey20", colour = NA, linewidth = 0.1, linetype = 1, alpha = NA, width = NA, height = NA), required_aes = c("x", "y"), diff --git a/R/geom-violin.r b/R/geom-violin.r index 9a56f34639..b1e5fab530 100644 --- a/R/geom-violin.r +++ b/R/geom-violin.r @@ -116,6 +116,7 @@ GeomViolin <- ggproto("GeomViolin", Geom, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { + data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% @@ -179,7 +180,7 @@ GeomViolin <- ggproto("GeomViolin", Geom, draw_key = draw_key_polygon, - default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = 0.5, + default_aes = aes(weight = 1, colour = "grey20", fill = "white", linewidth = 0.5, alpha = NA, linetype = "solid"), required_aes = c("x", "y") diff --git a/R/geom-vline.r b/R/geom-vline.r index 3c22e0b1c9..d14688371b 100644 --- a/R/geom-vline.r +++ b/R/geom-vline.r @@ -54,8 +54,11 @@ GeomVline <- ggproto("GeomVline", Geom, GeomSegment$draw_panel(unique(data), panel_params, coord) }, + setup_data = function(data, params) { + rename_size_aesthetic(data) + }, - default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA), + default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = "xintercept", draw_key = draw_key_vline diff --git a/R/legend-draw.r b/R/legend-draw.r index 6e51a63488..4b3dd37329 100644 --- a/R/legend-draw.r +++ b/R/legend-draw.r @@ -47,7 +47,7 @@ draw_key_abline <- function(data, params, size) { segmentsGrob(0, 0, 1, 1, gp = gpar( col = alpha(data$colour %||% data$fill %||% "black", data$alpha), - lwd = (data$size %||% 0.5) * .pt, + lwd = (data$linewidth %||% 0.5) * .pt, lty = data$linetype %||% 1, lineend = "butt" ) @@ -66,11 +66,11 @@ draw_key_rect <- function(data, params, size) { #' @export #' @rdname draw_key draw_key_polygon <- function(data, params, size) { - if (is.null(data$size)) { - data$size <- 0.5 + if (is.null(data$linewidth)) { + data$linewidth <- 0.5 } - lwd <- min(data$size, min(size) / 4) + lwd <- min(data$linewidth, min(size) / 4) rectGrob( width = unit(1, "npc") - unit(lwd, "mm"), @@ -104,7 +104,7 @@ draw_key_boxplot <- function(data, params, size) { gp = gpar( col = data$colour %||% "grey20", fill = alpha(data$fill %||% "white", data$alpha), - lwd = (data$size %||% 0.5) * .pt, + lwd = (data$linewidth %||% 0.5) * .pt, lty = data$linetype %||% 1 ) ) @@ -119,7 +119,7 @@ draw_key_crossbar <- function(data, params, size) { gp = gpar( col = data$colour %||% "grey20", fill = alpha(data$fill %||% "white", data$alpha), - lwd = (data$size %||% 0.5) * .pt, + lwd = (data$linewidth %||% 0.5) * .pt, lty = data$linetype %||% 1 ) ) @@ -137,7 +137,7 @@ draw_key_path <- function(data, params, size) { segmentsGrob(0.1, 0.5, 0.9, 0.5, gp = gpar( col = alpha(data$colour %||% data$fill %||% "black", data$alpha), - lwd = (data$size %||% 0.5) * .pt, + lwd = (data$linewidth %||% 0.5) * .pt, lty = data$linetype %||% 1, lineend = "butt" ), @@ -151,7 +151,7 @@ draw_key_vpath <- function(data, params, size) { segmentsGrob(0.5, 0.1, 0.5, 0.9, gp = gpar( col = alpha(data$colour %||% data$fill %||% "black", data$alpha), - lwd = (data$size %||% 0.5) * .pt, + lwd = (data$linewidth %||% 0.5) * .pt, lty = data$linetype %||% 1, lineend = "butt" ), @@ -176,7 +176,7 @@ draw_key_dotplot <- function(data, params, size) { draw_key_pointrange <- function(data, params, size) { grobTree( draw_key_vpath(data, params, size), - draw_key_point(transform(data, size = (data$size %||% 1.5) * 4), params) + draw_key_point(transform(data, size = (data$size %||% 1.5) * 4), params, size) ) } @@ -188,7 +188,7 @@ draw_key_smooth <- function(data, params, size) { grobTree( if (isTRUE(params$se)) rectGrob(gp = gpar(col = NA, fill = data$fill)), - draw_key_path(data, params) + draw_key_path(data, params, size) ) } @@ -223,7 +223,7 @@ draw_key_vline <- function(data, params, size) { segmentsGrob(0.5, 0, 0.5, 1, gp = gpar( col = alpha(data$colour %||% data$fill %||% "black", data$alpha), - lwd = (data$size %||% 0.5) * .pt, + lwd = (data$linewidth %||% 0.5) * .pt, lty = data$linetype %||% 1, lineend = "butt" ) @@ -244,7 +244,7 @@ draw_key_timeseries <- function(data, params, size) { y = c(0.1, 0.6, 0.4, 0.9), gp = gpar( col = alpha(data$colour %||% data$fill %||% "black", data$alpha), - lwd = (data$size %||% 0.5) * .pt, + lwd = (data$linewidth %||% 0.5) * .pt, lty = data$linetype %||% 1, lineend = "butt" ) diff --git a/R/scale-linewidth.R b/R/scale-linewidth.R new file mode 100644 index 0000000000..9a954ae22c --- /dev/null +++ b/R/scale-linewidth.R @@ -0,0 +1,84 @@ +#' Scales for line width +#' +#' `scale_linewidth` scales the width of lines and polygon strokes. Due to +#' historical reasons, it is also possible to control this with the `size` +#' aesthetic, but using `linewidth` is encourage to clearly differentiate area +#' aesthetics from line aesthetics. +#' +#' @name scale_linewidth +#' @inheritParams continuous_scale +#' @inheritParams binned_scale +#' @param range a numeric vector of length 2 that specifies the minimum and +#' maximum size of the plotting symbol after transformation. +#' @examples +#' +NULL + +#' @rdname scale_linewidth +#' @export +#' @usage NULL +scale_linewidth_continuous <- function(name = waiver(), breaks = waiver(), + labels = waiver(), limits = NULL, + range = c(1, 6), trans = "identity", + guide = "legend") { + continuous_scale("linewidth", "linewidth_c", rescale_pal(range), name = name, + breaks = breaks, labels = labels, limits = limits, trans = trans, + guide = guide) +} + +#' @rdname scale_linewidth +#' @export +scale_linewidth <- scale_linewidth_continuous + +#' @rdname scale_linewidth +#' @export +scale_linewidth_binned <- function(name = waiver(), breaks = waiver(), labels = waiver(), + limits = NULL, range = c(1, 6), n.breaks = NULL, + nice.breaks = TRUE, trans = "identity", guide = "bins") { + binned_scale("linewidth", "linewidth_b", rescale_pal(range), name = name, + breaks = breaks, labels = labels, limits = limits, trans = trans, + n.breaks = n.breaks, nice.breaks = nice.breaks, guide = guide) +} + +#' @rdname scale_linewidth +#' @export +#' @usage NULL +scale_size_discrete <- function(...) { + warning("Using linewidth for a discrete variable is not advised.", call. = FALSE) + scale_linewidth_ordinal(...) +} + +#' @rdname scale_linewidth +#' @export +#' @usage NULL +scale_linewidth_ordinal <- function(..., range = c(2, 6)) { + force(range) + + discrete_scale( + "linewidth", + "linewidth_d", + function(n) seq(range[1], range[2], length.out = n), + ... + ) +} + +#' @rdname scale_linewidth +#' @export +#' @usage NULL +scale_linewidth_datetime <- function(..., range = c(1, 6)) { + datetime_scale("linewidth", "time", palette = rescale_pal(range), ...) +} + +#' @rdname scale_linewidth +#' @export +#' @usage NULL +scale_linewidth_date <- function(..., range = c(1, 6)) { + datetime_scale("linewidth", "date", palette = rescale_pal(range), ...) +} + +rename_size_aesthetic <- function(data) { + if (is.null(data$linewidth)) { + data$linewidth <- data$size + } + data +} From c114f144d84723e07dfe7d09f73892dc618ebe13 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 23 May 2022 14:36:17 +0200 Subject: [PATCH 02/11] fix leftover size->linewidth --- R/geom-path.r | 2 +- R/geom-ribbon.r | 2 +- R/geom-rug.r | 2 +- tests/testthat/_snaps/guides.md | 20 ++++++++++---------- tests/testthat/test-geom-hex.R | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/R/geom-path.r b/R/geom-path.r index 7b542e922d..7d27e9e71f 100644 --- a/R/geom-path.r +++ b/R/geom-path.r @@ -135,7 +135,7 @@ GeomPath <- ggproto("GeomPath", Geom, handle_na = function(self, data, params) { # Drop missing values at the start or end of a line - can't drop in the # middle since you expect those to be shown by a break in the line - complete <- stats::complete.cases(data[c("x", "y", "size", "colour", "linetype")]) + complete <- stats::complete.cases(data[c("x", "y", "linewidth", "colour", "linetype")]) kept <- stats::ave(complete, data$group, FUN = keep_mid_true) data <- data[kept, ] diff --git a/R/geom-ribbon.r b/R/geom-ribbon.r index 7b5702e6af..a8af279e28 100644 --- a/R/geom-ribbon.r +++ b/R/geom-ribbon.r @@ -159,7 +159,7 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, gp = gpar( fill = alpha(aes$fill, aes$alpha), col = if (is_full_outline) aes$colour else NA, - lwd = if (is_full_outline) aes$size * .pt else 0, + lwd = if (is_full_outline) aes$linewidth * .pt else 0, lty = if (is_full_outline) aes$linetype else 1, lineend = lineend, linejoin = linejoin, diff --git a/R/geom-rug.r b/R/geom-rug.r index 83f477be19..69c5437965 100644 --- a/R/geom-rug.r +++ b/R/geom-rug.r @@ -112,7 +112,7 @@ GeomRug <- ggproto("GeomRug", Geom, gp <- gpar( col = alpha(data$colour, data$alpha), lty = data$linetype, - lwd = data$size * .pt, + lwd = data$linewidth * .pt, lineend = lineend ) if (!is.null(data$x)) { diff --git a/tests/testthat/_snaps/guides.md b/tests/testthat/_snaps/guides.md index 4b9f4b317b..88a8a97b71 100644 --- a/tests/testthat/_snaps/guides.md +++ b/tests/testthat/_snaps/guides.md @@ -1,13 +1,3 @@ -# binning scales understand the different combinations of limits, breaks, labels, and show.limits - - `show.limits` is ignored when `labels` are given as a character vector - i Either add the limits to `breaks` or provide a function for `labels` - ---- - - `show.limits` is ignored when `labels` are given as a character vector - i Either add the limits to `breaks` or provide a function for `labels` - # axis_label_element_overrides errors when angles are outside the range [0, 90] Unrecognized `axis_position`: "test" @@ -68,6 +58,16 @@ Breaks not formatted correctly for a bin legend. i Use `(, ]` format to indicate bins +# binning scales understand the different combinations of limits, breaks, labels, and show.limits + + `show.limits` is ignored when `labels` are given as a character vector + i Either add the limits to `breaks` or provide a function for `labels` + +--- + + `show.limits` is ignored when `labels` are given as a character vector + i Either add the limits to `breaks` or provide a function for `labels` + # a warning is generated when guides( = FALSE) is specified `guide = FALSE` is deprecated diff --git a/tests/testthat/test-geom-hex.R b/tests/testthat/test-geom-hex.R index 82465e2183..08669fdb88 100644 --- a/tests/testthat/test-geom-hex.R +++ b/tests/testthat/test-geom-hex.R @@ -12,7 +12,7 @@ test_that("density and value summaries are available", { test_that("size and linetype are applied", { df <- data_frame(x = c(1, 1, 1, 2), y = c(1, 1, 1, 2)) plot <- ggplot(df, aes(x, y)) + - geom_hex(color = "red", size = 4, linetype = 2) + geom_hex(color = "red", linewidth = 4, linetype = 2) gpar <- layer_grob(plot)[[1]]$children[[1]]$gp expect_equal(gpar$lwd, rep(4, 12) * .pt, tolerance = 1e-7) From 4d7dfe34ba4911d6a535cfd6e2d7397e6fc11984 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 23 May 2022 14:36:26 +0200 Subject: [PATCH 03/11] update visual tests --- .../draw-key/time-series-and-polygon-key-glyphs.svg | 6 +++--- .../_snaps/sec-axis/sec-axis-custom-transform.svg | 2 +- .../_snaps/stat-sum/summary-with-color-and-lines.svg | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/testthat/_snaps/draw-key/time-series-and-polygon-key-glyphs.svg b/tests/testthat/_snaps/draw-key/time-series-and-polygon-key-glyphs.svg index e8e6e2e746..1bac8bca4d 100644 --- a/tests/testthat/_snaps/draw-key/time-series-and-polygon-key-glyphs.svg +++ b/tests/testthat/_snaps/draw-key/time-series-and-polygon-key-glyphs.svg @@ -64,11 +64,11 @@ z - + - + - + a b c diff --git a/tests/testthat/_snaps/sec-axis/sec-axis-custom-transform.svg b/tests/testthat/_snaps/sec-axis/sec-axis-custom-transform.svg index 0d7652d395..42e97e6544 100644 --- a/tests/testthat/_snaps/sec-axis/sec-axis-custom-transform.svg +++ b/tests/testthat/_snaps/sec-axis/sec-axis-custom-transform.svg @@ -53,7 +53,7 @@ - + diff --git a/tests/testthat/_snaps/stat-sum/summary-with-color-and-lines.svg b/tests/testthat/_snaps/stat-sum/summary-with-color-and-lines.svg index 0045dd43fc..3e893f5010 100644 --- a/tests/testthat/_snaps/stat-sum/summary-with-color-and-lines.svg +++ b/tests/testthat/_snaps/stat-sum/summary-with-color-and-lines.svg @@ -59,8 +59,8 @@ - - + + @@ -92,10 +92,10 @@ factor(vs) - + - + 0 1 summary with color and lines From c9d7a6f6cafaec6a9fffa13754927b1cdb9c1936 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 23 May 2022 15:11:03 +0200 Subject: [PATCH 04/11] fix various edge cases --- R/geom-sf.R | 6 +++++- R/scale-linewidth.R | 4 ++-- .../_snaps/sec-axis/sec-axis-custom-transform.svg | 2 +- .../_snaps/stat-sum/summary-with-color-and-lines.svg | 8 ++++---- tests/testthat/test-geom-tile.R | 2 +- tests/testthat/test-scales.r | 4 ++++ tests/testthat/test-sec-axis.R | 2 +- tests/testthat/test-stat-sum.R | 2 +- 8 files changed, 19 insertions(+), 11 deletions(-) diff --git a/R/geom-sf.R b/R/geom-sf.R index 163c5ccda3..593ba18764 100644 --- a/R/geom-sf.R +++ b/R/geom-sf.R @@ -202,7 +202,11 @@ sf_grob <- function(x, lineend = "butt", linejoin = "round", linemitre = 10, fill <- alpha(fill, alpha) size <- x$size %||% defaults$size[type_ind] linewidth <- x$linewidth %||% defaults$linewidth[type_ind] - point_size <- ifelse(is_collection, x$size %||% defaults$point_size[type_ind], size) + point_size <- ifelse( + is_collection, + x$size %||% defaults$point_size[type_ind], + ifelse(is_point, size, linewidth) + ) stroke <- (x$stroke %||% defaults$stroke[1]) * .stroke / 2 fontsize <- point_size * .pt + stroke lwd <- ifelse(is_point, stroke, linewidth * .pt) diff --git a/R/scale-linewidth.R b/R/scale-linewidth.R index 9a954ae22c..b850a6bb51 100644 --- a/R/scale-linewidth.R +++ b/R/scale-linewidth.R @@ -43,8 +43,8 @@ scale_linewidth_binned <- function(name = waiver(), breaks = waiver(), labels = #' @rdname scale_linewidth #' @export #' @usage NULL -scale_size_discrete <- function(...) { - warning("Using linewidth for a discrete variable is not advised.", call. = FALSE) +scale_linewidth_discrete <- function(...) { + cli::cli_warn("Using {.field linewidth} for a discrete variable is not advised.") scale_linewidth_ordinal(...) } diff --git a/tests/testthat/_snaps/sec-axis/sec-axis-custom-transform.svg b/tests/testthat/_snaps/sec-axis/sec-axis-custom-transform.svg index 42e97e6544..0d7652d395 100644 --- a/tests/testthat/_snaps/sec-axis/sec-axis-custom-transform.svg +++ b/tests/testthat/_snaps/sec-axis/sec-axis-custom-transform.svg @@ -53,7 +53,7 @@ - + diff --git a/tests/testthat/_snaps/stat-sum/summary-with-color-and-lines.svg b/tests/testthat/_snaps/stat-sum/summary-with-color-and-lines.svg index 3e893f5010..0045dd43fc 100644 --- a/tests/testthat/_snaps/stat-sum/summary-with-color-and-lines.svg +++ b/tests/testthat/_snaps/stat-sum/summary-with-color-and-lines.svg @@ -59,8 +59,8 @@ - - + + @@ -92,10 +92,10 @@ factor(vs) - + - + 0 1 summary with color and lines diff --git a/tests/testthat/test-geom-tile.R b/tests/testthat/test-geom-tile.R index 00261386ca..d0c8a6f073 100644 --- a/tests/testthat/test-geom-tile.R +++ b/tests/testthat/test-geom-tile.R @@ -14,7 +14,7 @@ test_that("accepts width and height aesthetics", { df <- data_frame(x = 0, y = 0, width = c(2, 4), height = c(2, 4)) p <- ggplot(df, aes(x, y, width = width, height = height)) + - geom_tile(fill = NA, colour = "black", size = 1) + geom_tile(fill = NA, colour = "black", linewidth = 1) out <- layer_data(p) boundary <- as.data.frame(tibble::tribble( diff --git a/tests/testthat/test-scales.r b/tests/testthat/test-scales.r index b3a6e9bbb3..7be46b4dde 100644 --- a/tests/testthat/test-scales.r +++ b/tests/testthat/test-scales.r @@ -229,6 +229,10 @@ test_that("size and alpha scales throw appropriate warnings for factors", { ggplot_build(p + geom_point(aes(alpha = d))), "Using alpha for a discrete variable is not advised." ) + expect_warning( + ggplot_build(p + geom_line(aes(linewidth = d, group = 1))), + "Using linewidth for a discrete variable is not advised." + ) # There should be no warnings for ordered factors expect_warning(ggplot_build(p + geom_point(aes(size = o))), NA) expect_warning(ggplot_build(p + geom_point(aes(alpha = o))), NA) diff --git a/tests/testthat/test-sec-axis.R b/tests/testthat/test-sec-axis.R index 68067df80b..d77ee102bf 100644 --- a/tests/testthat/test-sec-axis.R +++ b/tests/testthat/test-sec-axis.R @@ -242,7 +242,7 @@ test_that("sec_axis() respects custom transformations", { expect_doppelganger( "sec_axis, custom transform", ggplot(dat, aes(x = x, y = y)) + - geom_line(size = 1, na.rm = T) + + geom_line(linewidth = 1, na.rm = T) + scale_y_continuous( trans = magnify_trans_log(interval_low = 0.5, interval_high = 1, reducer = 0.5, reducer2 = 8), breaks = diff --git a/tests/testthat/test-stat-sum.R b/tests/testthat/test-stat-sum.R index 43734a0961..350665d561 100644 --- a/tests/testthat/test-stat-sum.R +++ b/tests/testthat/test-stat-sum.R @@ -47,7 +47,7 @@ test_that("summaries are drawn correctly", { expect_doppelganger("summary with color and lines", ggplot(mtcars, aes(x = cyl, y = mpg, colour = factor(vs))) + geom_point() + - stat_summary(fun = mean, geom = "line", size = 2) + stat_summary(fun = mean, geom = "line", linewidth = 2) ) expect_doppelganger("summary with crossbars, no grouping", ggplot(mtcars, aes(x = cyl, y = mpg)) + From 401a10c1bdebd3186d9686a552c68c9393427e41 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Tue, 24 May 2022 09:45:12 +0200 Subject: [PATCH 05/11] document --- DESCRIPTION | 3 +- NAMESPACE | 7 +++ man/geom_abline.Rd | 2 +- man/geom_bar.Rd | 4 +- man/geom_boxplot.Rd | 1 + man/geom_contour.Rd | 4 +- man/geom_density.Rd | 2 +- man/geom_density_2d.Rd | 4 +- man/geom_errorbarh.Rd | 2 +- man/geom_function.Rd | 2 +- man/geom_hex.Rd | 2 +- man/geom_linerange.Rd | 2 +- man/geom_map.Rd | 2 +- man/geom_path.Rd | 2 +- man/geom_polygon.Rd | 2 +- man/geom_quantile.Rd | 2 +- man/geom_ribbon.Rd | 2 +- man/geom_rug.Rd | 2 +- man/geom_segment.Rd | 2 +- man/geom_smooth.Rd | 2 +- man/geom_spoke.Rd | 2 +- man/geom_tile.Rd | 2 +- man/geom_violin.Rd | 2 +- man/scale_linewidth.Rd | 111 +++++++++++++++++++++++++++++++++++++++++ 24 files changed, 144 insertions(+), 24 deletions(-) create mode 100644 man/scale_linewidth.Rd diff --git a/DESCRIPTION b/DESCRIPTION index a5f7d1dde9..16ecbb2405 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -80,7 +80,7 @@ Config/testthat/edition: 3 Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.0 +RoxygenNote: 7.2.0.9000 Collate: 'ggproto.r' 'ggplot-global.R' @@ -222,6 +222,7 @@ Collate: 'scale-hue.r' 'scale-identity.r' 'scale-linetype.r' + 'scale-linewidth.R' 'scale-manual.r' 'scale-shape.r' 'scale-size.r' diff --git a/NAMESPACE b/NAMESPACE index a931b99665..15d7b9c658 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -557,6 +557,13 @@ export(scale_linetype_continuous) export(scale_linetype_discrete) export(scale_linetype_identity) export(scale_linetype_manual) +export(scale_linewidth) +export(scale_linewidth_binned) +export(scale_linewidth_continuous) +export(scale_linewidth_date) +export(scale_linewidth_datetime) +export(scale_linewidth_discrete) +export(scale_linewidth_ordinal) export(scale_radius) export(scale_shape) export(scale_shape_binned) diff --git a/man/geom_abline.Rd b/man/geom_abline.Rd index d018b98860..03baa1d9b2 100644 --- a/man/geom_abline.Rd +++ b/man/geom_abline.Rd @@ -92,7 +92,7 @@ commonly set in the plot. They also do not affect the x and y scales. These geoms are drawn using with \code{\link[=geom_line]{geom_line()}} so support the same aesthetics: \code{alpha}, \code{colour}, \code{linetype} and -\code{size}. They also each have aesthetics that control the position of +\code{linewidth}. They also each have aesthetics that control the position of the line: \itemize{ \item \code{geom_vline()}: \code{xintercept} diff --git a/man/geom_bar.Rd b/man/geom_bar.Rd index d6a03c24e9..734c0d42c1 100644 --- a/man/geom_bar.Rd +++ b/man/geom_bar.Rd @@ -140,7 +140,7 @@ This geom treats each axis differently and, thus, can thus have two orientations \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. @@ -154,7 +154,7 @@ Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/geom_boxplot.Rd b/man/geom_boxplot.Rd index 3f8684b2c2..f9b850bcf0 100644 --- a/man/geom_boxplot.Rd +++ b/man/geom_boxplot.Rd @@ -165,6 +165,7 @@ See McGill et al. (1978) for more details. \item \code{fill} \item \code{group} \item \code{linetype} +\item \code{linewidth} \item \code{shape} \item \code{size} \item \code{weight} diff --git a/man/geom_contour.Rd b/man/geom_contour.Rd index cd653ee332..8341670c2d 100644 --- a/man/geom_contour.Rd +++ b/man/geom_contour.Rd @@ -162,7 +162,7 @@ using \code{\link[interp:interp]{interp::interp()}}, \code{\link[akima:bilinear] \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{weight} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. @@ -177,7 +177,7 @@ Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{subgroup} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/geom_density.Rd b/man/geom_density.Rd index dd8469635f..02fdc43627 100644 --- a/man/geom_density.Rd +++ b/man/geom_density.Rd @@ -135,7 +135,7 @@ This geom treats each axis differently and, thus, can thus have two orientations \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{weight} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/geom_density_2d.Rd b/man/geom_density_2d.Rd index 66639998ce..2b7337cfc4 100644 --- a/man/geom_density_2d.Rd +++ b/man/geom_density_2d.Rd @@ -170,7 +170,7 @@ bands. \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. @@ -184,7 +184,7 @@ Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{subgroup} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/geom_errorbarh.Rd b/man/geom_errorbarh.Rd index 5ba6f86942..d6f2c135dd 100644 --- a/man/geom_errorbarh.Rd +++ b/man/geom_errorbarh.Rd @@ -80,7 +80,7 @@ A rotated version of \code{\link[=geom_errorbar]{geom_errorbar()}}. \item \code{group} \item \code{height} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. } diff --git a/man/geom_function.Rd b/man/geom_function.Rd index 9900a10877..5dc8ef87d7 100644 --- a/man/geom_function.Rd +++ b/man/geom_function.Rd @@ -99,7 +99,7 @@ drawn (by default) with a line. \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. } diff --git a/man/geom_hex.Rd b/man/geom_hex.Rd index 97b41b321d..a6962f7cfd 100644 --- a/man/geom_hex.Rd +++ b/man/geom_hex.Rd @@ -101,7 +101,7 @@ the very regular alignment of \code{\link[=geom_bin2d]{geom_bin2d()}}. \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. } diff --git a/man/geom_linerange.Rd b/man/geom_linerange.Rd index 78d5957f78..d274ad2c1b 100644 --- a/man/geom_linerange.Rd +++ b/man/geom_linerange.Rd @@ -137,7 +137,7 @@ This geom treats each axis differently and, thus, can thus have two orientations \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. } diff --git a/man/geom_map.Rd b/man/geom_map.Rd index a992619015..3796ca67eb 100644 --- a/man/geom_map.Rd +++ b/man/geom_map.Rd @@ -78,7 +78,7 @@ This is pure annotation, so does not affect position scales. \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{subgroup} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/geom_path.Rd b/man/geom_path.Rd index b5b5db79a9..9d2af717fc 100644 --- a/man/geom_path.Rd +++ b/man/geom_path.Rd @@ -138,7 +138,7 @@ This geom treats each axis differently and, thus, can thus have two orientations \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. } diff --git a/man/geom_polygon.Rd b/man/geom_polygon.Rd index d94e333541..81d1eb61a6 100644 --- a/man/geom_polygon.Rd +++ b/man/geom_polygon.Rd @@ -91,7 +91,7 @@ polygon. \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{subgroup} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/geom_quantile.Rd b/man/geom_quantile.Rd index fe7a8f4830..cd53c5ee08 100644 --- a/man/geom_quantile.Rd +++ b/man/geom_quantile.Rd @@ -112,7 +112,7 @@ with lines. This is as a continuous analogue to \code{\link[=geom_boxplot]{geom_ \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{weight} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/geom_ribbon.Rd b/man/geom_ribbon.Rd index f8ef013641..21d0c9c21b 100644 --- a/man/geom_ribbon.Rd +++ b/man/geom_ribbon.Rd @@ -121,7 +121,7 @@ This geom treats each axis differently and, thus, can thus have two orientations \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. } diff --git a/man/geom_rug.Rd b/man/geom_rug.Rd index 9a1723e074..91eed7baa0 100644 --- a/man/geom_rug.Rd +++ b/man/geom_rug.Rd @@ -95,7 +95,7 @@ any data points under the default settings. \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{x} \item \code{y} } diff --git a/man/geom_segment.Rd b/man/geom_segment.Rd index b93f35c05d..310daacc1f 100644 --- a/man/geom_segment.Rd +++ b/man/geom_segment.Rd @@ -131,7 +131,7 @@ need to connect points across multiple cases. \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. } diff --git a/man/geom_smooth.Rd b/man/geom_smooth.Rd index 7df592c77f..ba84914d29 100644 --- a/man/geom_smooth.Rd +++ b/man/geom_smooth.Rd @@ -165,7 +165,7 @@ This geom treats each axis differently and, thus, can thus have two orientations \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{weight} \item \code{ymax} \item \code{ymin} diff --git a/man/geom_spoke.Rd b/man/geom_spoke.Rd index fbd2728756..d38bd3aa45 100644 --- a/man/geom_spoke.Rd +++ b/man/geom_spoke.Rd @@ -83,7 +83,7 @@ The angles start from east and increase counterclockwise. \item \code{colour} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. } diff --git a/man/geom_tile.Rd b/man/geom_tile.Rd index a07095f2b6..2da772536c 100644 --- a/man/geom_tile.Rd +++ b/man/geom_tile.Rd @@ -123,7 +123,7 @@ performance special case for when all the tiles are the same size. \item \code{group} \item \code{height} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{width} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/geom_violin.Rd b/man/geom_violin.Rd index 6f3500a0c1..c125383a95 100644 --- a/man/geom_violin.Rd +++ b/man/geom_violin.Rd @@ -133,7 +133,7 @@ This geom treats each axis differently and, thus, can thus have two orientations \item \code{fill} \item \code{group} \item \code{linetype} -\item \code{size} +\item \code{linewidth} \item \code{weight} } Learn more about setting these aesthetics in \code{vignette("ggplot2-specs")}. diff --git a/man/scale_linewidth.Rd b/man/scale_linewidth.Rd new file mode 100644 index 0000000000..074f201ca6 --- /dev/null +++ b/man/scale_linewidth.Rd @@ -0,0 +1,111 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/scale-linewidth.R +\name{scale_linewidth} +\alias{scale_linewidth} +\alias{scale_linewidth_continuous} +\alias{scale_linewidth_binned} +\alias{scale_linewidth_discrete} +\alias{scale_linewidth_ordinal} +\alias{scale_linewidth_datetime} +\alias{scale_linewidth_date} +\title{Scales for line width} +\usage{ +scale_linewidth( + name = waiver(), + breaks = waiver(), + labels = waiver(), + limits = NULL, + range = c(1, 6), + trans = "identity", + guide = "legend" +) + +scale_linewidth_binned( + name = waiver(), + breaks = waiver(), + labels = waiver(), + limits = NULL, + range = c(1, 6), + n.breaks = NULL, + nice.breaks = TRUE, + trans = "identity", + guide = "bins" +) +} +\arguments{ +\item{name}{The name of the scale. Used as the axis or legend title. If +\code{waiver()}, the default, the name of the scale is taken from the first +mapping used for that aesthetic. If \code{NULL}, the legend title will be +omitted.} + +\item{breaks}{One of: +\itemize{ +\item \code{NULL} for no breaks +\item \code{waiver()} for the default breaks computed by the +\link[scales:trans_new]{transformation object} +\item A numeric vector of positions +\item A function that takes the limits as input and returns breaks +as output (e.g., a function returned by \code{\link[scales:breaks_extended]{scales::extended_breaks()}}). +Also accepts rlang \link[rlang:as_function]{lambda} function notation. +}} + +\item{labels}{One of: +\itemize{ +\item \code{NULL} for no labels +\item \code{waiver()} for the default labels computed by the +transformation object +\item A character vector giving labels (must be same length as \code{breaks}) +\item An expression vector (must be the same length as breaks). See ?plotmath for details. +\item A function that takes the breaks as input and returns labels +as output. Also accepts rlang \link[rlang:as_function]{lambda} function +notation. +}} + +\item{limits}{One of: +\itemize{ +\item \code{NULL} to use the default scale range +\item A numeric vector of length two providing limits of the scale. +Use \code{NA} to refer to the existing minimum or maximum +\item A function that accepts the existing (automatic) limits and returns +new limits. Also accepts rlang \link[rlang:as_function]{lambda} function +notation. +Note that setting limits on positional scales will \strong{remove} data outside of the limits. +If the purpose is to zoom, use the limit argument in the coordinate system +(see \code{\link[=coord_cartesian]{coord_cartesian()}}). +}} + +\item{range}{a numeric vector of length 2 that specifies the minimum and +maximum size of the plotting symbol after transformation.} + +\item{trans}{For continuous scales, the name of a transformation object +or the object itself. Built-in transformations include "asn", "atanh", +"boxcox", "date", "exp", "hms", "identity", "log", "log10", "log1p", "log2", +"logit", "modulus", "probability", "probit", "pseudo_log", "reciprocal", +"reverse", "sqrt" and "time". + +A transformation object bundles together a transform, its inverse, +and methods for generating breaks and labels. Transformation objects +are defined in the scales package, and are called \verb{_trans} (e.g., +\code{\link[scales:boxcox_trans]{scales::boxcox_trans()}}). You can create your own +transformation with \code{\link[scales:trans_new]{scales::trans_new()}}.} + +\item{guide}{A function used to create a guide or its name. See +\code{\link[=guides]{guides()}} for more information.} + +\item{n.breaks}{An integer guiding the number of major breaks. The algorithm +may choose a slightly different number to ensure nice break labels. Will +only have an effect if \code{breaks = waiver()}. Use \code{NULL} to use the default +number of breaks given by the transformation.} + +\item{nice.breaks}{Logical. Should breaks be attempted placed at nice values +instead of exactly evenly spaced between the limits. If \code{TRUE} (default) +the scale will ask the transformation object to create breaks, and this +may result in a different number of breaks than requested. Ignored if +breaks are given explicitly.} +} +\description{ +\code{scale_linewidth} scales the width of lines and polygon strokes. Due to +historical reasons, it is also possible to control this with the \code{size} +aesthetic, but using \code{linewidth} is encourage to clearly differentiate area +aesthetics from line aesthetics. +} From 98c425aed5c3f9fca18314adef7e75d6d3cfa7f4 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Tue, 24 May 2022 10:22:23 +0200 Subject: [PATCH 06/11] fix vignette --- R/scale-linewidth.R | 10 +++++++++- man/scale_linewidth.Rd | 13 ++++++++++++- vignettes/extending-ggplot2.Rmd | 6 +++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/R/scale-linewidth.R b/R/scale-linewidth.R index b850a6bb51..535b4aeba6 100644 --- a/R/scale-linewidth.R +++ b/R/scale-linewidth.R @@ -3,7 +3,7 @@ #' `scale_linewidth` scales the width of lines and polygon strokes. Due to #' historical reasons, it is also possible to control this with the `size` #' aesthetic, but using `linewidth` is encourage to clearly differentiate area -#' aesthetics from line aesthetics. +#' aesthetics from stroke width aesthetics. #' #' @name scale_linewidth #' @inheritParams continuous_scale @@ -11,6 +11,14 @@ #' @param range a numeric vector of length 2 that specifies the minimum and #' maximum size of the plotting symbol after transformation. #' @examples +#' p <- ggplot(economics, aes(date, unemploy, linewidth = uempmed)) + +#' geom_line(lineend = "round") +#' p +#' p + scale_linewidth("Duration of\nunemployment") +#' p + scale_linewidth(range = c(0, 4)) +#' +#' # Binning can sometimes make it easier to match the scaled data to the legend +#' p + scale_linewidth_binned() #' NULL diff --git a/man/scale_linewidth.Rd b/man/scale_linewidth.Rd index 074f201ca6..eeb1ccb061 100644 --- a/man/scale_linewidth.Rd +++ b/man/scale_linewidth.Rd @@ -107,5 +107,16 @@ breaks are given explicitly.} \code{scale_linewidth} scales the width of lines and polygon strokes. Due to historical reasons, it is also possible to control this with the \code{size} aesthetic, but using \code{linewidth} is encourage to clearly differentiate area -aesthetics from line aesthetics. +aesthetics from stroke width aesthetics. +} +\examples{ +p <- ggplot(economics, aes(date, unemploy, linewidth = uempmed)) + + geom_line(lineend = "round") +p +p + scale_linewidth("Duration of\nunemployment") +p + scale_linewidth(range = c(0, 4)) + +# Binning can sometimes make it easier to match the scaled data to the legend +p + scale_linewidth_binned() + } diff --git a/vignettes/extending-ggplot2.Rmd b/vignettes/extending-ggplot2.Rmd index 9719384769..666d5409c9 100644 --- a/vignettes/extending-ggplot2.Rmd +++ b/vignettes/extending-ggplot2.Rmd @@ -401,7 +401,7 @@ GeomSimplePolygon <- ggproto("GeomPolygon", Geom, required_aes = c("x", "y"), default_aes = aes( - colour = NA, fill = "grey20", size = 0.5, + colour = NA, fill = "grey20", linewidth = 0.5, linetype = 1, alpha = 1 ), @@ -421,7 +421,7 @@ GeomSimplePolygon <- ggproto("GeomPolygon", Geom, gp = grid::gpar( col = first_row$colour, fill = scales::alpha(first_row$fill, first_row$alpha), - lwd = first_row$size * .pt, + lwd = first_row$linewidth * .pt, lty = first_row$linetype ) ) @@ -465,7 +465,7 @@ Sometimes you just want to make a small modification to an existing geom. In thi ```{r} GeomPolygonHollow <- ggproto("GeomPolygonHollow", GeomPolygon, - default_aes = aes(colour = "black", fill = NA, size = 0.5, linetype = 1, + default_aes = aes(colour = "black", fill = NA, linewidth = 0.5, linetype = 1, alpha = NA) ) geom_chull <- function(mapping = NULL, data = NULL, From 0499aa512449a26be6f201606da0c3305820e4a4 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Tue, 24 May 2022 13:52:09 +0200 Subject: [PATCH 07/11] update implementation to new and improved --- R/geom-.r | 10 +++++++++- R/geom-abline.r | 7 +++---- R/geom-bar.r | 1 - R/geom-boxplot.r | 5 +++-- R/geom-col.r | 5 +++-- R/geom-errorbar.r | 5 +++-- R/geom-errorbarh.r | 5 +++-- R/geom-hex.r | 7 +++---- R/geom-hline.r | 7 +++---- R/geom-linerange.r | 5 +++-- R/geom-path.r | 7 ++----- R/geom-polygon.r | 8 +++----- R/geom-rect.r | 6 ++---- R/geom-ribbon.r | 4 ++-- R/geom-rug.r | 8 +++----- R/geom-segment.r | 7 +++---- R/geom-spoke.r | 1 - R/geom-tile.r | 1 - R/geom-violin.r | 5 +++-- R/geom-vline.r | 7 +++---- R/guides-.r | 3 +++ R/layer.r | 20 ++++++++++++++++++++ R/scale-linewidth.R | 7 ------- 23 files changed, 77 insertions(+), 64 deletions(-) diff --git a/R/geom-.r b/R/geom-.r index 9bf55ff501..9ec3691ab9 100644 --- a/R/geom-.r +++ b/R/geom-.r @@ -108,6 +108,11 @@ Geom <- ggproto("Geom", # Combine data with defaults and set aesthetics from parameters use_defaults = function(self, data, params = list(), modifiers = aes()) { + # Inherit size as linewidth if no linewidth aesthetic and param exist + if (self$rename_size && is.null(data$linewidth) && is.null(params$linewidth)) { + data$linewidth <- data$size + params$linewidth <- params$size + } # Fill in missing aesthetics with their defaults missing_aes <- setdiff(names(self$default_aes), names(data)) @@ -187,7 +192,10 @@ Geom <- ggproto("Geom", required_aes <- unlist(strsplit(self$required_aes, '|', fixed = TRUE)) } c(union(required_aes, names(self$default_aes)), self$optional_aes, "group") - } + }, + + # Should the geom rename size to linewidth? + rename_size = FALSE ) diff --git a/R/geom-abline.r b/R/geom-abline.r index a94e730551..ff7d359ab6 100644 --- a/R/geom-abline.r +++ b/R/geom-abline.r @@ -124,9 +124,6 @@ geom_abline <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomAbline <- ggproto("GeomAbline", Geom, - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, draw_panel = function(data, panel_params, coord, lineend = "butt") { ranges <- coord$backtransform_range(panel_params) @@ -147,5 +144,7 @@ GeomAbline <- ggproto("GeomAbline", Geom, default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = c("slope", "intercept"), - draw_key = draw_key_abline + draw_key = draw_key_abline, + + rename_size = TRUE ) diff --git a/R/geom-bar.r b/R/geom-bar.r index b22e5736bd..4f5b3f9aa6 100644 --- a/R/geom-bar.r +++ b/R/geom-bar.r @@ -126,7 +126,6 @@ GeomBar <- ggproto("GeomBar", GeomRect, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% diff --git a/R/geom-boxplot.r b/R/geom-boxplot.r index 0a5eaaf4d5..d787f64b7a 100644 --- a/R/geom-boxplot.r +++ b/R/geom-boxplot.r @@ -175,7 +175,6 @@ GeomBoxplot <- ggproto("GeomBoxplot", Geom, }, setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% @@ -297,5 +296,7 @@ GeomBoxplot <- ggproto("GeomBoxplot", Geom, default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = NULL, alpha = NA, shape = 19, linetype = "solid", linewidth = 0.5), - required_aes = c("x|y", "lower|xlower", "upper|xupper", "middle|xmiddle", "ymin|xmin", "ymax|xmax") + required_aes = c("x|y", "lower|xlower", "upper|xupper", "middle|xmiddle", "ymin|xmin", "ymax|xmax"), + + rename_size = TRUE ) diff --git a/R/geom-col.r b/R/geom-col.r index 21c0e7a9c3..b75aa34e18 100644 --- a/R/geom-col.r +++ b/R/geom-col.r @@ -45,7 +45,6 @@ GeomCol <- ggproto("GeomCol", GeomRect, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% @@ -67,5 +66,7 @@ GeomCol <- ggproto("GeomCol", GeomRect, lineend = lineend, linejoin = linejoin ) - } + }, + + rename_size = TRUE ) diff --git a/R/geom-errorbar.r b/R/geom-errorbar.r index f4fdea5a6f..41e1cad5b5 100644 --- a/R/geom-errorbar.r +++ b/R/geom-errorbar.r @@ -42,7 +42,6 @@ GeomErrorbar <- ggproto("GeomErrorbar", Geom, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% @@ -69,5 +68,7 @@ GeomErrorbar <- ggproto("GeomErrorbar", Geom, )) data <- flip_data(data, flipped_aes) GeomPath$draw_panel(data, panel_params, coord, lineend = lineend) - } + }, + + rename_size = TRUE ) diff --git a/R/geom-errorbarh.r b/R/geom-errorbarh.r index a3a6eca9be..93ceea200d 100644 --- a/R/geom-errorbarh.r +++ b/R/geom-errorbarh.r @@ -59,7 +59,6 @@ GeomErrorbarh <- ggproto("GeomErrorbarh", Geom, required_aes = c("xmin", "xmax", "y"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$height <- data$height %||% params$height %||% (resolution(data$y, FALSE) * 0.9) @@ -79,5 +78,7 @@ GeomErrorbarh <- ggproto("GeomErrorbarh", Geom, group = rep(1:(nrow(data)), each = 8), row.names = 1:(nrow(data) * 8) )), panel_params, coord, lineend = lineend) - } + }, + + rename_size = TRUE ) diff --git a/R/geom-hex.r b/R/geom-hex.r index 79e42fbf16..421a3d0116 100644 --- a/R/geom-hex.r +++ b/R/geom-hex.r @@ -54,9 +54,6 @@ geom_hex <- function(mapping = NULL, data = NULL, #' @usage NULL #' @export GeomHex <- ggproto("GeomHex", Geom, - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, draw_group = function(data, panel_params, coord, lineend = "butt", linejoin = "mitre", linemitre = 10) { if (empty(data)) { @@ -114,7 +111,9 @@ GeomHex <- ggproto("GeomHex", Geom, alpha = NA ), - draw_key = draw_key_polygon + draw_key = draw_key_polygon, + + rename_size = TRUE ) diff --git a/R/geom-hline.r b/R/geom-hline.r index 394a06eb9f..f1e4bb8286 100644 --- a/R/geom-hline.r +++ b/R/geom-hline.r @@ -54,12 +54,11 @@ GeomHline <- ggproto("GeomHline", Geom, GeomSegment$draw_panel(unique(data), panel_params, coord, lineend = lineend) }, - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = "yintercept", - draw_key = draw_key_path + draw_key = draw_key_path, + + rename_size = TRUE ) diff --git a/R/geom-linerange.r b/R/geom-linerange.r index f412f77271..beb1b23cc6 100644 --- a/R/geom-linerange.r +++ b/R/geom-linerange.r @@ -109,7 +109,6 @@ GeomLinerange <- ggproto("GeomLinerange", Geom, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data }, @@ -119,5 +118,7 @@ GeomLinerange <- ggproto("GeomLinerange", Geom, data <- transform(data, xend = x, y = ymin, yend = ymax) data <- flip_data(data, flipped_aes) ggname("geom_linerange", GeomSegment$draw_panel(data, panel_params, coord, lineend = lineend)) - } + }, + + rename_size = TRUE ) diff --git a/R/geom-path.r b/R/geom-path.r index 7d27e9e71f..b8a76bf639 100644 --- a/R/geom-path.r +++ b/R/geom-path.r @@ -217,11 +217,9 @@ GeomPath <- ggproto("GeomPath", Geom, } }, - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, + draw_key = draw_key_path, - draw_key = draw_key_path + rename_size = TRUE ) # Trim false values from left and right: keep all values from @@ -276,7 +274,6 @@ GeomLine <- ggproto("GeomLine", GeomPath, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data <- data[order(data$PANEL, data$group, data$x), ] diff --git a/R/geom-polygon.r b/R/geom-polygon.r index 1a845f7adb..9c771cced7 100644 --- a/R/geom-polygon.r +++ b/R/geom-polygon.r @@ -174,10 +174,6 @@ GeomPolygon <- ggproto("GeomPolygon", Geom, } }, - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, - default_aes = aes(colour = NA, fill = "grey20", linewidth = 0.5, linetype = 1, alpha = NA, subgroup = NULL), @@ -187,7 +183,9 @@ GeomPolygon <- ggproto("GeomPolygon", Geom, required_aes = c("x", "y"), - draw_key = draw_key_polygon + draw_key = draw_key_polygon, + + rename_size = TRUE ) # Assigning pathGrob in .onLoad ensures that packages that subclass GeomPolygon diff --git a/R/geom-rect.r b/R/geom-rect.r index 2daff650b0..9ee285f5d6 100644 --- a/R/geom-rect.r +++ b/R/geom-rect.r @@ -67,11 +67,9 @@ GeomRect <- ggproto("GeomRect", Geom, } }, - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, + draw_key = draw_key_polygon, - draw_key = draw_key_polygon + rename_size = TRUE ) diff --git a/R/geom-ribbon.r b/R/geom-ribbon.r index a8af279e28..081b21fb30 100644 --- a/R/geom-ribbon.r +++ b/R/geom-ribbon.r @@ -86,7 +86,6 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, extra_params = c("na.rm", "orientation"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) @@ -197,8 +196,9 @@ GeomRibbon <- ggproto("GeomRibbon", Geom, ) ggname("geom_ribbon", grobTree(g_poly, g_lines)) - } + }, + rename_size = TRUE ) #' @rdname geom_ribbon diff --git a/R/geom-rug.r b/R/geom-rug.r index 69c5437965..6d4c3e7ac4 100644 --- a/R/geom-rug.r +++ b/R/geom-rug.r @@ -154,11 +154,9 @@ GeomRug <- ggproto("GeomRug", Geom, gTree(children = do.call("gList", rugs)) }, - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, - default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), - draw_key = draw_key_path + draw_key = draw_key_path, + + rename_size = TRUE ) diff --git a/R/geom-segment.r b/R/geom-segment.r index 27adfdcd8c..ef511f35c2 100644 --- a/R/geom-segment.r +++ b/R/geom-segment.r @@ -105,9 +105,6 @@ GeomSegment <- ggproto("GeomSegment", Geom, required_aes = c("x", "y", "xend", "yend"), non_missing_aes = c("linetype", "linewidth", "shape"), default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, draw_panel = function(self, data, panel_params, coord, arrow = NULL, arrow.fill = NULL, lineend = "butt", linejoin = "round", na.rm = FALSE) { data <- remove_missing(data, na.rm = na.rm, @@ -145,5 +142,7 @@ GeomSegment <- ggproto("GeomSegment", Geom, lineend = lineend) }, - draw_key = draw_key_path + draw_key = draw_key_path, + + rename_size = TRUE ) diff --git a/R/geom-spoke.r b/R/geom-spoke.r index 1ac09ae676..80b3b96810 100644 --- a/R/geom-spoke.r +++ b/R/geom-spoke.r @@ -57,7 +57,6 @@ stat_spoke <- function(...) { #' @export GeomSpoke <- ggproto("GeomSpoke", GeomSegment, setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$radius <- data$radius %||% params$radius data$angle <- data$angle %||% params$angle diff --git a/R/geom-tile.r b/R/geom-tile.r index ec7b1e05db..15d6aba054 100644 --- a/R/geom-tile.r +++ b/R/geom-tile.r @@ -100,7 +100,6 @@ GeomTile <- ggproto("GeomTile", GeomRect, extra_params = c("na.rm"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$width <- data$width %||% params$width %||% resolution(data$x, FALSE) data$height <- data$height %||% params$height %||% resolution(data$y, FALSE) diff --git a/R/geom-violin.r b/R/geom-violin.r index bbe2a2a6bd..20d20f7c81 100644 --- a/R/geom-violin.r +++ b/R/geom-violin.r @@ -123,7 +123,6 @@ GeomViolin <- ggproto("GeomViolin", Geom, extra_params = c("na.rm", "orientation", "lineend", "linejoin", "linemitre"), setup_data = function(data, params) { - data <- rename_size_aesthetic(data) data$flipped_aes <- params$flipped_aes data <- flip_data(data, params$flipped_aes) data$width <- data$width %||% @@ -192,7 +191,9 @@ GeomViolin <- ggproto("GeomViolin", Geom, default_aes = aes(weight = 1, colour = "grey20", fill = "white", linewidth = 0.5, alpha = NA, linetype = "solid"), - required_aes = c("x", "y") + required_aes = c("x", "y"), + + rename_size = TRUE ) # Returns a data.frame with info needed to draw quantile segments. diff --git a/R/geom-vline.r b/R/geom-vline.r index db6c362ea7..d81f089ad7 100644 --- a/R/geom-vline.r +++ b/R/geom-vline.r @@ -54,12 +54,11 @@ GeomVline <- ggproto("GeomVline", Geom, GeomSegment$draw_panel(unique(data), panel_params, coord, lineend = lineend) }, - setup_data = function(data, params) { - rename_size_aesthetic(data) - }, default_aes = aes(colour = "black", linewidth = 0.5, linetype = 1, alpha = NA), required_aes = "xintercept", - draw_key = draw_key_vline + draw_key = draw_key_vline, + + rename_size = TRUE ) diff --git a/R/guides-.r b/R/guides-.r index 87e5fe6456..f752e033a3 100644 --- a/R/guides-.r +++ b/R/guides-.r @@ -384,6 +384,9 @@ guide_gengrob <- function(guide, theme) UseMethod("guide_gengrob") matched_aes <- function(layer, guide) { all <- names(c(layer$computed_mapping, layer$stat$default_aes)) geom <- c(layer$geom$required_aes, names(layer$geom$default_aes)) + + # Make sure that size guides are shown if a renaming layer is used + if (layer$geom$rename_size && "size" %in% all && !"linewidth" %in% all) geom <- c(geom, "size") matched <- intersect(intersect(all, geom), names(guide$key)) matched <- setdiff(matched, names(layer$computed_geom_params)) setdiff(matched, names(layer$aes_params)) diff --git a/R/layer.r b/R/layer.r index 5cdf9d241c..ad96acfd61 100644 --- a/R/layer.r +++ b/R/layer.r @@ -125,6 +125,12 @@ layer <- function(geom = NULL, stat = NULL, # Warn about extra params and aesthetics extra_param <- setdiff(names(params), all) + # Take care of size->linewidth renaming in layer params + if (geom$rename_size && "size" %in% extra_param && !"linewidth" %in% mapped_aesthetics(mapping)) { + aes_params <- c(aes_params, params["size"]) + extra_param <- setdiff(extra_param, "size") + cli::cli_inform("Using {.arg size} as {.arg linewidth}") + } if (check.param && length(extra_param) > 0) { cli::cli_warn("Ignoring unknown parameters: {.arg {extra_param}}", call = call_env) } @@ -133,6 +139,11 @@ layer <- function(geom = NULL, stat = NULL, mapped_aesthetics(mapping), c(geom$aesthetics(), stat$aesthetics()) ) + # Take care of size->linewidth aes renaming + if (geom$rename_size && "size" %in% extra_aes && !"linewidth" %in% mapped_aesthetics(mapping)) { + extra_aes <- setdiff(extra_aes, "size") + cli::cli_inform("Using {.field size} as {.field linewidth}") + } if (check.aes && length(extra_aes) > 0) { cli::cli_warn("Ignoring unknown aesthetics: {.field {extra_aes}}", call = call_env) } @@ -217,6 +228,15 @@ Layer <- ggproto("Layer", NULL, # For annotation geoms, it is useful to be able to ignore the default aes if (isTRUE(self$inherit.aes)) { self$computed_mapping <- defaults(self$mapping, plot$mapping) + + # Inherit size as linewidth from global mapping + if (self$geom$rename_size && + "size" %in% names(plot$mapping) && + !"linewidth" %in% names(self$computed_mapping) && + "linewidth" %in% self$geom$aesthetics()) { + self$computed_mapping$size <- plot$mapping$size + cli::cli_inform("Inheriting {.field size} as {.field linewidth}") + } # defaults() strips class, but it needs to be preserved for now class(self$computed_mapping) <- "uneval" } else { diff --git a/R/scale-linewidth.R b/R/scale-linewidth.R index 535b4aeba6..0c726e7016 100644 --- a/R/scale-linewidth.R +++ b/R/scale-linewidth.R @@ -83,10 +83,3 @@ scale_linewidth_datetime <- function(..., range = c(1, 6)) { scale_linewidth_date <- function(..., range = c(1, 6)) { datetime_scale("linewidth", "date", palette = rescale_pal(range), ...) } - -rename_size_aesthetic <- function(data) { - if (is.null(data$linewidth)) { - data$linewidth <- data$size - } - data -} From 66ccd3c67fb44e72a20a9b8ebb792c4001d55b72 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Fri, 10 Jun 2022 14:25:09 +0200 Subject: [PATCH 08/11] remove dev version for Roxygen --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 16ecbb2405..fb540ccca0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -80,7 +80,7 @@ Config/testthat/edition: 3 Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.0.9000 +RoxygenNote: 7.2.0 Collate: 'ggproto.r' 'ggplot-global.R' From 0d51d9e66889eb1d187e118ea6e8ab7eed7fdd5c Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Fri, 10 Jun 2022 14:25:28 +0200 Subject: [PATCH 09/11] Add note about the change to the scale_size doc --- R/scale-size.r | 9 ++++++++- man/scale_size.Rd | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/R/scale-size.r b/R/scale-size.r index 84a0ff88cf..b56f01d555 100644 --- a/R/scale-size.r +++ b/R/scale-size.r @@ -8,13 +8,20 @@ #' scales by area (but does not ensure 0 equals an area of zero). For a binned #' equivalent of `scale_size_area()` use `scale_size_binned_area()`. #' +#' @note Historically the size aesthetic was used for two different things: +#' Scaling the size of object (like points and glyphs) and scaling the width +#' of lines. From ggplot2 3.4.0 the latter has been moved to its own linewidth +#' aesthetic. For backwards compatibility using size is still possible, but it +#' is highly advised to switch to the new linewidth aesthetic for these cases. +#' #' @name scale_size #' @inheritParams continuous_scale #' @inheritParams binned_scale #' @param range a numeric vector of length 2 that specifies the minimum and #' maximum size of the plotting symbol after transformation. #' @seealso [scale_size_area()] if you want 0 values to be mapped -#' to points with size 0. +#' to points with size 0. [scale_linewidth()] if you want to scale the width +#' of lines. #' @examples #' p <- ggplot(mpg, aes(displ, hwy, size = hwy)) + #' geom_point() diff --git a/man/scale_size.Rd b/man/scale_size.Rd index 83ce8692e8..00a03998ce 100644 --- a/man/scale_size.Rd +++ b/man/scale_size.Rd @@ -165,6 +165,13 @@ to a size of 0. \code{scale_size_binned()} is a binned version of \code{scale_si scales by area (but does not ensure 0 equals an area of zero). For a binned equivalent of \code{scale_size_area()} use \code{scale_size_binned_area()}. } +\note{ +Historically the size aesthetic was used for two different things: +Scaling the size of object (like points and glyphs) and scaling the width +of lines. From ggplot2 3.4.0 the latter has been moved to its own linewidth +aesthetic. For backwards compatibility using size is still possible, but it +is highly advised to switch to the new linewidth aesthetic for these cases. +} \examples{ p <- ggplot(mpg, aes(displ, hwy, size = hwy)) + geom_point() @@ -188,5 +195,6 @@ p + scale_radius() } \seealso{ \code{\link[=scale_size_area]{scale_size_area()}} if you want 0 values to be mapped -to points with size 0. +to points with size 0. \code{\link[=scale_linewidth]{scale_linewidth()}} if you want to scale the width +of lines. } From 9f4ead64b669562aa1dfe3cd9331ffb17d217e49 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Mon, 13 Jun 2022 10:25:21 +0200 Subject: [PATCH 10/11] improve messaging --- R/layer.r | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/R/layer.r b/R/layer.r index ad96acfd61..7ea5ab669a 100644 --- a/R/layer.r +++ b/R/layer.r @@ -129,7 +129,11 @@ layer <- function(geom = NULL, stat = NULL, if (geom$rename_size && "size" %in% extra_param && !"linewidth" %in% mapped_aesthetics(mapping)) { aes_params <- c(aes_params, params["size"]) extra_param <- setdiff(extra_param, "size") - cli::cli_inform("Using {.arg size} as {.arg linewidth}") + # TODO: move to cli_warn() + cli::cli_inform(c( + "{.field size} aesthetic has been deprecated for use with lines as of ggplot2 3.4.0", + "i" = "Please use {.field linewidth} aesthetic instead" + ), .frequency = "regularly", .frequency_id = "ggplot-size-linewidth") } if (check.param && length(extra_param) > 0) { cli::cli_warn("Ignoring unknown parameters: {.arg {extra_param}}", call = call_env) @@ -142,7 +146,11 @@ layer <- function(geom = NULL, stat = NULL, # Take care of size->linewidth aes renaming if (geom$rename_size && "size" %in% extra_aes && !"linewidth" %in% mapped_aesthetics(mapping)) { extra_aes <- setdiff(extra_aes, "size") - cli::cli_inform("Using {.field size} as {.field linewidth}") + # TODO: move to cli_warn() + cli::cli_inform(c( + "{.field size} aesthetic has been deprecated for use with lines as of ggplot2 3.4.0", + "i" = "Please use {.field linewidth} aesthetic instead" + ), .frequency = "regularly", .frequency_id = "ggplot-size-linewidth") } if (check.aes && length(extra_aes) > 0) { cli::cli_warn("Ignoring unknown aesthetics: {.field {extra_aes}}", call = call_env) @@ -235,7 +243,11 @@ Layer <- ggproto("Layer", NULL, !"linewidth" %in% names(self$computed_mapping) && "linewidth" %in% self$geom$aesthetics()) { self$computed_mapping$size <- plot$mapping$size - cli::cli_inform("Inheriting {.field size} as {.field linewidth}") + # TODO: move to cli_warn() + cli::cli_inform(c( + "{.field size} aesthetic has been deprecated for use with lines as of ggplot2 3.4.0", + "i" = "Please use {.field linewidth} aesthetic instead" + ), .frequency = "regularly", .frequency_id = "ggplot-size-linewidth") } # defaults() strips class, but it needs to be preserved for now class(self$computed_mapping) <- "uneval" From 526482f5edb747218c64f4dd296db7444f68c287 Mon Sep 17 00:00:00 2001 From: Thomas Lin Pedersen Date: Wed, 15 Jun 2022 10:18:40 +0200 Subject: [PATCH 11/11] add news bullet --- NEWS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS.md b/NEWS.md index 41949e533b..6d8576201d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,10 @@ # ggplot2 (development version) +* A `linewidth` aesthetic has been introduced and supersedes the `size` + aesthetic for scaling the width of lines in line based geoms. `size` will + remain functioning but deprecated for these geoms and it is recommended to + update all code to reflect the new aesthetic (@thomasp85, #3672) + * Secondary axis ticks are now positioned more precisely, removing small visual artefacts with alignment between grid and ticks (@thomasp85, #3576)