diff --git a/NEWS.md b/NEWS.md index 47e99f6589..0f242a2612 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,6 +31,8 @@ cannot be transformed (@teunbrand, #3171). * `stat_density()` has the new computed variable: `wdensity`, which is calculated as the density times the sum of weights (@teunbrand, #4176). +* `theme()` gets new `spacing` and `margins` arguments that all other spacings + and (non-text) margins inherit from (@teunbrand, #5622). # ggplot2 3.5.1 diff --git a/R/facet-grid-.R b/R/facet-grid-.R index 54c4b8f971..0854b5299b 100644 --- a/R/facet-grid-.R +++ b/R/facet-grid-.R @@ -412,10 +412,10 @@ FacetGrid <- ggproto("FacetGrid", Facet, panel_widths, panel_heights, respect = respect, clip = coord$clip, z = mtx(1)) panel_table$layout$name <- paste0('panel-', rep(seq_len(nrow), ncol), '-', rep(seq_len(ncol), each = nrow)) - panel_table <- gtable_add_col_space(panel_table, - theme$panel.spacing.x %||% theme$panel.spacing) - panel_table <- gtable_add_row_space(panel_table, - theme$panel.spacing.y %||% theme$panel.spacing) + spacing_x <- calc_element("panel.spacing.x", theme) + spacing_y <- calc_element("panel.spacing.y", theme) + panel_table <- gtable_add_col_space(panel_table, spacing_x) + panel_table <- gtable_add_row_space(panel_table, spacing_y) # Add axes if (params$draw_axes$x) { @@ -445,7 +445,7 @@ FacetGrid <- ggproto("FacetGrid", Facet, switch_y <- !is.null(params$switch) && params$switch %in% c("both", "y") inside_x <- (theme$strip.placement.x %||% theme$strip.placement %||% "inside") == "inside" inside_y <- (theme$strip.placement.y %||% theme$strip.placement %||% "inside") == "inside" - strip_padding <- convertUnit(theme$strip.switch.pad.grid, "cm") + strip_padding <- convertUnit(calc_element("strip.switch.pad.grid", theme), "cm") panel_pos_col <- panel_cols(panel_table) if (switch_x) { if (!is.null(strips$x$bottom)) { diff --git a/R/facet-wrap.R b/R/facet-wrap.R index f69cdd8f95..720e2e8e37 100644 --- a/R/facet-wrap.R +++ b/R/facet-wrap.R @@ -325,10 +325,9 @@ FacetWrap <- ggproto("FacetWrap", Facet, heights = unit(rep(abs(aspect_ratio), nrow), "null"), respect = respect, clip = coord$clip, z = matrix(1, ncol = ncol, nrow = nrow)) panel_table$layout$name <- paste0('panel-', rep(seq_len(ncol), nrow), '-', rep(seq_len(nrow), each = ncol)) - panel_table <- gtable_add_col_space(panel_table, - theme$panel.spacing.x %||% theme$panel.spacing) - panel_table <- gtable_add_row_space(panel_table, - theme$panel.spacing.y %||% theme$panel.spacing) + + panel_table <- gtable_add_col_space(panel_table, calc_element("panel.spacing.x", theme)) + panel_table <- gtable_add_row_space(panel_table, calc_element("panel.spacing.y", theme)) # Add axes axis_mat_x_top <- empty_table @@ -442,7 +441,7 @@ FacetWrap <- ggproto("FacetWrap", Facet, axis_size <- panel_table$sizes panel_table <- panel_table$panels - strip_padding <- convertUnit(theme$strip.switch.pad.wrap, "cm") + strip_padding <- convertUnit(calc_element("strip.switch.pad.wrap", theme), "cm") strip_name <- paste0("strip-", substr(params$strip.position, 1, 1)) strip_mat <- empty_table strip_mat[panel_pos] <- unlist(unname(strips), recursive = FALSE)[[params$strip.position]] diff --git a/R/guide-legend.R b/R/guide-legend.R index c685cdd8c7..157018dc48 100644 --- a/R/guide-legend.R +++ b/R/guide-legend.R @@ -313,8 +313,8 @@ GuideLegend <- ggproto( arg_match0(title_position, .trbl, arg_nm = "legend.title.position") # Set default spacing - theme$legend.key.spacing <- theme$legend.key.spacing %||% unit(5.5, "pt") - gap <- calc_element("legend.key.spacing", theme) + theme$legend.key.spacing <- calc_element("legend.key.spacing", theme) + gap <- theme$legend.key.spacing # For backward compatibility, default vertical spacing is no spacing if (params$direction == "vertical") { diff --git a/R/guides-.R b/R/guides-.R index 2280c40def..8a0117dc75 100644 --- a/R/guides-.R +++ b/R/guides-.R @@ -608,7 +608,7 @@ Guides <- ggproto( box_xjust <- box_just[1] box_yjust <- box_just[2] - margin <- theme$legend.box.margin %||% margin() + margin <- calc_element("legend.box.margin", theme) %||% margin() # setting that is different for vertical and horizontal guide-boxes. if (identical(theme$legend.box, "horizontal")) { diff --git a/R/plot-build.R b/R/plot-build.R index d53f16ba85..55c419d1e9 100644 --- a/R/plot-build.R +++ b/R/plot-build.R @@ -261,10 +261,8 @@ ggplot_gtable.ggplot_built <- function(data) { plot_table <- table_add_tag(plot_table, plot$labels$tag, theme) # Margins - plot_table <- gtable_add_rows(plot_table, theme$plot.margin[1], pos = 0) - plot_table <- gtable_add_cols(plot_table, theme$plot.margin[2]) - plot_table <- gtable_add_rows(plot_table, theme$plot.margin[3]) - plot_table <- gtable_add_cols(plot_table, theme$plot.margin[4], pos = 0) + plot_margin <- calc_element("plot.margin", theme) + plot_table <- gtable_add_padding(plot_table, plot_margin) if (inherits(theme$plot.background, "element")) { plot_table <- gtable_add_grob(plot_table, @@ -443,7 +441,7 @@ table_add_legends <- function(table, legends, theme) { empty <- vapply(legends, is.zero, logical(1)) widths[!empty] <- lapply(legends[!empty], gtable_width) heights[!empty] <- lapply(legends[!empty], gtable_height) - spacing <- theme$legend.box.spacing %||% unit(0.2, "cm") + spacing <- calc_element("legend.box.spacing", theme) %||% unit(0.2, "cm") # If legend is missing, set spacing to zero for that legend zero <- unit(0, "pt") diff --git a/R/theme-defaults.R b/R/theme-defaults.R index 05260557e9..2066679533 100644 --- a/R/theme-defaults.R +++ b/R/theme-defaults.R @@ -133,6 +133,8 @@ theme_grey <- function(base_size = 11, base_family = "", lineheight = 0.9, hjust = 0.5, vjust = 0.5, angle = 0, margin = margin(), debug = FALSE ), + spacing = unit(half_line, "pt"), + margins = margin(half_line, half_line, half_line, half_line), axis.line = element_blank(), axis.line.x = NULL, @@ -145,7 +147,7 @@ theme_grey <- function(base_size = 11, base_family = "", axis.text.r = element_text(margin = margin(l = 0.8 * half_line / 2, r = 0.8 * half_line / 2), hjust = 0.5), axis.ticks = element_line(colour = "grey20"), - axis.ticks.length = unit(half_line / 2, "pt"), + axis.ticks.length = rel(0.5), axis.ticks.length.x = NULL, axis.ticks.length.x.top = NULL, axis.ticks.length.x.bottom = NULL, @@ -173,15 +175,15 @@ theme_grey <- function(base_size = 11, base_family = "", ), legend.background = element_rect(colour = NA), - legend.spacing = unit(2 * half_line, "pt"), + legend.spacing = rel(2), legend.spacing.x = NULL, legend.spacing.y = NULL, - legend.margin = margin(half_line, half_line, half_line, half_line), + legend.margin = NULL, legend.key = NULL, legend.key.size = unit(1.2, "lines"), legend.key.height = NULL, legend.key.width = NULL, - legend.key.spacing = unit(half_line, "pt"), + legend.key.spacing = NULL, legend.text = element_text(size = rel(0.8)), legend.title = element_text(hjust = 0), legend.ticks.length = rel(0.2), @@ -189,15 +191,15 @@ theme_grey <- function(base_size = 11, base_family = "", legend.direction = NULL, legend.justification = "center", legend.box = NULL, - legend.box.margin = margin(0, 0, 0, 0, "cm"), + legend.box.margin = rel(0), legend.box.background = element_blank(), - legend.box.spacing = unit(2 * half_line, "pt"), + legend.box.spacing = rel(2), panel.background = element_rect(fill = "grey92", colour = NA), panel.border = element_blank(), panel.grid = element_line(colour = "white"), panel.grid.minor = element_line(linewidth = rel(0.5)), - panel.spacing = unit(half_line, "pt"), + panel.spacing = NULL, panel.spacing.x = NULL, panel.spacing.y = NULL, panel.ontop = FALSE, @@ -240,7 +242,7 @@ theme_grey <- function(base_size = 11, base_family = "", hjust = 0.5, vjust = 0.5 ), plot.tag.position = 'topleft', - plot.margin = margin(half_line, half_line, half_line, half_line), + plot.margin = NULL, complete = TRUE ) @@ -466,30 +468,35 @@ theme_void <- function(base_size = 11, base_family = "", lineheight = 0.9, hjust = 0.5, vjust = 0.5, angle = 0, margin = margin(), debug = FALSE ), + spacing = unit(half_line, "pt"), + margins = margin(half_line, half_line, half_line, half_line), axis.text = element_blank(), axis.title = element_blank(), - axis.ticks.length = unit(0, "pt"), + axis.ticks.length = rel(0), axis.ticks.length.x = NULL, axis.ticks.length.x.top = NULL, axis.ticks.length.x.bottom = NULL, axis.ticks.length.y = NULL, axis.ticks.length.y.left = NULL, axis.ticks.length.y.right = NULL, - axis.minor.ticks.length = unit(0, "pt"), + axis.minor.ticks.length = NULL, legend.box = NULL, legend.key.size = unit(1.2, "lines"), legend.position = "right", legend.text = element_text(size = rel(0.8)), legend.title = element_text(hjust = 0), - legend.key.spacing = unit(half_line, "pt"), + legend.key.spacing = rel(1), + legend.margin = rel(0), + legend.box.margin = rel(0), + legend.box.spacing = unit(0.2, "cm"), legend.ticks.length = rel(0.2), strip.clip = "inherit", strip.text = element_text(size = rel(0.8)), - strip.switch.pad.grid = unit(half_line / 2, "pt"), - strip.switch.pad.wrap = unit(half_line / 2, "pt"), + strip.switch.pad.grid = rel(0.5), + strip.switch.pad.wrap = rel(0.5), panel.ontop = FALSE, - panel.spacing = unit(half_line, "pt"), - plot.margin = unit(c(0, 0, 0, 0), "lines"), + panel.spacing = NULL, + plot.margin = rel(0), plot.title = element_text( size = rel(1.2), hjust = 0, vjust = 1, @@ -542,6 +549,8 @@ theme_test <- function(base_size = 11, base_family = "", lineheight = 0.9, hjust = 0.5, vjust = 0.5, angle = 0, margin = margin(), debug = FALSE ), + spacing = unit(half_line, "pt"), + margins = margin(half_line, half_line, half_line, half_line), axis.line = element_blank(), axis.line.x = NULL, @@ -552,7 +561,7 @@ theme_test <- function(base_size = 11, base_family = "", axis.text.y = element_text(margin = margin(r = 0.8 * half_line / 2), hjust = 1), axis.text.y.right = element_text(margin = margin(l = 0.8 * half_line / 2), hjust = 0), axis.ticks = element_line(colour = "grey20"), - axis.ticks.length = unit(half_line / 2, "pt"), + axis.ticks.length = rel(0.5), axis.ticks.length.x = NULL, axis.ticks.length.x.top = NULL, axis.ticks.length.x.bottom = NULL, @@ -580,7 +589,7 @@ theme_test <- function(base_size = 11, base_family = "", ), legend.background = element_rect(colour = NA), - legend.spacing = unit(2 * half_line, "pt"), + legend.spacing = rel(2), legend.spacing.x = NULL, legend.spacing.y = NULL, legend.margin = margin(0, 0, 0, 0, "cm"), @@ -588,7 +597,7 @@ theme_test <- function(base_size = 11, base_family = "", legend.key.size = unit(1.2, "lines"), legend.key.height = NULL, legend.key.width = NULL, - legend.key.spacing = unit(half_line, "pt"), + legend.key.spacing = NULL, legend.key.spacing.x = NULL, legend.key.spacing.y = NULL, legend.text = element_text(size = rel(0.8)), @@ -600,13 +609,13 @@ theme_test <- function(base_size = 11, base_family = "", legend.box = NULL, legend.box.margin = margin(0, 0, 0, 0, "cm"), legend.box.background = element_blank(), - legend.box.spacing = unit(2 * half_line, "pt"), + legend.box.spacing = rel(2), panel.background = element_rect(fill = "white", colour = NA), panel.border = element_rect(fill = NA, colour = "grey20"), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), - panel.spacing = unit(half_line, "pt"), + panel.spacing = NULL, panel.spacing.x = NULL, panel.spacing.y = NULL, panel.ontop = FALSE, @@ -624,8 +633,8 @@ theme_test <- function(base_size = 11, base_family = "", strip.placement = "inside", strip.placement.x = NULL, strip.placement.y = NULL, - strip.switch.pad.grid = unit(half_line / 2, "pt"), - strip.switch.pad.wrap = unit(half_line / 2, "pt"), + strip.switch.pad.grid = rel(0.5), + strip.switch.pad.wrap = rel(0.5), plot.background = element_rect(colour = "white"), plot.title = element_text( @@ -649,7 +658,7 @@ theme_test <- function(base_size = 11, base_family = "", hjust = 0.5, vjust = 0.5 ), plot.tag.position = 'topleft', - plot.margin = margin(half_line, half_line, half_line, half_line), + plot.margin = NULL, complete = TRUE ) diff --git a/R/theme-elements.R b/R/theme-elements.R index 41b989df7e..23bf79bd6e 100644 --- a/R/theme-elements.R +++ b/R/theme-elements.R @@ -419,11 +419,14 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) { rect = el_def("element_rect"), text = el_def("element_text"), title = el_def("element_text", "text"), + spacing = el_def("unit"), + margins = el_def("margin"), + axis.line = el_def("element_line", "line"), axis.text = el_def("element_text", "text"), axis.title = el_def("element_text", "title"), axis.ticks = el_def("element_line", "line"), - legend.key.size = el_def("unit"), + legend.key.size = el_def(c("unit", "rel"), "spacing"), panel.grid = el_def("element_line", "line"), panel.grid.major = el_def("element_line", "panel.grid"), panel.grid.minor = el_def("element_line", "panel.grid"), @@ -447,7 +450,7 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) { axis.text.theta = el_def("element_text", "axis.text.x"), axis.text.r = el_def("element_text", "axis.text.y"), - axis.ticks.length = el_def("unit"), + axis.ticks.length = el_def(c("unit", "rel"), "spacing"), axis.ticks.length.x = el_def(c("unit", "rel"), "axis.ticks.length"), axis.ticks.length.x.top = el_def(c("unit", "rel"), "axis.ticks.length.x"), axis.ticks.length.x.bottom = el_def(c("unit", "rel"), "axis.ticks.length.x"), @@ -503,14 +506,14 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) { ), legend.background = el_def("element_rect", "rect"), - legend.margin = el_def("margin"), - legend.spacing = el_def("unit"), + legend.margin = el_def(c("margin", "rel"), "margins"), + legend.spacing = el_def(c("unit", "rel"), "spacing"), legend.spacing.x = el_def(c("unit", "rel"), "legend.spacing"), legend.spacing.y = el_def(c("unit", "rel"), "legend.spacing"), legend.key = el_def("element_rect", "panel.background"), legend.key.height = el_def(c("unit", "rel"), "legend.key.size"), legend.key.width = el_def(c("unit", "rel"), "legend.key.size"), - legend.key.spacing = el_def("unit"), + legend.key.spacing = el_def(c("unit", "rel"), "spacing"), legend.key.spacing.x = el_def(c("unit", "rel"), "legend.key.spacing"), legend.key.spacing.y = el_def(c("unit", "rel"), "legend.key.spacing"), legend.frame = el_def("element_rect", "rect"), @@ -552,13 +555,13 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) { legend.box = el_def("character"), legend.box.just = el_def("character"), - legend.box.margin = el_def("margin"), + legend.box.margin = el_def(c("margin", "rel"), "margins"), legend.box.background = el_def("element_rect", "rect"), - legend.box.spacing = el_def("unit"), + legend.box.spacing = el_def(c("unit", "rel"), "spacing"), panel.background = el_def("element_rect", "rect"), panel.border = el_def("element_rect", "rect"), - panel.spacing = el_def("unit"), + panel.spacing = el_def(c("unit", "rel"), "spacing"), panel.spacing.x = el_def(c("unit", "rel"), "panel.spacing"), panel.spacing.y = el_def(c("unit", "rel"), "panel.spacing"), panel.grid.major.x = el_def("element_line", "panel.grid.major"), @@ -580,8 +583,8 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) { strip.placement = el_def("character"), strip.placement.x = el_def("character", "strip.placement"), strip.placement.y = el_def("character", "strip.placement"), - strip.switch.pad.grid = el_def("unit"), - strip.switch.pad.wrap = el_def("unit"), + strip.switch.pad.grid = el_def(c("unit", "rel"), "spacing"), + strip.switch.pad.wrap = el_def(c("unit", "rel"), "spacing"), plot.background = el_def("element_rect", "rect"), plot.title = el_def("element_text", "title"), @@ -592,7 +595,7 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) { plot.tag = el_def("element_text", "title"), plot.tag.position = el_def(c("character", "numeric", "integer")), # Need to also accept numbers plot.tag.location = el_def("character"), - plot.margin = el_def("margin"), + plot.margin = el_def(c("margin", "rel"), "margins"), aspect.ratio = el_def(c("numeric", "integer")) ) diff --git a/R/theme.R b/R/theme.R index 3611af323e..f03d2a67ef 100644 --- a/R/theme.R +++ b/R/theme.R @@ -25,6 +25,8 @@ #' @param text all text elements ([element_text()]) #' @param title all title elements: plot, axes, legends ([element_text()]; #' inherits from `text`) +#' @param spacing all spacings ([`unit()`][grid::unit]) +#' @param margins all margins ([margin()]) #' @param aspect.ratio aspect ratio of the panel #' #' @param axis.title,axis.title.x,axis.title.y,axis.title.x.top,axis.title.x.bottom,axis.title.y.left,axis.title.y.right @@ -52,7 +54,7 @@ #' minor tick marks along axes ([element_line()]). `axis.minor.ticks.*.*` #' inherit from the corresponding major ticks `axis.ticks.*.*`. #' @param axis.ticks.length,axis.ticks.length.x,axis.ticks.length.x.top,axis.ticks.length.x.bottom,axis.ticks.length.y,axis.ticks.length.y.left,axis.ticks.length.y.right,axis.ticks.length.theta,axis.ticks.length.r -#' length of tick marks (`unit`) +#' length of tick marks (`unit`). `axis.ticks.length` inherits from `spacing`. #' @param axis.minor.ticks.length,axis.minor.ticks.length.x,axis.minor.ticks.length.x.top,axis.minor.ticks.length.x.bottom,axis.minor.ticks.length.y,axis.minor.ticks.length.y.left,axis.minor.ticks.length.y.right,axis.minor.ticks.length.theta,axis.minor.ticks.length.r #' length of minor tick marks (`unit`), or relative to `axis.ticks.length` when provided with `rel()`. #' @param axis.line,axis.line.x,axis.line.x.top,axis.line.x.bottom,axis.line.y,axis.line.y.left,axis.line.y.right,axis.line.theta,axis.line.r @@ -65,22 +67,26 @@ #' #' @param legend.background background of legend ([element_rect()]; inherits #' from `rect`) -#' @param legend.margin the margin around each legend ([margin()]) +#' @param legend.margin the margin around each legend ([margin()]); inherits +#' from `margins`. #' @param legend.spacing,legend.spacing.x,legend.spacing.y #' the spacing between legends (`unit`). `legend.spacing.x` & `legend.spacing.y` -#' inherit from `legend.spacing` or can be specified separately +#' inherit from `legend.spacing` or can be specified separately. +#' `legend.spacing` inherits from `spacing`. #' @param legend.key background underneath legend keys ([element_rect()]; #' inherits from `rect`) #' @param legend.key.size,legend.key.height,legend.key.width #' size of legend keys (`unit`); key background height & width inherit from -#' `legend.key.size` or can be specified separately +#' `legend.key.size` or can be specified separately. In turn `legend.key.size` +#' inherits from `spacing`. #' @param legend.key.spacing,legend.key.spacing.x,legend.key.spacing.y spacing #' between legend keys given as a `unit`. Spacing in the horizontal (x) and #' vertical (y) direction inherit from `legend.key.spacing` or can be -#' specified separately. +#' specified separately. `legend.key.spacing` inherits from `spacing`. #' @param legend.frame frame drawn around the bar ([element_rect()]). #' @param legend.ticks tick marks shown along bars or axes ([element_line()]) -#' @param legend.ticks.length length of tick marks in legend (`unit`) +#' @param legend.ticks.length length of tick marks in legend +#' ([`unit()`][grid::unit]); inherits from `legend.key.size`. #' @param legend.axis.line lines along axes in legends ([element_line()]) #' @param legend.text legend item labels ([element_text()]; inherits from #' `text`) @@ -113,11 +119,11 @@ #' bounding box, when there are multiple legends ("top", "bottom", "left", or #' "right") #' @param legend.box.margin margins around the full legend area, as specified -#' using [margin()] +#' using [margin()]; inherits from `margins`. #' @param legend.box.background background of legend area ([element_rect()]; #' inherits from `rect`) #' @param legend.box.spacing The spacing between the plotting area and the -#' legend box (`unit`) +#' legend box (`unit`); inherits from `spacing`. #' #' @param panel.background background of plotting area, drawn underneath plot #' ([element_rect()]; inherits from `rect`) @@ -127,7 +133,7 @@ #' ([element_rect()]; inherits from `rect`) #' @param panel.spacing,panel.spacing.x,panel.spacing.y spacing between facet #' panels (`unit`). `panel.spacing.x` & `panel.spacing.y` inherit from `panel.spacing` -#' or can be specified separately. +#' or can be specified separately. `panel.spacing` inherits from `spacing`. #' @param panel.grid,panel.grid.major,panel.grid.minor,panel.grid.major.x,panel.grid.major.y,panel.grid.minor.x,panel.grid.minor.y #' grid lines ([element_line()]). Specify major grid lines, #' or minor grid lines separately (using `panel.grid.major` or `panel.grid.minor`) @@ -166,7 +172,7 @@ #' set the x,y-coordinate relative to the whole plot. The coordinate option #' is unavailable for `plot.tag.location = "margin"`. #' @param plot.margin margin around entire plot (`unit` with the sizes of -#' the top, right, bottom, and left margins) +#' the top, right, bottom, and left margins); inherits from `margin`. #' #' @param strip.background,strip.background.x,strip.background.y #' background of facet labels ([element_rect()]; @@ -188,10 +194,8 @@ #' that inherit from `strip.text.x` and `strip.text.y`, respectively. #' As a consequence, some theme stylings need to be applied to #' the position-dependent elements rather than to the parent elements -#' @param strip.switch.pad.grid space between strips and axes when strips are -#' switched (`unit`) -#' @param strip.switch.pad.wrap space between strips and axes when strips are -#' switched (`unit`) +#' @param strip.switch.pad.grid,strip.switch.pad.wrap space between strips and +#' axes when strips are switched (`unit`); inherits from `spacing`. #' #' @param ... additional element specifications not part of base ggplot2. In general, #' these should also be defined in the `element tree` argument. [Splicing][rlang::splice] a list is also supported. @@ -311,6 +315,8 @@ theme <- function(..., rect, text, title, + spacing, + margins, aspect.ratio, axis.title, axis.title.x, diff --git a/man/geom_density.Rd b/man/geom_density.Rd index 26f2554e1c..86bf57d6e9 100644 --- a/man/geom_density.Rd +++ b/man/geom_density.Rd @@ -188,7 +188,7 @@ These are calculated by the 'stat' part of layers and can be accessed with \link \itemize{ \item \code{after_stat(density)}\cr density estimate. \item \code{after_stat(count)}\cr density * number of points - useful for stacked density plots. -\item \code{after_stat(wdensity)}\cr density * sum of weights. In absence of weights, the same as \code{count} +\item \code{after_stat(wdensity)}\cr density * sum of weights. In absence of weights, the same as \code{count}. \item \code{after_stat(scaled)}\cr density estimate, scaled to maximum of 1. \item \code{after_stat(n)}\cr number of points. \item \code{after_stat(ndensity)}\cr alias for \code{scaled}, to mirror the syntax of \code{\link[=stat_bin]{stat_bin()}}. diff --git a/man/theme.Rd b/man/theme.Rd index 5d51fd8643..13a88a2e2a 100644 --- a/man/theme.Rd +++ b/man/theme.Rd @@ -10,6 +10,8 @@ theme( rect, text, title, + spacing, + margins, aspect.ratio, axis.title, axis.title.x, @@ -159,6 +161,10 @@ these should also be defined in the \verb{element tree} argument. \link[rlang:sp \item{title}{all title elements: plot, axes, legends (\code{\link[=element_text]{element_text()}}; inherits from \code{text})} +\item{spacing}{all spacings (\code{\link[grid:unit]{unit()}})} + +\item{margins}{all margins (\code{\link[=margin]{margin()}})} + \item{aspect.ratio}{aspect ratio of the panel} \item{axis.title, axis.title.x, axis.title.y, axis.title.x.top, axis.title.x.bottom, axis.title.y.left, axis.title.y.right}{labels of axes (\code{\link[=element_text]{element_text()}}). Specify all axes' labels (\code{axis.title}), @@ -185,7 +191,7 @@ from \code{line}} \item{axis.minor.ticks.x.top, axis.minor.ticks.x.bottom, axis.minor.ticks.y.left, axis.minor.ticks.y.right, axis.minor.ticks.theta, axis.minor.ticks.r, }{minor tick marks along axes (\code{\link[=element_line]{element_line()}}). \verb{axis.minor.ticks.*.*} inherit from the corresponding major ticks \verb{axis.ticks.*.*}.} -\item{axis.ticks.length, axis.ticks.length.x, axis.ticks.length.x.top, axis.ticks.length.x.bottom, axis.ticks.length.y, axis.ticks.length.y.left, axis.ticks.length.y.right, axis.ticks.length.theta, axis.ticks.length.r}{length of tick marks (\code{unit})} +\item{axis.ticks.length, axis.ticks.length.x, axis.ticks.length.x.top, axis.ticks.length.x.bottom, axis.ticks.length.y, axis.ticks.length.y.left, axis.ticks.length.y.right, axis.ticks.length.theta, axis.ticks.length.r}{length of tick marks (\code{unit}). \code{axis.ticks.length} inherits from \code{spacing}.} \item{axis.minor.ticks.length, axis.minor.ticks.length.x, axis.minor.ticks.length.x.top, axis.minor.ticks.length.x.bottom, axis.minor.ticks.length.y, axis.minor.ticks.length.y.left, axis.minor.ticks.length.y.right, axis.minor.ticks.length.theta, axis.minor.ticks.length.r}{length of minor tick marks (\code{unit}), or relative to \code{axis.ticks.length} when provided with \code{rel()}.} @@ -199,27 +205,31 @@ from \code{line}} \item{legend.background}{background of legend (\code{\link[=element_rect]{element_rect()}}; inherits from \code{rect})} -\item{legend.margin}{the margin around each legend (\code{\link[=margin]{margin()}})} +\item{legend.margin}{the margin around each legend (\code{\link[=margin]{margin()}}); inherits +from \code{margins}.} \item{legend.spacing, legend.spacing.x, legend.spacing.y}{the spacing between legends (\code{unit}). \code{legend.spacing.x} & \code{legend.spacing.y} -inherit from \code{legend.spacing} or can be specified separately} +inherit from \code{legend.spacing} or can be specified separately. +\code{legend.spacing} inherits from \code{spacing}.} \item{legend.key}{background underneath legend keys (\code{\link[=element_rect]{element_rect()}}; inherits from \code{rect})} \item{legend.key.size, legend.key.height, legend.key.width}{size of legend keys (\code{unit}); key background height & width inherit from -\code{legend.key.size} or can be specified separately} +\code{legend.key.size} or can be specified separately. In turn \code{legend.key.size} +inherits from \code{spacing}.} \item{legend.key.spacing, legend.key.spacing.x, legend.key.spacing.y}{spacing between legend keys given as a \code{unit}. Spacing in the horizontal (x) and vertical (y) direction inherit from \code{legend.key.spacing} or can be -specified separately.} +specified separately. \code{legend.key.spacing} inherits from \code{spacing}.} \item{legend.frame}{frame drawn around the bar (\code{\link[=element_rect]{element_rect()}}).} \item{legend.ticks}{tick marks shown along bars or axes (\code{\link[=element_line]{element_line()}})} -\item{legend.ticks.length}{length of tick marks in legend (\code{unit})} +\item{legend.ticks.length}{length of tick marks in legend +(\code{\link[grid:unit]{unit()}}); inherits from \code{legend.key.size}.} \item{legend.axis.line}{lines along axes in legends (\code{\link[=element_line]{element_line()}})} @@ -266,13 +276,13 @@ bounding box, when there are multiple legends ("top", "bottom", "left", or "right")} \item{legend.box.margin}{margins around the full legend area, as specified -using \code{\link[=margin]{margin()}}} +using \code{\link[=margin]{margin()}}; inherits from \code{margins}.} \item{legend.box.background}{background of legend area (\code{\link[=element_rect]{element_rect()}}; inherits from \code{rect})} \item{legend.box.spacing}{The spacing between the plotting area and the -legend box (\code{unit})} +legend box (\code{unit}); inherits from \code{spacing}.} \item{panel.background}{background of plotting area, drawn underneath plot (\code{\link[=element_rect]{element_rect()}}; inherits from \code{rect})} @@ -284,7 +294,7 @@ it covers tick marks and grid lines. This should be used with \item{panel.spacing, panel.spacing.x, panel.spacing.y}{spacing between facet panels (\code{unit}). \code{panel.spacing.x} & \code{panel.spacing.y} inherit from \code{panel.spacing} -or can be specified separately.} +or can be specified separately. \code{panel.spacing} inherits from \code{spacing}.} \item{panel.grid, panel.grid.major, panel.grid.minor, panel.grid.major.x, panel.grid.major.y, panel.grid.minor.x, panel.grid.minor.y}{grid lines (\code{\link[=element_line]{element_line()}}). Specify major grid lines, or minor grid lines separately (using \code{panel.grid.major} or \code{panel.grid.minor}) @@ -332,7 +342,7 @@ inside the panel space, anywhere in the plot as a whole, or in the margin around the panel space.} \item{plot.margin}{margin around entire plot (\code{unit} with the sizes of -the top, right, bottom, and left margins)} +the top, right, bottom, and left margins); inherits from \code{margin}.} \item{strip.background, strip.background.x, strip.background.y}{background of facet labels (\code{\link[=element_rect]{element_rect()}}; inherits from \code{rect}). Horizontal facet background (\code{strip.background.x}) @@ -356,11 +366,8 @@ that inherit from \code{strip.text.x} and \code{strip.text.y}, respectively. As a consequence, some theme stylings need to be applied to the position-dependent elements rather than to the parent elements} -\item{strip.switch.pad.grid}{space between strips and axes when strips are -switched (\code{unit})} - -\item{strip.switch.pad.wrap}{space between strips and axes when strips are -switched (\code{unit})} +\item{strip.switch.pad.grid, strip.switch.pad.wrap}{space between strips and +axes when strips are switched (\code{unit}); inherits from \code{spacing}.} \item{complete}{set this to \code{TRUE} if this is a complete theme, such as the one returned by \code{\link[=theme_grey]{theme_grey()}}. Complete themes behave diff --git a/tests/testthat/_snaps/theme/large-margins.svg b/tests/testthat/_snaps/theme/large-margins.svg new file mode 100644 index 0000000000..1e4bfb10db --- /dev/null +++ b/tests/testthat/_snaps/theme/large-margins.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + +1.0 +1.5 +2.0 +2.5 +3.0 +1.0 +1.5 +2.0 +2.5 +3.0 + + + + + +x +y + +z + + + + +a +b +large margins + + diff --git a/tests/testthat/_snaps/theme/large-spacing.svg b/tests/testthat/_snaps/theme/large-spacing.svg new file mode 100644 index 0000000000..1680934c61 --- /dev/null +++ b/tests/testthat/_snaps/theme/large-spacing.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + +1.0 +1.5 +2.0 +2.5 +3.0 +1.0 +1.5 +2.0 +2.5 +3.0 + + + + + +x +y + +z + + + + +a +b +large spacing + + diff --git a/tests/testthat/test-theme.R b/tests/testthat/test-theme.R index 895d4cf9fc..1200a56d99 100644 --- a/tests/testthat/test-theme.R +++ b/tests/testthat/test-theme.R @@ -649,6 +649,19 @@ test_that("themes look decent at larger base sizes", { expect_doppelganger("theme_linedraw_large", plot + theme_linedraw(base_size = 33)) }) +test_that("setting 'spacing' and 'margins' affect the whole plot", { + + df <- data_frame(x = 1:3, y = 1:3, z = c("a", "b", "a"), a = 1) + plot <- ggplot(df, aes(x, y, colour = z)) + + geom_point() + + facet_wrap(~ a) + + theme_gray() + + expect_doppelganger("large spacing", plot + theme(spacing = unit(1, "cm"))) + expect_doppelganger("large margins", plot + theme(margins = margin(1, 1, 1, 1, "cm"))) + +}) + test_that("axes can be styled independently", { plot <- ggplot() + geom_point(aes(1:10, 1:10)) + diff --git a/vignettes/articles/faq-axes.Rmd b/vignettes/articles/faq-axes.Rmd index 6a9ed45521..f9868cdf8e 100644 --- a/vignettes/articles/faq-axes.Rmd +++ b/vignettes/articles/faq-axes.Rmd @@ -193,7 +193,7 @@ ggplot(sales, aes(x = interaction(quarter, year), y = value, group = 1)) + geom_line() + coord_cartesian(ylim = c(9, 32), expand = FALSE, clip = "off") + theme( - plot.margin = unit(c(1, 1, 3, 1), "lines"), + plot.margin = margin(1, 1, 3, 1, "lines"), axis.title.x = element_blank(), axis.text.x = element_blank() ) + @@ -215,7 +215,7 @@ ggplot(sales, aes(x = interaction(quarter, year), y = value)) + annotate(geom = "text", x = seq_len(nrow(sales)), y = -1, label = sales$quarter, size = 3) + annotate(geom = "text", x = c(2.5, 6.5), y = -3, label = unique(sales$year), size = 4) + theme( - plot.margin = unit(c(1, 1, 3, 1), "lines"), + plot.margin = margin(1, 1, 3, 1, "lines"), axis.title.x = element_blank(), axis.text.x = element_blank() ) diff --git a/vignettes/extending-ggplot2.Rmd b/vignettes/extending-ggplot2.Rmd index 01383378bc..6ee65ae718 100644 --- a/vignettes/extending-ggplot2.Rmd +++ b/vignettes/extending-ggplot2.Rmd @@ -724,11 +724,7 @@ render <- function(panels, layout, x_scales, y_scales, ranges, coord, data, panel_table <- gtable::gtable_matrix("layout", panels, widths = unit(c(1, 1), "null"), heights = unit(1, "null"), clip = "on") # Add spacing according to theme - panel_spacing <- if (is.null(theme$panel.spacing.x)) { - theme$panel.spacing - } else { - theme$panel.spacing.x - } + panel_spacing <- calc_element("panel.spacing.x", theme) panel_table <- gtable::gtable_add_col_space(panel_table, panel_spacing) } else { panels <- matrix(panels, ncol = 1) @@ -909,21 +905,13 @@ FacetTrans <- ggproto("FacetTrans", Facet, panel_table <- gtable::gtable_matrix("layout", panels, widths = unit(c(1, 1), "null"), heights = unit(1, "null"), clip = "on") # Add spacing according to theme - panel_spacing <- if (is.null(theme$panel.spacing.x)) { - theme$panel.spacing - } else { - theme$panel.spacing.x - } + panel_spacing <- calc_element("panel.spacing.x", theme) panel_table <- gtable::gtable_add_col_space(panel_table, panel_spacing) } else { panels <- matrix(panels, ncol = 1) panel_table <- gtable::gtable_matrix("layout", panels, widths = unit(1, "null"), heights = unit(c(1, 1), "null"), clip = "on") - panel_spacing <- if (is.null(theme$panel.spacing.y)) { - theme$panel.spacing - } else { - theme$panel.spacing.y - } + panel_spacing <- calc_element("panel.spacing.y", theme) panel_table <- gtable::gtable_add_row_space(panel_table, panel_spacing) } # Name panel grobs so they can be found later