Skip to content

Commit 394ee59

Browse files
committed
smart distribution of null units
1 parent 5a9d4d9 commit 394ee59

File tree

1 file changed

+48
-38
lines changed

1 file changed

+48
-38
lines changed

R/guides-.R

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -502,17 +502,17 @@ Guides <- ggproto(
502502
theme$legend.spacing.x <- theme$legend.spacing.x %||% theme$legend.spacing
503503

504504
# Measure guides
505-
widths <- lapply(grobs, function(g) sum(g$widths))
506-
widths <- inject(unit.c(!!!widths))
507-
heights <- lapply(grobs, function(g) sum(g$heights))
508-
heights <- inject(unit.c(!!!heights))
505+
widths <- lapply(grobs, `[[`, "widths")
506+
heights <- lapply(grobs, `[[`, "heights")
509507

510508
# Set the justification of each legend within the legend box
511509
# First value is xjust, second value is yjust
512510
just <- valid.just(theme$legend.box.just)
513511
xjust <- just[1]
514512
yjust <- just[2]
515513

514+
margin <- theme$legend.box.margin %||% margin()
515+
516516
# setting that is different for vertical and horizontal guide-boxes.
517517
if (identical(theme$legend.box, "horizontal")) {
518518
# Set justification for each legend
@@ -523,14 +523,16 @@ Guides <- ggproto(
523523
height = heightDetails(grobs[[i]]))
524524
)
525525
}
526-
widths <- redistribute_null_units(widths, "width")
526+
spacing <- convertWidth(theme$legend.spacing.x, "cm")
527+
widths <- redistribute_null_units(widths, spacing, margin, "width")
528+
heights <- unit(height_cm(lapply(heights, sum)), "cm")
527529

528530
guides <- gtable_row(name = "guides",
529531
grobs = grobs,
530532
widths = widths, height = max(heights))
531533

532534
# add space between the guide-boxes
533-
guides <- gtable_add_col_space(guides, theme$legend.spacing.x)
535+
guides <- gtable_add_col_space(guides, spacing)
534536

535537
} else { # theme$legend.box == "vertical"
536538
# Set justification for each legend
@@ -541,18 +543,19 @@ Guides <- ggproto(
541543
width = widthDetails(grobs[[i]]))
542544
)
543545
}
544-
heights <- redistribute_null_units(heights, "height")
546+
spacing <- convertHeight(theme$legend.spacing.y, "cm")
547+
heights <- redistribute_null_units(heights, spacing, margin, "height")
548+
widths <- unit(width_cm(lapply(widths, sum)), "cm")
545549

546550
guides <- gtable_col(name = "guides",
547551
grobs = grobs,
548552
width = max(widths), heights = heights)
549553

550554
# add space between the guide-boxes
551-
guides <- gtable_add_row_space(guides, theme$legend.spacing.y)
555+
guides <- gtable_add_row_space(guides, spacing)
552556
}
553557

554558
# Add margins around the guide-boxes.
555-
margin <- theme$legend.box.margin %||% margin()
556559
guides <- gtable_add_cols(guides, margin[4], pos = 0)
557560
guides <- gtable_add_cols(guides, margin[2], pos = ncol(guides))
558561
guides <- gtable_add_rows(guides, margin[1], pos = 0)
@@ -681,38 +684,45 @@ validate_guide <- function(guide) {
681684
cli::cli_abort("Unknown guide: {guide}")
682685
}
683686

684-
redistribute_null_units <- function(unit, type = "width") {
685-
if (!any(unitType(unit) %in% c("sum", "max", "min"))) {
686-
return(unit)
687+
redistribute_null_units <- function(units, spacing, margin, type = "width") {
688+
689+
has_null <- vapply(units, function(x) any(unitType(x) == "null"), logical(1))
690+
691+
# Early exit when we needn't bother with null units
692+
if (!any(has_null)) {
693+
units <- lapply(units, sum)
694+
units <- inject(unit.c(!!!units))
695+
return(units)
687696
}
688697

689-
# Find out the absolute part of the units
690-
cms <- absolute.size(unit)
691-
cms <- switch(
692-
type,
693-
width = convertWidth( cms, "cm", valueOnly = TRUE),
694-
height = convertHeight(cms, "cm", valueOnly = TRUE)
695-
)
696-
fixed <- sum(cms)
697-
698-
# Try to grab the nulls from sum units
699-
nulls <- rep(0, length(unit))
700-
is_sum <- unitType(unit) == "sum"
701-
nulls[is_sum] <- vapply(unclass(unit)[is_sum], function(x) {
702-
if (is.null(x)) {
703-
return(0)
704-
}
705-
x <- x[[2]]
706-
sum(as.numeric(x[unitType(x) == "null"]))
698+
# Get spacing between guides and margins in absolute units
699+
size <- switch(type, width = convertWidth, height = convertHeight)
700+
spacing <- size(spacing, "cm", valueOnly = TRUE)
701+
spacing <- sum(rep(spacing, length(units) - 1))
702+
margin <- switch(type, width = margin[c(2, 4)], height = margin[c(1, 3)])
703+
margin <- sum(size(margin, "cm", valueOnly = TRUE))
704+
705+
# Get the absolute parts of the unit
706+
absolute <- vapply(units, function(u) {
707+
u <- absolute.size(u)
708+
u <- size(u, "cm", valueOnly = TRUE)
709+
sum(u)
707710
}, numeric(1))
708-
# Add the plain nulls not part of sums/min/max
709-
nulls <- nulls + as.numeric(unit) * (unitType(unit) == "null")
710-
null_sum <- sum(nulls)
711-
if (null_sum == 0) {
712-
null_sum <- 1
713-
}
714-
nulls <- nulls / null_sum
711+
absolute_sum <- sum(absolute) + spacing + margin
715712

713+
# Get the null parts of the unit
714+
relative <- rep(0, length(units))
715+
relative[has_null] <- vapply(units[has_null], function(u) {
716+
sum(as.numeric(u)[unitType(u) == "null"])
717+
}, numeric(1))
718+
relative_sum <- sum(relative)
719+
720+
if (relative_sum == 0) {
721+
return(unit(absolute, "cm"))
722+
}
716723

717-
(unit(1, "npc") - unit(fixed, "cm")) * nulls + unit(cms, "cm")
724+
relative <- relative / relative_sum
725+
available_space <- unit(1, "npc") - unit(absolute_sum, "cm")
726+
relative_space <- available_space * relative
727+
relative_space + unit(absolute, "cm")
718728
}

0 commit comments

Comments
 (0)