Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ Collate:
'theme.R'
'theme-defaults.R'
'theme-current.R'
'theme-sub.R'
'utilities-break.R'
'utilities-grid.R'
'utilities-help.R'
Expand Down
11 changes: 11 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -663,17 +663,28 @@ export(summarise_layout)
export(sym)
export(syms)
export(theme)
export(theme_axis)
export(theme_axis_bottom)
export(theme_axis_left)
export(theme_axis_right)
export(theme_axis_top)
export(theme_axis_x)
export(theme_axis_y)
export(theme_bw)
export(theme_classic)
export(theme_dark)
export(theme_get)
export(theme_gray)
export(theme_grey)
export(theme_legend)
export(theme_light)
export(theme_linedraw)
export(theme_minimal)
export(theme_panel)
export(theme_plot)
export(theme_replace)
export(theme_set)
export(theme_strip)
export(theme_test)
export(theme_update)
export(theme_void)
Expand Down
8 changes: 7 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# ggplot2 (development version)

* New function family for setting parts of a theme. For example, you can now use
`theme_axis(line, text, ticks, ticks.length, line)` as a substitute for
`theme(axis.line, axis.text, axis.ticks, axis.ticks.length, axis.line)`. This
should allow slightly terser and more organised theme declarations
(@teunbrand, #5301).

* `ScaleContinuous$get_breaks()` now only calls `scales::zero_range()` on limits
in transformed space, rather than in data space (#5304).

Expand Down Expand Up @@ -36,7 +42,7 @@

* Integers are once again valid input to theme arguments that expect numeric
input (@teunbrand, #5369)

* Nicer error messages for xlim/ylim arguments in coord-* functions
(@92amartins, #4601, #5297).

Expand Down
144 changes: 144 additions & 0 deletions R/theme-sub.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#' Shortcuts for theme settings
#'
#' This collection of functions serves as a shortcut for [`theme()`][theme] with
#' shorter argument names. Besides the shorter arguments, it also helps in
#' keeping theme declarations more organised.
#'
#' @eval subtheme_param_doc()
#'
#' @return A `theme`-class object that can be added to a plot.
#' @name subtheme
#'
#' @examples
#' # A standard plot
#' p <- ggplot(mtcars, aes(disp, mpg, colour = drat)) +
#' geom_point()
#'
#' red_text <- element_text(colour = "red")
#' red_line <- element_line(colour = "red")
#'
#' # The theme settings below:
#' p + theme(
#' axis.title.x.bottom = red_text,
#' axis.text.x.bottom = red_text,
#' axis.line.x.bottom = red_line,
#' axis.ticks.x.bottom = red_line
#' )
#'
#' # Are equivalent to these less verbose theme settings
#' p + theme_axis_bottom(
#' title = red_text,
#' text = red_text,
#' line = red_line,
#' ticks = red_line
#' )
NULL

subtheme <- function(elements, prefix = "", suffix = "", call = caller_env()) {
if (length(elements) < 1) {
return(theme())
}
names(elements) <- paste0(prefix, names(elements), suffix)

extra <- setdiff(names(elements), names(get_element_tree()))
if (length(extra) > 0) {
cli::cli_warn(
"Ignoring unknown {.fn theme} element{?s}: {.and {.field {extra}}}.",
call = call
)
elements <- elements[setdiff(names(elements), extra)]
}

exec(theme, !!!elements)
}

#' @export
#' @describeIn subtheme Theme specification for all axes.
theme_axis <- function(title, text, ticks, ticks.length, line) {
subtheme(find_args(), "axis.")
}

#' @export
#' @describeIn subtheme Theme specification for both x axes.
theme_axis_x <- function(title, text, ticks, ticks.length, line) {
subtheme(find_args(), "axis.", ".x")
}

#' @export
#' @describeIn subtheme Theme specification for both y axes.
theme_axis_y <- function(title, text, ticks, ticks.length, line) {
subtheme(find_args(), "axis.", ".y")
}

#' @export
#' @describeIn subtheme Theme specification for the bottom x axis.
theme_axis_bottom <- function(title, text, ticks, ticks.length, line) {
subtheme(find_args(), "axis.", ".x.bottom")
}

#' @export
#' @describeIn subtheme Theme specification for the top x axis.
theme_axis_top <- function(title, text, ticks, ticks.length, line) {
subtheme(find_args(), "axis.", ".x.top")
}

#' @export
#' @describeIn subtheme Theme specification for the left y axis.
theme_axis_left <- function(title, text, ticks, ticks.length, line) {
subtheme(find_args(), "axis.", ".y.left")
}

#' @export
#' @describeIn subtheme Theme specification for the right y axis.
theme_axis_right <- function(title, text, ticks, ticks.length, line) {
subtheme(find_args(), "axis.", ".y.right")
}

#' @export
#' @describeIn subtheme Theme specification for the legend.
theme_legend <- function(background, margin, spacing, spacing.x, spacing.y,
key, key.size, key.height, key.width, text, title,
position, direction, justification, box, box.just,
box.margin, box.background, box.spacing) {
subtheme(find_args(), "legend.")
}

#' @export
#' @describeIn subtheme Theme specification for the panels.
theme_panel <- function(background, border, spacing, spacing.x, spacing.y,
grid, grid.major, grid.minor, grid.major.x,
grid.major.y, grid.minor.x, grid.minor.y, ontop) {
subtheme(find_args(), "panel.")
}

#' @export
#' @describeIn subtheme Theme specification for the whole plot.
theme_plot <- function(background, title, title.position, subtitle, caption,
caption.position, tag, tag.position, tag.location,
margin) {
subtheme(find_args(), "plot.")
}

#' @export
#' @describeIn subtheme Theme specification for facet strips.
theme_strip <- function(background, background.x, background.y, clip,
placement, text, text.x, text.x.bottom, text.x.top,
text.y, text.y.left, text.y.right,
switch.pad.grid, switch.pad.wrap) {
subtheme(find_args(), "strip.")
}

subtheme_param_doc <- function() {
funs <- list(
theme_axis, theme_axis_x, theme_axis_y, theme_axis_bottom,
theme_axis_top, theme_axis_left, theme_axis_right, theme_legend,
theme_panel, theme_plot, theme_strip
)
args <- sort(unique(unlist(lapply(funs, fn_fmls_names), use.names = FALSE)))
paste0(
"@param ",
paste0(args, collapse = ","),
" Arguments that are renamed and passed on to ",
"\\code{\\link[=theme]{theme()}}."
)
}
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ reference:
- theme
- theme_bw
- theme_update
- subtheme
- element_line
- margin

Expand Down
159 changes: 159 additions & 0 deletions man/subtheme.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions tests/testthat/_snaps/theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
`plot.tag.position` must be one of "topleft", "top", "topright", "left", "right", "bottomleft", "bottom", or "bottomright", not "test".
i Did you mean "left"?

# subtheme functions rename arguments as intended

Ignoring unknown `theme()` elements: foo and bar.

# Theme validation behaves as expected

The `aspect.ratio` theme element must be a <numeric/integer> object.
Expand Down
Loading