Skip to content

Commit 42a764d

Browse files
authored
Move guide building to ggplot_build() (#5483)
* Divorce building and drawing/assembly * Fix test guide orders * Disconnect theme from build step * Move guide building to `ggplot_build()` * Some error messages are now thrown earlier * Adapt `guide_old()` * Expose `data` to `process_layers()` * Add news bullet
1 parent 34a59ef commit 42a764d

14 files changed

+157
-141
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# ggplot2 (development version)
22

3+
* (internal) guide building is now part of `ggplot_build()` instead of
4+
`ggplot_gtable()` to allow guides to observe unmapped data (#5483).
5+
36
* `geom_violin()` gains a `bounds` argument analogous to `geom_density()`s (@eliocamp, #5493).
47

58
* Legend titles no longer take up space if they've been removed by setting

R/coord-cartesian-.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,5 @@ panel_guides_grob <- function(guides, position, theme) {
151151
return(zeroGrob())
152152
}
153153
pair <- guides$get_position(position)
154-
pair$guide$draw(theme, pair$params)
154+
pair$guide$draw(theme, params = pair$params)
155155
}

R/guide-.R

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,12 @@ new_guide <- function(..., available_aes = "any", super) {
117117
#' `params$hash`. This ensures that e.g. `guide_legend()` can display both
118118
#' `shape` and `colour` in the same guide.
119119
#'
120-
#' - `get_layer_key()` Extract information from layers. This can be used to
121-
#' check that the guide's aesthetic is actually in use, or to gather
122-
#' information about how legend keys should be displayed.
120+
#' - `process_layers()` Extract information from layers. This acts mostly
121+
#' as a filter for which layers to include and these are then (typically)
122+
#' forwarded to `get_layer_key()`.
123+
#'
124+
#' - `get_layer_key()` This can be used to gather information about how legend
125+
#' keys should be displayed.
123126
#'
124127
#' - `setup_params()` Set up parameters at the beginning of drawing stages.
125128
#' It can be used to overrule user-supplied parameters or perform checks on
@@ -253,7 +256,11 @@ Guide <- ggproto(
253256

254257
# Function for extracting information from the layers.
255258
# Mostly applies to `guide_legend()` and `guide_binned()`
256-
get_layer_key = function(params, layers) {
259+
process_layers = function(self, params, layers, data = NULL) {
260+
self$get_layer_key(params, layers, data)
261+
},
262+
263+
get_layer_key = function(params, layers, data = NULL) {
257264
return(params)
258265
},
259266

@@ -280,11 +287,14 @@ Guide <- ggproto(
280287

281288
# Main drawing function that organises more specialised aspects of guide
282289
# drawing.
283-
draw = function(self, theme, params = self$params) {
290+
draw = function(self, theme, position = NULL, direction = NULL,
291+
params = self$params) {
284292

285293
key <- params$key
286294

287295
# Setup parameters and theme
296+
params$position <- params$position %||% position
297+
params$direction <- params$direction %||% direction
288298
params <- self$setup_params(params)
289299
elems <- self$setup_elements(params, self$elements, theme)
290300
elems <- self$override_elements(params, elems, theme)

R/guide-axis.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ draw_axis <- function(break_positions, break_labels, axis_position, theme,
486486
!!aes := c(0, 1),
487487
!!opp := opp_value
488488
)
489-
guide$draw(theme, params)
489+
guide$draw(theme, params = params)
490490
}
491491

492492
draw_axis_labels <- function(break_positions, break_labels, label_element, is_vertical,

R/guide-bins.R

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -298,15 +298,15 @@ GuideBins <- ggproto(
298298
params$title <- scale$make_title(
299299
params$title %|W|% scale$name %|W|% title
300300
)
301+
params$key <- key
302+
params
303+
},
304+
305+
setup_params = function(params) {
301306
params$direction <- arg_match0(
302-
params$direction %||% direction,
307+
params$direction,
303308
c("horizontal", "vertical"), arg_nm = "direction"
304309
)
305-
if (params$direction == "vertical") {
306-
key$.value <- 1 - key$.value
307-
}
308-
309-
params$key <- key
310310
valid_label_pos <- switch(
311311
params$direction,
312312
"horizontal" = c("bottom", "top"),
@@ -320,10 +320,6 @@ GuideBins <- ggproto(
320320
"not {.val {params$label.position}}."
321321
))
322322
}
323-
params
324-
},
325-
326-
setup_params = function(params) {
327323
params <- GuideLegend$setup_params(params)
328324
params$byrow <- FALSE
329325
params$rejust_labels <- FALSE
@@ -345,10 +341,15 @@ GuideBins <- ggproto(
345341
}
346342
key$.label[c(1, n_labels)[!params$show.limits]] <- ""
347343

348-
just <- if (params$direction == "horizontal") {
349-
elements$text$vjust
350-
} else {
351-
elements$text$hjust
344+
just <- switch(
345+
params$direction,
346+
horizontal = elements$text$vjust,
347+
vertical = elements$text$hjust,
348+
0.5
349+
)
350+
351+
if (params$direction == "vertical") {
352+
key$.value <- 1 - key$.value
352353
}
353354

354355
list(labels = flip_element_grob(
@@ -363,6 +364,9 @@ GuideBins <- ggproto(
363364
},
364365

365366
build_ticks = function(key, elements, params, position = params$position) {
367+
if (params$direction == "vertical") {
368+
key$.value <- 1 - key$.value
369+
}
366370
key$.value[c(1, nrow(key))[!params$show.limits]] <- NA
367371
Guide$build_ticks(key$.value, elements, params, params$label.position)
368372
},

R/guide-colorbar.R

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -344,27 +344,10 @@ GuideColourbar <- ggproto(
344344
},
345345

346346
extract_params = function(scale, params,
347-
title = waiver(), direction = "vertical", ...) {
347+
title = waiver(), ...) {
348348
params$title <- scale$make_title(
349349
params$title %|W|% scale$name %|W|% title
350350
)
351-
params$direction <- arg_match0(
352-
params$direction %||% direction,
353-
c("horizontal", "vertical"), arg_nm = "direction"
354-
)
355-
valid_label_pos <- switch(
356-
params$direction,
357-
"horizontal" = c("bottom", "top"),
358-
"vertical" = c("right", "left")
359-
)
360-
params$label.position <- params$label.position %||% valid_label_pos[1]
361-
if (!params$label.position %in% valid_label_pos) {
362-
cli::cli_abort(paste0(
363-
"When {.arg direction} is {.val {params$direction}}, ",
364-
"{.arg label.position} must be one of {.or {.val {valid_label_pos}}}, ",
365-
"not {.val {params$label.position}}."
366-
))
367-
}
368351

369352
limits <- c(params$decor$value[1], params$decor$value[nrow(params$decor)])
370353
params$key$.value <- rescale(
@@ -381,27 +364,28 @@ GuideColourbar <- ggproto(
381364
return(list(guide = self, params = params))
382365
},
383366

384-
get_layer_key = function(params, layers) {
385-
386-
guide_layers <- lapply(layers, function(layer) {
387-
388-
matched_aes <- matched_aes(layer, params)
389-
390-
# Check if this layer should be included
391-
if (include_layer_in_guide(layer, matched_aes)) {
392-
layer
393-
} else {
394-
NULL
395-
}
396-
})
397-
398-
if (length(compact(guide_layers)) == 0) {
399-
return(NULL)
400-
}
401-
return(params)
367+
get_layer_key = function(params, layers, data = NULL) {
368+
params
402369
},
403370

404371
setup_params = function(params) {
372+
params$direction <- arg_match0(
373+
params$direction,
374+
c("horizontal", "vertical"), arg_nm = "direction"
375+
)
376+
valid_label_pos <- switch(
377+
params$direction,
378+
"horizontal" = c("bottom", "top"),
379+
"vertical" = c("right", "left")
380+
)
381+
params$label.position <- params$label.position %||% valid_label_pos[1]
382+
if (!params$label.position %in% valid_label_pos) {
383+
cli::cli_abort(paste0(
384+
"When {.arg direction} is {.val {params$direction}}, ",
385+
"{.arg label.position} must be one of {.or {.val {valid_label_pos}}}, ",
386+
"not {.val {params$label.position}}."
387+
))
388+
}
405389
params$title.position <- arg_match0(
406390
params$title.position %||%
407391
switch(params$direction, vertical = "top", horizontal = "left"),

R/guide-legend.R

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ GuideLegend <- ggproto(
244244

245245
available_aes = "any",
246246

247-
hashables = exprs(title, key$.label, direction, name),
247+
hashables = exprs(title, key$.label, name),
248248

249249
elements = list(
250250
background = "legend.background",
@@ -260,14 +260,10 @@ GuideLegend <- ggproto(
260260
),
261261

262262
extract_params = function(scale, params,
263-
title = waiver(), direction = NULL, ...) {
263+
title = waiver(), ...) {
264264
params$title <- scale$make_title(
265265
params$title %|W|% scale$name %|W|% title
266266
)
267-
params$direction <- arg_match0(
268-
params$direction %||% direction,
269-
c("horizontal", "vertical"), arg_nm = "direction"
270-
)
271267
if (isTRUE(params$reverse %||% FALSE)) {
272268
params$key <- params$key[nrow(params$key):1, , drop = FALSE]
273269
}
@@ -291,17 +287,26 @@ GuideLegend <- ggproto(
291287
},
292288

293289
# Arrange common data for vertical and horizontal legends
294-
get_layer_key = function(params, layers) {
290+
process_layers = function(self, params, layers, data = NULL) {
291+
292+
include <- vapply(layers, function(layer) {
293+
aes <- matched_aes(layer, params)
294+
include_layer_in_guide(layer, aes)
295+
}, logical(1))
296+
297+
if (!any(include)) {
298+
return(NULL)
299+
}
300+
301+
self$get_layer_key(params, layers[include], data[include])
302+
},
303+
304+
get_layer_key = function(params, layers, data) {
295305

296306
decor <- lapply(layers, function(layer) {
297307

298308
matched_aes <- matched_aes(layer, params)
299309

300-
# Check if this layer should be included
301-
if (!include_layer_in_guide(layer, matched_aes)) {
302-
return(NULL)
303-
}
304-
305310
if (length(matched_aes) > 0) {
306311
# Filter out aesthetics that can't be applied to the legend
307312
n <- lengths(layer$aes_params, use.names = FALSE)
@@ -338,14 +343,15 @@ GuideLegend <- ggproto(
338343

339344
# Remove NULL geoms
340345
params$decor <- compact(decor)
341-
342-
if (length(params$decor) == 0) {
343-
return(NULL)
344-
}
345346
return(params)
346347
},
347348

348349
setup_params = function(params) {
350+
params$direction <- arg_match0(
351+
params$direction %||% direction,
352+
c("horizontal", "vertical"), arg_nm = "direction"
353+
)
354+
349355
if ("title.position" %in% names(params)) {
350356
params$title.position <- arg_match0(
351357
params$title.position %||%

R/guide-none.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ GuideNone <- ggproto(
3535
},
3636

3737
# Draw nothing
38-
draw = function(self, params, theme) {
38+
draw = function(self, ...) {
3939
zeroGrob()
4040
}
4141
)

R/guide-old.R

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ GuideOld <- ggproto(
9090
train = function(self, params, scale, aesthetic = NULL,
9191
title = waiver(), direction = NULL) {
9292
params$title <- scale$make_title(params$title %|W|% scale$name %|W|% title)
93-
params$direction <- params$direction %||% direction
93+
params$direction <- params$direction %||% direction %||% "vertical"
9494
params <- guide_train(params, scale, aesthetic)
9595
params
9696
},
@@ -103,13 +103,14 @@ GuideOld <- ggproto(
103103
guide_transform(params, coord, panel_params)
104104
},
105105

106-
get_layer_key = function(params, layers) {
106+
process_layers = function(self, params, layers, data = NULL) {
107107
guide_geom(params, layers, default_mapping = NULL)
108108
},
109109

110-
draw = function(self, theme, params) {
110+
draw = function(self, theme, position = NULL, direction = NULL, params) {
111+
params$direction <- params$direction %||% direction %||% "placeholder"
111112
params$title.position <- params$title.position %||% switch(
112-
params$direction %||% "placeholder",
113+
params$direction,
113114
vertical = "top", horizontal = "left",
114115
NULL
115116
)

0 commit comments

Comments
 (0)