Skip to content

Commit e7cf7de

Browse files
committed
avoid modify package_box
1 parent 4dd4970 commit e7cf7de

File tree

2 files changed

+73
-90
lines changed

2 files changed

+73
-90
lines changed

R/guides-.R

Lines changed: 68 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -514,74 +514,86 @@ Guides <- ggproto(
514514

515515
# we grouped the legends by the positions, for inside legends, they'll be
516516
# splitted by the actual inside coordinate
517-
groups <- positions
518-
for (i in seq_along(positions)[positions == "inside"]) {
517+
for (i in seq_along(positions)) {
518+
if (identical(positions[i], "inside")) {
519519
# the actual inside position and justification can be set in each guide
520520
# by `theme` argument, here, we won't use `calc_element()` which will
521521
# use inherits from `legend.justification` or `legend.position`, we only
522522
# follow the inside elements from the guide theme
523523
inside_just <- params[[i]]$theme[["legend.justification.inside"]]
524-
inside_justs[[i]] <- valid.just(inside_just %||% default_inside_just)
525-
inside_positions[[i]] <- params[[i]]$theme[[
526-
"legend.position.inside"
527-
]] %||% default_inside_position %||% inside_justs[[i]]
528-
groups[i] <- paste("inside",
529-
paste(inside_positions[[i]], collapse = "_"),
530-
paste(inside_justs[[i]], collapse = "_"),
531-
sep = "_"
524+
inside_justs[i] <- list(
525+
valid.just(inside_just %||% default_inside_just)
526+
)
527+
inside_positions[i] <- list(
528+
params[[i]]$theme[[
529+
"legend.position.inside"
530+
]] %||% default_inside_position %||% inside_justs[[i]]
532531
)
533532
}
534533
}
535534

536535
positions <- positions[keep]
537536
inside_positions <- inside_positions[keep]
538537
inside_justs <- inside_justs[keep]
539-
groups <- groups[keep]
540538

541539
# we group the guide legends
542-
locs <- vec_group_loc(groups)
543-
indices <- locs$loc
544-
grobs <- vec_chop(grobs, indices = indices)
545-
names(grobs) <- locs$key
546-
547-
# for each group, they share the same locations,
548-
# so we only extract the first one of `positions` and `inside_positions`
549-
first_indice <- lapply(indices, `[[`, 1L)
550-
positions <- vec_chop(positions, indices = first_indice)
551-
inside_positions <- vec_chop(inside_positions, indices = first_indice)
552-
inside_justs <- vec_chop(inside_justs, indices = first_indice)
540+
locs <- vec_group_loc(new_data_frame(
541+
set_names(
542+
list(positions, inside_positions, inside_justs),
543+
c("position", "coords", "justs")
544+
)
545+
))
546+
grobs <- vec_chop(grobs, indices = locs$loc)
547+
keys <- locs$key
553548

554549
# Set spacing
555550
theme$legend.spacing <- theme$legend.spacing %||% unit(0.5, "lines")
556551
theme$legend.spacing.y <- calc_element("legend.spacing.y", theme)
557552
theme$legend.spacing.x <- calc_element("legend.spacing.x", theme)
558553

559-
Map(
560-
grobs = grobs,
561-
position = positions,
562-
inside_position = inside_positions,
563-
inside_just = inside_justs,
564-
self$package_box,
565-
MoreArgs = list(theme = theme)
566-
)
554+
# prepare output
555+
ans <- vector("list", 5L)
556+
names(ans) <- c(.trbl, "inside")
557+
for (i in vec_seq_along(locs)) {
558+
if (identical(position <- keys$position[i], "inside")) {
559+
ans[[position]] <- c(
560+
ans[[position]],
561+
list(self$package_box(
562+
grobs = grobs[[i]],
563+
position = position,
564+
theme = theme + theme(
565+
legend.position.inside = keys$coords[[i]],
566+
legend.justification.inside = keys$justs[[i]]
567+
)
568+
))
569+
)
570+
} else {
571+
ans[[position]] <- self$package_box(
572+
grobs = grobs[[i]],
573+
position = position, theme = theme
574+
)
575+
}
576+
}
577+
# merge inside grobs into single gtable
578+
if (!is.null(ans$inside)) {
579+
ans$inside <- gtable_add_grob(
580+
gtable(unit(1, "null"), unit(1, "null")),
581+
grobs = ans$inside,
582+
clip = "off",
583+
t = 1L, l = 1L,
584+
name = paste("guide-box-inside", seq_along(ans$inside), sep = "-")
585+
)
586+
}
587+
ans
567588
},
568589

569590
# Render the guides into grobs
570-
draw = function(self, theme, positions = NULL, direction = NULL,
591+
draw = function(self, theme, positions, direction = NULL,
571592
params = self$params,
572593
guides = self$guides) {
573-
positions <- positions %||% vapply(
574-
params,
575-
function(p) p$position[1] %||% "right",
576-
character(1), USE.NAMES = FALSE
577-
)
594+
directions <- rep(direction %||% "vertical", length(positions))
578595
if (is.null(direction)) {
579-
directions <- ifelse(
580-
positions %in% c("top", "bottom"),
581-
"horizontal", "vertical"
582-
)
583-
} else {
584-
directions <- rep(direction, length(positions))
596+
directions[positions %in% c("top", "bottom")] <- "horizontal"
585597
}
586598

587599
grobs <- vector("list", length(guides))
@@ -597,8 +609,8 @@ Guides <- ggproto(
597609
# here, we put `inside_position` and `inside_just` in the last, so that it
598610
# won't break current implement of patchwork, which depends on the top three
599611
# arguments to collect guides
600-
package_box = function(grobs, position, theme,
601-
inside_position = NULL, inside_just = NULL) {
612+
package_box = function(grobs, position, theme) {
613+
602614
if (is.zero(grobs) || length(grobs) == 0) {
603615
return(zeroGrob())
604616
}
@@ -626,36 +638,19 @@ Guides <- ggproto(
626638
stretch_x <- any(unlist(lapply(widths, unitType)) == "null")
627639
stretch_y <- any(unlist(lapply(heights, unitType)) == "null")
628640

641+
# Global justification of the complete legend box
642+
global_just <- paste0("legend.justification.", position)
643+
global_just <- valid.just(calc_element(global_just, theme))
644+
629645
if (position == "inside") {
630-
# for backward compatibility, no `inside_just` input
631-
if (is.null(inside_just) ||
632-
# `inside_just` is a list of length one
633-
is.null(inside_just <- inside_just[[1L]])) {
634-
global_just <- valid.just(
635-
calc_element("legend.justification.inside", theme)
636-
)
637-
} else {
638-
global_just <- inside_just
639-
}
640-
global_xjust <- global_just[1]
641-
global_yjust <- global_just[2]
642-
# for backward compatibility, no `inside_position` input
643-
if (is.null(inside_position) ||
644-
# `inside_position` is a list of length one
645-
is.null(inside_position <- inside_position[[1L]])) {
646-
x <- global_xjust
647-
y <- global_yjust
648-
} else {
649-
x <- inside_position[1L]
650-
y <- inside_position[2L]
651-
}
646+
# The position of inside legends are set by their justification
647+
inside_position <- theme$legend.position.inside %||% global_just
648+
global_xjust <- inside_position[1]
649+
global_yjust <- inside_position[2]
652650
global_margin <- margin()
653651
} else {
654-
# Global justification of the complete legend box
655-
global_just <- paste0("legend.justification.", position)
656-
global_just <- valid.just(calc_element(global_just, theme))
657-
x <- global_xjust <- global_just[1]
658-
y <- global_yjust <- global_just[2]
652+
global_xjust <- global_just[1]
653+
global_yjust <- global_just[2]
659654
# Legends to the side of the plot need a margin for justification
660655
# relative to the plot panel
661656
global_margin <- margin(
@@ -697,7 +692,7 @@ Guides <- ggproto(
697692

698693
# Set global justification
699694
vp <- viewport(
700-
x = x, y = y, just = global_just,
695+
x = global_xjust, y = global_yjust, just = global_just,
701696
height = max(heights),
702697
width = vp_width
703698
)
@@ -735,7 +730,7 @@ Guides <- ggproto(
735730

736731
# Set global justification
737732
vp <- viewport(
738-
x = x, y = y, just = global_just,
733+
x = global_xjust, y = global_yjust, just = global_just,
739734
height = vp_height,
740735
width = max(widths)
741736
)
@@ -776,7 +771,6 @@ Guides <- ggproto(
776771
guides$name <- "guide-box"
777772
guides
778773
},
779-
780774
## Utilities -----------------------------------------------------------------
781775

782776
print = function(self) {

R/plot-build.R

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -515,22 +515,11 @@ table_add_legends <- function(table, legends, theme) {
515515

516516
# Add manual legend
517517
place <- find_panel(table)
518-
inside_legends <- legends[startsWith(names(legends), "inside")]
519-
if (length(inside_legends)) {
520-
for (i in seq_along(inside_legends)) {
521-
table <- gtable_add_grob(
522-
table, inside_legends[[i]], clip = "off",
523-
t = place$t, b = place$b, l = place$l, r = place$r,
524-
name = paste("guide-box-inside", i, sep = "-")
525-
)
526-
}
527-
} else { # to be consistent with original gtable layout
528-
table <- gtable_add_grob(
529-
table, zeroGrob(), clip = "off",
530-
t = place$t, b = place$b, l = place$l, r = place$r,
531-
name = "guide-box-inside"
532-
)
533-
}
518+
table <- gtable_add_grob(
519+
table, legends$inside %||% zeroGrob(), clip = "off",
520+
t = place$t, b = place$b, l = place$l, r = place$r,
521+
name = "guide-box-inside"
522+
)
534523
table
535524
}
536525

0 commit comments

Comments
 (0)