Skip to content

Commit

Permalink
Fix #198
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasp85 committed Sep 3, 2024
1 parent f10264d commit 3cb3d7b
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 34 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ importFrom(ggplot2,set_last_plot)
importFrom(ggplot2,theme)
importFrom(ggplot2,theme_get)
importFrom(ggplot2,theme_void)
importFrom(ggplot2,waiver)
importFrom(ggplot2,wrap_dims)
importFrom(ggplot2,zeroGrob)
importFrom(grDevices,is.raster)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* `as.list()` is now provided for patchwork objects to get the plots in a
patchwork as a list. This also allows the use of `lapply()` and friends on
patchwork objects (#381)
* The default arguments in `plot_annotation()` and `plot_layout()` are now
`waiver()` allowing the use of `NULL` to remove an already set value (#198)

# patchwork 1.2.0

Expand Down
2 changes: 2 additions & 0 deletions R/aaa.R
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ check_object <- function(x,
call = call
)
}

is_waiver <- function(x) inherits(x, "waiver")
25 changes: 23 additions & 2 deletions R/add_plot.R
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,29 @@ add_patches.patchwork <- function(plot, patches) {
new_patchwork <- function() {
list(
plots = list(),
layout = plot_layout(),
annotation = plot_annotation()
# We need to initialise layout and annotation with NULL values rather than waivers
layout = plot_layout(
ncol = NULL,
nrow = NULL,
byrow = NULL,
widths = NULL,
heights = NULL,
guides = NULL,
tag_level = NULL,
design = NULL,
axes = NULL,
axis_titles = NULL
),
annotation = plot_annotation(
title = NULL,
subtitle = NULL,
caption = NULL,
tag_levels = NULL,
tag_prefix = NULL,
tag_suffix = NULL,
tag_sep = NULL,
theme = NULL
)
)
}
#' @importFrom ggplot2 ggplot
Expand Down
30 changes: 23 additions & 7 deletions R/plot_annotation.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ has_tag <- function(x) {
#' The result of this function can be added to a patchwork using `+` in the same
#' way as [plot_layout()], but unlike [plot_layout()] it will only have an
#' effect on the top level plot. As the name suggests it controls different
#' aspects of the annotation of the final plot, such as titles and tags.
#' aspects of the annotation of the final plot, such as titles and tags. Already
#' added annotations can be removed by setting the relevant argument to `NULL`.
#'
#' @details
#' Tagging of subplots is done automatically and following the order of the
Expand Down Expand Up @@ -38,6 +39,7 @@ has_tag <- function(x) {
#' @return A `plot_annotation` object
#'
#' @export
#' @importFrom ggplot2 waiver
#'
#' @examples
#' library(ggplot2)
Expand Down Expand Up @@ -69,9 +71,9 @@ has_tag <- function(x) {
#' p1 / ((p2 | p3) + plot_layout(tag_level = 'new')) +
#' plot_annotation(tag_levels = list(c('&', '%'), '1'))
#'
plot_annotation <- function(title = NULL, subtitle = NULL, caption = NULL,
tag_levels = NULL, tag_prefix = NULL, tag_suffix = NULL,
tag_sep = NULL, theme = NULL) {
plot_annotation <- function(title = waiver(), subtitle = waiver(), caption = waiver(),
tag_levels = waiver(), tag_prefix = waiver(), tag_suffix = waiver(),
tag_sep = waiver(), theme = waiver()) {
th <- if (is.null(theme)) ggplot2::theme() else theme
structure(list(
title = title,
Expand All @@ -84,14 +86,28 @@ plot_annotation <- function(title = NULL, subtitle = NULL, caption = NULL,
theme = th
), class = 'plot_annotation')
}
default_annotation <- plot_annotation(tag_levels = character(), tag_prefix = '', tag_suffix = '', tag_sep = '')
default_annotation <- plot_annotation(
title = NULL,
subtitle = NULL,
caption = NULL,
tag_levels = character(),
tag_prefix = '',
tag_suffix = '',
tag_sep = '',
theme = NULL
)
#' @importFrom utils modifyList
#' @export
ggplot_add.plot_annotation <- function(object, plot, object_name) {
plot <- as_patchwork(plot)
plot$patches$annotation$theme <- plot$patches$annotation$theme + object$theme
if (is.null(object$theme)) {
plot$patches$annotation$theme <- NULL
} else if (!is_waiver(object$theme)) {
plot$patches$annotation$theme <- plot$patches$annotation$theme + object$theme
}
object$theme <- NULL
plot$patches$annotation <- modifyList(plot$patches$annotation, object[!vapply(object, is.null, logical(1))])
do_change <- object[!vapply(object, is_waiver, logical(1))]
plot$patches$annotation[names(do_change)] <- do_change
plot
}
#' @importFrom ggplot2 is.ggplot labs
Expand Down
39 changes: 23 additions & 16 deletions R/plot_layout.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#'
#' To control how different plots are laid out, you need to add a
#' layout specification. If you are nesting grids, the layout is scoped to the
#' current nesting level.
#' current nesting level. An already set value can be removed by setting it to
#' `NULL`.
#'
#' @param ncol,nrow The dimensions of the grid to create - if both are `NULL` it
#' will use the same logic as [facet_wrap()][ggplot2::facet_wrap] to set the
Expand Down Expand Up @@ -106,18 +107,22 @@
#' # Guide position must be applied to entire patchwork
#' p6 + p7 + plot_layout(guides='collect') &
#' theme(legend.position='bottom')

plot_layout <- function(ncol = NULL, nrow = NULL, byrow = NULL, widths = NULL,
heights = NULL, guides = NULL, tag_level = NULL,
design = NULL, axes = NULL, axis_titles = axes) {
if (!is.null(guides)) guides <- match.arg(guides, c('auto', 'collect', 'keep'))
if (!is.null(tag_level)) tag_level <- match.arg(tag_level, c('keep', 'new'))
if (!is.null(axes)) axes <- match.arg(
axes, c('keep', 'collect', 'collect_x', 'collect_y')
)
if (!is.null(axis_titles)) collect_titles <- match.arg(
axis_titles, c('keep', 'collect', 'collect_x', 'collect_y')
)
plot_layout <- function(ncol = waiver(), nrow = waiver(), byrow = waiver(),
widths = waiver(), heights = waiver(), guides = waiver(),
tag_level = waiver(), design = waiver(), axes = waiver(),
axis_titles = axes) {
if (!is.null(guides) && !is_waiver(guides)) {
guides <- arg_match0(guides, c('auto', 'collect', 'keep'))
}
if (!is.null(tag_level) && !is_waiver(tag_level)) {
tag_level <- arg_match0(tag_level, c('keep', 'new'))
}
if (!is.null(axes) && !is_waiver(axes)) {
axes <- arg_match0(axes, c('keep', 'collect', 'collect_x', 'collect_y'))
}
if (!is.null(axis_titles) && !is_waiver(axis_titles)) {
collect_titles <- arg_match0(axis_titles, c('keep', 'collect', 'collect_x', 'collect_y'))
}
structure(list(
ncol = ncol,
nrow = nrow,
Expand All @@ -128,7 +133,7 @@ plot_layout <- function(ncol = NULL, nrow = NULL, byrow = NULL, widths = NULL,
tag_level = tag_level,
axes = axes,
axis_titles = axis_titles,
design = as_areas(design)
design = if (is_waiver(design)) design else as_areas(design)
), class = 'plot_layout')
}
#' Specify a plotting area in a layout
Expand Down Expand Up @@ -304,13 +309,15 @@ c.patch_area <- function(..., recursive = FALSE) {
area
}
default_layout <- plot_layout(
byrow = TRUE, widths = NA, heights = NA, guides = 'auto', tag_level = 'keep',
ncol = NULL, nrow = NULL, byrow = TRUE, widths = NA, heights = NA,
guides = 'auto', tag_level = 'keep', design = NULL,
axes = 'keep', axis_titles = 'keep'
)
#' @importFrom utils modifyList
#' @export
ggplot_add.plot_layout <- function(object, plot, object_name) {
plot <- as_patchwork(plot)
plot$patches$layout <- modifyList(plot$patches$layout, object[!vapply(object, is.null, logical(1))])
do_change <- object[!vapply(object, is_waiver, logical(1))]
plot$patches$layout[names(do_change)] <- do_change
plot
}
19 changes: 10 additions & 9 deletions man/plot_annotation.Rd

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

0 comments on commit 3cb3d7b

Please sign in to comment.