Skip to content

Commit b69b372

Browse files
committed
revert d35f103
1 parent 6a447ba commit b69b372

File tree

2 files changed

+365
-366
lines changed

2 files changed

+365
-366
lines changed

R/plot-build.R

Lines changed: 0 additions & 366 deletions
Original file line numberDiff line numberDiff line change
@@ -177,369 +177,3 @@ get_layer_grob <- function(plot = get_last_plot(), i = 1L) {
177177
#' @export
178178
#' @rdname ggplot_build
179179
layer_grob <- get_layer_grob
180-
181-
#' Build a plot with all the usual bits and pieces.
182-
#'
183-
#' This function builds all grobs necessary for displaying the plot, and
184-
#' stores them in a special data structure called a [`gtable`][gtable::gtable].
185-
#' This object is amenable to programmatic manipulation, should you want
186-
#' to (e.g.) make the legend box 2 cm wide, or combine multiple plots into
187-
#' a single display, preserving aspect ratios across the plots.
188-
#'
189-
#' The `ggplot_gtable()` function is vestigial and the `gtable_ggplot()` function
190-
#' should be used instead.
191-
#'
192-
#' @seealso
193-
#' [print.ggplot()] and [benchplot()] for
194-
#' for functions that contain the complete set of steps for generating
195-
#' a ggplot2 plot.
196-
#'
197-
#' The `r link_book("gtable step section", "internals#sec-ggplotgtable")`
198-
#' @return a `gtable` object
199-
#' @keywords internal
200-
#' @param data plot data generated by [ggplot_build()]
201-
#' @export
202-
ggplot_gtable <- function(data) {
203-
# TODO: Swap to S7 generic once S7/#543 is resolved
204-
attach_plot_env(data@plot@plot_env)
205-
UseMethod("ggplot_gtable")
206-
}
207-
208-
S7::method(ggplot_gtable, class_ggplot_built) <- function(data) {
209-
plot <- data@plot
210-
layout <- data@layout
211-
data <- data@data
212-
theme <- plot@theme
213-
214-
geom_grobs <- by_layer(function(l, d) l$draw_geom(d, layout), plot@layers, data, "converting geom to grob")
215-
216-
plot_table <- layout$render(geom_grobs, data, theme, plot@labels)
217-
218-
# Legends
219-
legend_box <- plot@guides$assemble(theme)
220-
plot_table <- table_add_legends(plot_table, legend_box, theme)
221-
222-
# Title
223-
title <- element_render(
224-
theme, "plot.title", plot@labels$title,
225-
margin_y = TRUE, margin_x = TRUE
226-
)
227-
title_height <- grobHeight(title)
228-
229-
# Subtitle
230-
subtitle <- element_render(
231-
theme, "plot.subtitle", plot@labels$subtitle,
232-
margin_y = TRUE, margin_x = TRUE
233-
)
234-
subtitle_height <- grobHeight(subtitle)
235-
236-
# whole plot annotation
237-
caption <- element_render(
238-
theme, "plot.caption", plot@labels$caption,
239-
margin_y = TRUE, margin_x = TRUE
240-
)
241-
caption_height <- grobHeight(caption)
242-
243-
# positioning of title and subtitle is governed by plot.title.position
244-
# positioning of caption is governed by plot.caption.position
245-
# "panel" means align to the panel(s)
246-
# "plot" means align to the entire plot (except margins and tag)
247-
title_pos <- arg_match0(
248-
theme$plot.title.position %||% "panel",
249-
c("panel", "plot"),
250-
arg_nm = "plot.title.position",
251-
error_call = expr(theme())
252-
)
253-
254-
caption_pos <- arg_match0(
255-
theme$plot.caption.position %||% "panel",
256-
values = c("panel", "plot"),
257-
arg_nm = "plot.caption.position",
258-
error_call = expr(theme())
259-
)
260-
261-
pans <- plot_table$layout[grepl("^panel", plot_table$layout$name), , drop = FALSE]
262-
if (title_pos == "panel") {
263-
title_l <- min(pans$l)
264-
title_r <- max(pans$r)
265-
} else {
266-
title_l <- 1
267-
title_r <- ncol(plot_table)
268-
}
269-
if (caption_pos == "panel") {
270-
caption_l <- min(pans$l)
271-
caption_r <- max(pans$r)
272-
} else {
273-
caption_l <- 1
274-
caption_r <- ncol(plot_table)
275-
}
276-
277-
plot_table <- gtable_add_rows(plot_table, subtitle_height, pos = 0)
278-
plot_table <- gtable_add_grob(plot_table, subtitle, name = "subtitle",
279-
t = 1, b = 1, l = title_l, r = title_r, clip = "off")
280-
281-
plot_table <- gtable_add_rows(plot_table, title_height, pos = 0)
282-
plot_table <- gtable_add_grob(plot_table, title, name = "title",
283-
t = 1, b = 1, l = title_l, r = title_r, clip = "off")
284-
285-
plot_table <- gtable_add_rows(plot_table, caption_height, pos = -1)
286-
plot_table <- gtable_add_grob(plot_table, caption, name = "caption",
287-
t = -1, b = -1, l = caption_l, r = caption_r, clip = "off")
288-
289-
plot_table <- table_add_tag(plot_table, plot@labels$tag, theme)
290-
291-
# Margins
292-
plot_margin <- calc_element("plot.margin", theme) %||% margin()
293-
plot_table <- gtable_add_padding(plot_table, plot_margin)
294-
295-
if (is_theme_element(theme$plot.background)) {
296-
plot_table <- gtable_add_grob(plot_table,
297-
element_render(theme, "plot.background"),
298-
t = 1, l = 1, b = -1, r = -1, name = "background", z = -Inf)
299-
plot_table$layout <- plot_table$layout[c(nrow(plot_table$layout), 1:(nrow(plot_table$layout) - 1)),]
300-
plot_table$grobs <- plot_table$grobs[c(nrow(plot_table$layout), 1:(nrow(plot_table$layout) - 1))]
301-
}
302-
303-
# add alt-text as attribute
304-
attr(plot_table, "alt-label") <- plot@labels$alt
305-
306-
plot_table
307-
}
308-
309-
#' Generate a ggplot2 plot grob.
310-
#'
311-
#' @param x ggplot2 object
312-
#' @keywords internal
313-
#' @export
314-
ggplotGrob <- function(x) {
315-
ggplot_gtable(ggplot_build(x))
316-
}
317-
318-
S7::method(as.gtable, class_ggplot) <- function(x, ...) ggplotGrob(x)
319-
S7::method(as.gtable, class_ggplot_built) <- function(x, ...) ggplot_gtable(x)
320-
321-
# Apply function to layer and matching data
322-
by_layer <- function(f, layers, data, step = NULL) {
323-
ordinal <- label_ordinal()
324-
out <- vector("list", length(data))
325-
try_fetch(
326-
for (i in seq_along(data)) {
327-
out[[i]] <- f(l = layers[[i]], d = data[[i]])
328-
},
329-
error = function(cnd) {
330-
cli::cli_abort(c(
331-
"Problem while {step}.",
332-
"i" = "Error occurred in the {ordinal(i)} layer."),
333-
call = layers[[i]]$constructor,
334-
parent = cnd
335-
)
336-
}
337-
)
338-
out
339-
}
340-
341-
# Add the tag element to the gtable
342-
table_add_tag <- function(table, label, theme) {
343-
# Initialise the tag margins
344-
table <- gtable_add_padding(table, unit(0, "pt"))
345-
346-
# Early exit when label is absent or element is blank
347-
if (length(label) < 1) {
348-
return(table)
349-
}
350-
element <- calc_element("plot.tag", theme)
351-
if (is_theme_element(element, "blank")) {
352-
return(table)
353-
}
354-
355-
# Resolve position
356-
position <- calc_element("plot.tag.position", theme) %||% "topleft"
357-
location <- calc_element("plot.tag.location", theme) %||%
358-
(if (is.numeric(position)) "plot" else "margin")
359-
360-
if (is.numeric(position)) {
361-
if (location == "margin") {
362-
cli::cli_abort(paste0(
363-
"A {.cls numeric} {.arg plot.tag.position} cannot be used with ",
364-
"`{.val margin}` as {.arg plot.tag.location}."
365-
),
366-
call = expr(theme()))
367-
}
368-
check_length(
369-
position, 2L, call = expr(theme()),
370-
arg = I("A {.cls numeric} {.arg plot.tag.position}")
371-
)
372-
top <- left <- right <- bottom <- FALSE
373-
} else {
374-
# Break position into top/left/right/bottom
375-
position <- arg_match0(
376-
position[1],
377-
c("topleft", "top", "topright", "left",
378-
"right", "bottomleft", "bottom", "bottomright"),
379-
arg_nm = "plot.tag.position",
380-
error_call = expr(theme())
381-
)
382-
top <- position %in% c("topleft", "top", "topright")
383-
left <- position %in% c("topleft", "left", "bottomleft")
384-
right <- position %in% c("topright", "right", "bottomright")
385-
bottom <- position %in% c("bottomleft", "bottom", "bottomright")
386-
}
387-
388-
# Resolve tag and sizes
389-
tag <- element_grob(element, label = label, margin_y = TRUE, margin_x = TRUE)
390-
height <- grobHeight(tag)
391-
width <- grobWidth(tag)
392-
393-
if (location %in% c("plot", "panel")) {
394-
if (!is.numeric(position)) {
395-
hjust <- try_prop(element, "hjust", default = 0.5)
396-
if (right || left) {
397-
x <- (1 - hjust) * width
398-
if (right) {
399-
x <- unit(1, "npc") - x
400-
}
401-
} else {
402-
x <- unit(hjust, "npc")
403-
}
404-
if (top || bottom) {
405-
vjust <- try_prop(element, "vjust", default = 0.5)
406-
y <- (1 - vjust) * height
407-
if (top) {
408-
y <- unit(1, "npc") - y
409-
}
410-
} else {
411-
y <- unit(vjust, "npc")
412-
}
413-
} else {
414-
x <- unit(position[1], "npc")
415-
y <- unit(position[2], "npc")
416-
}
417-
# Re-render with manual positions
418-
tag <- element_grob(
419-
element, x = x, y = y, label = label,
420-
margin_y = TRUE, margin_x = TRUE
421-
)
422-
if (location == "plot") {
423-
table <- gtable_add_grob(
424-
table, tag, name = "tag", clip = "off",
425-
t = 1, b = nrow(table), l = 1, r = ncol(table)
426-
)
427-
return(table)
428-
}
429-
}
430-
431-
if (location == "panel") {
432-
place <- find_panel(table)
433-
} else {
434-
n_col <- ncol(table)
435-
n_row <- nrow(table)
436-
# Actually fill margin with relevant units
437-
if (top) table$heights <- unit.c(height, table$heights[-1])
438-
if (left) table$widths <- unit.c(width, table$widths[-1])
439-
if (right) table$widths <- unit.c(table$widths[-n_col], width)
440-
if (bottom) table$heights <- unit.c(table$heights[-n_row], height)
441-
place <- data_frame0(t = 1L, r = n_col, b = n_row, l = 1L)
442-
}
443-
444-
# Shrink placement to position
445-
if (top) place$b <- place$t
446-
if (left) place$r <- place$l
447-
if (right) place$l <- place$r
448-
if (bottom) place$t <- place$b
449-
450-
gtable_add_grob(
451-
table, tag, name = "tag", clip = "off",
452-
t = place$t, l = place$l, b = place$b, r = place$r
453-
)
454-
}
455-
456-
# Add the legends to the gtable
457-
table_add_legends <- function(table, legends, theme) {
458-
459-
if (is_zero(legends)) {
460-
legends <- rep(list(zeroGrob()), 5)
461-
names(legends) <- c(.trbl, "inside")
462-
}
463-
464-
# Extract sizes
465-
widths <- heights <- set_names(
466-
rep(list(unit(0, "cm")), length(legends)),
467-
names(legends)
468-
)
469-
470-
empty <- vapply(legends, is_zero, logical(1))
471-
widths[!empty] <- lapply(legends[!empty], gtable_width)
472-
heights[!empty] <- lapply(legends[!empty], gtable_height)
473-
spacing <- calc_element("legend.box.spacing", theme) %||% unit(0.2, "cm")
474-
475-
# If legend is missing, set spacing to zero for that legend
476-
zero <- unit(0, "pt")
477-
spacing <- lapply(empty, function(is_empty) if (is_empty) zero else spacing)
478-
479-
location <- switch(
480-
theme$legend.location %||% "panel",
481-
"plot" = plot_extent,
482-
find_panel
483-
)
484-
485-
place <- location(table)
486-
487-
# Add right legend
488-
table <- gtable_add_cols(table, spacing$right, pos = -1)
489-
table <- gtable_add_cols(table, widths$right, pos = -1)
490-
table <- gtable_add_grob(
491-
table, legends$right, clip = "off",
492-
t = place$t, b = place$b, l = -1, r = -1,
493-
name = "guide-box-right"
494-
)
495-
496-
# Add left legend
497-
table <- gtable_add_cols(table, spacing$left, pos = 0)
498-
table <- gtable_add_cols(table, widths$left, pos = 0)
499-
table <- gtable_add_grob(
500-
table, legends$left, clip = "off",
501-
t = place$t, b = place$b, l = 1, r = 1,
502-
name = "guide-box-left"
503-
)
504-
505-
place <- location(table)
506-
507-
# Add bottom legend
508-
table <- gtable_add_rows(table, spacing$bottom, pos = -1)
509-
table <- gtable_add_rows(table, heights$bottom, pos = -1)
510-
table <- gtable_add_grob(
511-
table, legends$bottom, clip = "off",
512-
t = -1, b = -1, l = place$l, r = place$r,
513-
name = "guide-box-bottom"
514-
)
515-
516-
# Add top legend
517-
table <- gtable_add_rows(table, spacing$top, pos = 0)
518-
table <- gtable_add_rows(table, heights$top, pos = 0)
519-
table <- gtable_add_grob(
520-
table, legends$top, clip = "off",
521-
t = 1, b = 1, l = place$l, r = place$r,
522-
name = "guide-box-top"
523-
)
524-
525-
# Add manual legend
526-
place <- find_panel(table)
527-
table <- gtable_add_grob(
528-
table, legends$inside, clip = "off",
529-
t = place$t, b = place$b, l = place$l, r = place$r,
530-
name = "guide-box-inside"
531-
)
532-
533-
table
534-
}
535-
536-
plot_extent <- function(table) {
537-
layout <- table$layout
538-
data_frame0(
539-
t = min(layout[["t"]]),
540-
r = max(layout[["r"]]),
541-
b = max(layout[["b"]]),
542-
l = min(layout[["l"]]),
543-
.size = 1L
544-
)
545-
}

0 commit comments

Comments
 (0)