@@ -502,17 +502,17 @@ Guides <- ggproto(
502
502
theme $ legend.spacing.x <- theme $ legend.spacing.x %|| % theme $ legend.spacing
503
503
504
504
# 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" )
509
507
510
508
# Set the justification of each legend within the legend box
511
509
# First value is xjust, second value is yjust
512
510
just <- valid.just(theme $ legend.box.just )
513
511
xjust <- just [1 ]
514
512
yjust <- just [2 ]
515
513
514
+ margin <- theme $ legend.box.margin %|| % margin()
515
+
516
516
# setting that is different for vertical and horizontal guide-boxes.
517
517
if (identical(theme $ legend.box , " horizontal" )) {
518
518
# Set justification for each legend
@@ -523,14 +523,16 @@ Guides <- ggproto(
523
523
height = heightDetails(grobs [[i ]]))
524
524
)
525
525
}
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" )
527
529
528
530
guides <- gtable_row(name = " guides" ,
529
531
grobs = grobs ,
530
532
widths = widths , height = max(heights ))
531
533
532
534
# 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 )
534
536
535
537
} else { # theme$legend.box == "vertical"
536
538
# Set justification for each legend
@@ -541,18 +543,19 @@ Guides <- ggproto(
541
543
width = widthDetails(grobs [[i ]]))
542
544
)
543
545
}
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" )
545
549
546
550
guides <- gtable_col(name = " guides" ,
547
551
grobs = grobs ,
548
552
width = max(widths ), heights = heights )
549
553
550
554
# 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 )
552
556
}
553
557
554
558
# Add margins around the guide-boxes.
555
- margin <- theme $ legend.box.margin %|| % margin()
556
559
guides <- gtable_add_cols(guides , margin [4 ], pos = 0 )
557
560
guides <- gtable_add_cols(guides , margin [2 ], pos = ncol(guides ))
558
561
guides <- gtable_add_rows(guides , margin [1 ], pos = 0 )
@@ -681,38 +684,45 @@ validate_guide <- function(guide) {
681
684
cli :: cli_abort(" Unknown guide: {guide}" )
682
685
}
683
686
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 )
687
696
}
688
697
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 )
707
710
}, 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
715
712
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
+ }
716
723
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" )
718
728
}
0 commit comments