Skip to content

Commit 40878c9

Browse files
author
Yunuuuu
committed
feat: define patch_options to pass layout configuration arguments
1 parent e14c856 commit 40878c9

13 files changed

Lines changed: 103 additions & 63 deletions

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ importFrom(S7,methods_register)
449449
importFrom(S7,new_object)
450450
importFrom(S7,prop)
451451
importFrom(S7,props)
452+
importFrom(S7,set_props)
452453
importFrom(S7,super)
453454
importFrom(cli,cli_abort)
454455
importFrom(cli,cli_inform)

R/alignpatch-.R

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,8 @@ Patch <- ggproto(
197197
#' [`standardized gtable`][standardized_gtable] object.
198198
#'
199199
#' **Arguments**
200-
#' - `theme`: The global [`theme`][ggplot2::theme] of the parent
201-
#' [`alignpatches()`] object.
202-
#' - `guides`: Specifies which sides of guide legends should be collected by
203-
#' the parent [`alignpatches()`] object. In most cases, this is the value
204-
#' returned by the subplot's `self$guides()` method. For plots along the
205-
#' border, any guide legends on that side will always be collected if any
206-
#' legends on that side of any subplot are being collected.
207-
#' - `tagger`: Either `NULL` (no tagging) or a `LayoutTagger` object that
208-
#' provides a `$tag_table` method (accepting the `gtable` and `theme`)
209-
#' used to add tag.
200+
#' - `options`: A [`patch_options`] object that contains various layout
201+
#' options.
210202
#'
211203
#' **Value**
212204
#' A standardized [`gtable`][gtable::gtable] object, or a simple
@@ -216,7 +208,7 @@ Patch <- ggproto(
216208
#' be a full table-based layout (`gtable`) for more complex arrangements or
217209
#' a simpler graphical object (`grob`) when only basic plot elements are
218210
#' involved.
219-
gtable = function(self, theme = NULL, guides = NULL, tagger = NULL) {
211+
gtable = function(self, options) {
220212
cli_abort("{.fn gtable} method is not defined")
221213
},
222214

R/alignpatch-alignpatches.R

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -145,19 +145,40 @@ S7::method(patch, alignpatches) <- function(x) {
145145

146146
##############################################################
147147
# For z in the gtable layout
148+
# 0L: layout background
149+
# 1L: background of the plot
150+
# 2L: plot table
151+
# 3L: foreground of the panel area
152+
# 4L: legends
153+
# 5L: tags
148154
LAYOUT_BACKGROUND_Z <- 0L
149155
PLOT_BACKGROUND_Z <- 1L
150156
PLOT_TABLE_Z <- 2L
151157
LAYOUT_FOREGROUND_Z <- 3L
152158
GUIDE_LEGENDS_Z <- 4L
153159
TAGS_Z <- 5L
154160

155-
# 0L: layout background
156-
# 1L: background of the plot
157-
# 2L: plot table
158-
# 3L: foreground of the panel area
159-
# 4L: legends
160-
# 5L: tags
161+
#' Options passed to the Patch `gtable` method
162+
#'
163+
#' This class defines the options that can be passed to the `gtable` method of a
164+
#' `Patch` object. It includes:
165+
#'
166+
#' - `theme`: The theme to be applied, which can be either `NULL` or a ggplot2
167+
#' [theme][ggplot2::theme] object.
168+
#' - `guides`: The guides for the plot, which can be `NULL` or a character
169+
#' vector.
170+
#' - `tagger`: Either `NULL` (no tagging) or a `LayoutTagger` object that
171+
#' provides a `$tag_table` method (accepting the `gtable` and `theme`)
172+
#' used to add tag.
173+
#'
174+
#' @keywords internal
175+
patch_options <- S7::new_class("patch_options",
176+
properties = list(
177+
theme = S7::new_union(NULL, ggplot2::class_theme),
178+
guides = S7::new_union(NULL, S7::class_character),
179+
tagger = S7::new_union(NULL, S7::new_S3_class("ggalign::LayoutTagger"))
180+
)
181+
)
161182

162183
#' @importFrom ggplot2 ggproto
163184
#' @noRd
@@ -166,12 +187,12 @@ PatchAlignpatches <- ggproto(
166187
#' @importFrom gtable gtable gtable_add_grob
167188
#' @importFrom grid unit
168189
#' @importFrom ggplot2 wrap_dims calc_element zeroGrob theme_get
169-
#' @importFrom S7 prop
170-
gtable = function(self, theme = NULL, guides = NULL, tagger = NULL) {
190+
#' @importFrom S7 prop prop<- set_props
191+
gtable = function(self, options) {
171192
patches <- lapply(prop(self$plot, "plots"), function(p) {
172193
out <- patch(p)
173194
if (!is.null(out) &&
174-
!inherits(out, sprintf("%s::Patch", pkg_nm()))) {
195+
!inherits(out, "ggalign::Patch")) {
175196
cli_abort("{.fn alignpatch} must return a {.cls Patch} object")
176197
}
177198
out
@@ -234,7 +255,8 @@ PatchAlignpatches <- ggproto(
234255
}
235256

236257
# we define the global theme --------------------------
237-
if (is.null(theme)) { # No parent theme provided
258+
# No parent theme provided
259+
if (is.null(theme <- prop(options, "theme"))) {
238260
top_level <- TRUE
239261
# by default, we use ggplot2 default theme
240262
theme <- prop(self$plot, "theme")
@@ -243,9 +265,10 @@ PatchAlignpatches <- ggproto(
243265
theme <- theme + prop(self$plot, "theme")
244266
}
245267
theme <- complete_theme(theme)
268+
prop(options, "theme", check = FALSE) <- theme
246269

247270
# by default, we won't collect any guide legends
248-
collected <- guides
271+
collected <- prop(options, "guides")
249272
guides <- prop(layout, "guides")
250273
if (is_string(guides)) {
251274
guides <- setup_guides(guides)
@@ -268,15 +291,17 @@ PatchAlignpatches <- ggproto(
268291
# - A single string representing the tag for the entire layout,
269292
# - NULL, meaning no tagging,
270293
# - Or a `LayoutTagger` object used to tag each plot individually.
271-
tagger <- create_layout_tagger(prop(self$plot, "tags"), tagger)
272-
if (!is.null(tagger) && !inherits(tagger, "LayoutTagger")) {
273-
# If tagger is not a LayoutTagger, treat it as a single tag for the
274-
# whole layout
275-
tag <- tagger
276-
tagger <- NULL
277-
} else {
278-
# Otherwise, no single tag for the whole layout
294+
tag <- create_layout_tagger(
295+
prop(self$plot, "tags"),
296+
prop(options, "tagger")
297+
)
298+
if (is.null(tag) || inherits(tag, "ggalign::LayoutTagger")) {
299+
prop(options, "tagger", check = FALSE) <- tag
279300
tag <- NULL
301+
} else {
302+
# If tag is a single string, treat it as a single tag for the
303+
# whole layout
304+
prop(options, "tagger", check = FALSE) <- NULL
280305
}
281306

282307
# Let each patch to determine whether to collect guides
@@ -299,7 +324,7 @@ PatchAlignpatches <- ggproto(
299324
.subset2(guides, i),
300325
intersect(border_with_guides, .subset2(borders_list, i))
301326
)
302-
gt <- patch$gtable(theme, g, tagger)
327+
gt <- patch$gtable(set_props(options, guides = g))
303328
components <- patch$decompose_guides(gt, g)
304329
guides_list[i] <- list(.subset2(components, "guides"))
305330
gt_list[i] <- list(.subset2(components, "gt"))

R/alignpatch-build.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ S7::method(ggalign_build, alignpatches) <- function(x) x
1212
#' @importFrom rlang arg_match0
1313
#' @importFrom S7 prop
1414
S7::method(ggalign_gtable, alignpatches) <- function(x) {
15-
table <- patch(x)$gtable()
15+
table <- patch(x)$gtable(patch_options())
1616

1717
# ensure theme has no missing value
1818
theme <- complete_theme(prop(x, "theme") %||% theme_get())

R/alignpatch-ggplot2.R

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ grid.draw.patch_ggplot <- function(x, recording = TRUE) {
5757

5858
##################################################
5959
S7::method(ggalign_gtable, ggplot2::class_ggplot) <- function(x) {
60-
patch(x)$gtable()
60+
patch(x)$gtable(patch_options())
6161
}
6262

6363
S7::method(ggalign_build, ggplot2::class_ggplot) <- function(x) x
@@ -80,12 +80,12 @@ S7::method(patch, ggplot2::class_ggplot) <- function(x) {
8080
#' @importFrom ggplot2 ggplotGrob update_labels complete_theme
8181
#' @include alignpatch-.R
8282
PatchGgplot <- ggproto("PatchGgplot", Patch,
83-
gtable = function(self, theme = NULL, guides = NULL, tagger = NULL) {
83+
gtable = function(self, options) {
8484
plot <- self$plot
85-
if (is.null(theme)) {
85+
if (is.null(prop(options, "theme"))) {
8686
theme <- plot$theme
8787
} else {
88-
theme <- tag_theme(theme) + plot$theme
88+
theme <- tag_theme(prop(options, "theme")) + plot$theme
8989
}
9090

9191
# complete_theme() will ensure elements exist --------
@@ -100,7 +100,9 @@ PatchGgplot <- ggproto("PatchGgplot", Patch,
100100
# always add strips columns and/or rows
101101
ans <- add_strips(ans, self$strip_pos)
102102
ans <- setup_patch_title(ans, plot$ggalign_patch_title, theme = theme)
103-
if (!is.null(tagger)) ans <- tagger$tag_table(ans, theme)
103+
if (!is.null(prop(options, "tagger"))) {
104+
ans <- prop(options, "tagger")$tag_table(ans, theme)
105+
}
104106
ans
105107
},
106108
border_sizes = function(self, gt = NULL, free = NULL) {

R/alignpatch-inset.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ patch.ggalign_inset <- function(x) {
129129
ggproto(
130130
"PatchWrapped",
131131
Parent,
132-
gtable = function(self, theme = NULL, guides = NULL, tagger = NULL) {
133-
gt <- ggproto_parent(Parent, self)$gtable(theme, guides, tagger)
132+
gtable = function(self, options) {
133+
gt <- ggproto_parent(Parent, self)$gtable(options)
134134
# Note: When the gtable represents a facetted plot, the number
135135
# of rows/columns (heights or widths) will exceed
136136
# TABLE_ROWS/COLS.

R/alignpatch-patchwork.R

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ PatchPatchworkPatch <- ggproto(
6969
# `patch` from `patchwork`: patchwork::plot_spacer
7070
#' @importFrom gtable gtable_add_rows gtable_add_cols
7171
#' @importFrom ggplot2 find_panel
72-
gtable = function(self, theme = NULL, guides = NULL, tagger = NULL) {
73-
guides <- if (length(guides)) "collect" else "keep"
72+
gtable = function(self, options) {
73+
guides <- if (length(prop(options, "guides"))) "collect" else "keep"
7474
ans <- patchwork::patchGrob(self$plot, guides = guides)
7575
# add rows and columns for `patch_title()`
7676
for (border in .TLBR) {
@@ -89,8 +89,10 @@ PatchPatchworkPatch <- ggproto(
8989
ans <- gtable_add_cols(ans, unit(0, "mm"), pos = v)
9090
}
9191
}
92-
if (!is.null(tagger)) {
93-
ans <- tagger$tag_table(ans, theme %||% theme_get())
92+
if (!is.null(tagger <- prop(options, "tagger"))) {
93+
ans <- tagger$tag_table(
94+
ans, prop(options, "theme") %||% theme_get()
95+
)
9496
}
9597
ans
9698
}

R/alignpatch-tags.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ create_layout_tagger <- function(tags, parent) {
180180
)
181181
}
182182
ggproto(
183-
"LayoutTagger", NULL,
183+
"ggalign::LayoutTagger", NULL,
184184
tags = tags,
185185
prefix = prefix,
186186
suffix = suffix,

R/layout-chain-circle-build.R

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,17 +315,19 @@ S7::method(ggalign_gtable, CircleLayout) <- function(x) {
315315
S7::method(patch, CircleLayout) <- function(x) {
316316
build <- ggalign_build(x)
317317
ggproto(NULL, PatchGgplot,
318-
gtable = function(self, theme = NULL, guides = NULL, tagger = NULL) {
318+
gtable = function(self, options) {
319319
# Preserve tag-related theme settings from the original layout
320320
# theme. These are intentionally not overridden so that
321321
# `PatchAlignpatches` retains full control over tag appearance and
322322
# positioning.
323-
if (!is.null(theme)) {
323+
if (!is.null(theme <- prop(options, "theme"))) {
324324
theme <- prop(build, "theme") +
325325
(tag_theme(theme) + tag_theme(prop(x, "theme")))
326326
}
327327
gt <- ggalign_gtable(build)
328-
if (!is.null(tagger)) gt <- tagger$tag_table(gt, theme)
328+
if (!is.null(tagger <- prop(options, "tagger"))) {
329+
gt <- tagger$tag_table(gt, theme)
330+
}
329331
gt
330332
}
331333
)

R/layout-chain-stack-build.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ S7::method(ggalign_build, StackLayout) <- function(x) {
99
S7::method(patch, StackLayout) <- function(x) {
1010
Parent <- patch(ggalign_build(x))
1111
ggproto(NULL, Parent,
12-
gtable = function(self, theme = NULL, guides = NULL, tagger = NULL) {
12+
gtable = function(self, options) {
1313
# Preserve tag-related theme settings from the original layout
1414
# theme. These are intentionally not overridden so that `Parent`
1515
# retains full control over tag appearance and positioning.
16-
if (!is.null(theme)) {
16+
if (!is.null(theme <- prop(options, "theme"))) {
1717
prop(self$plot, "theme") <- prop(self$plot, "theme") +
1818
(tag_theme(theme) + tag_theme(prop(x, "theme")))
1919
}
20-
ggproto_parent(Parent, self)$gtable(theme, guides, tagger)
20+
ggproto_parent(Parent, self)$gtable(options)
2121
}
2222
)
2323
}

0 commit comments

Comments
 (0)