4242# ' @param keyheight A numeric or a [grid::unit()] object specifying
4343# ' the height of the legend key. Default value is `legend.key.height` or
4444# ' `legend.key.size` in [theme()].
45+ # ' @param key.spacing,key.spacing.x,key.spacing.y A numeric or [grid::unit()]
46+ # ' object specifying the distance between key-label pairs in the horizontal
47+ # ' direction (`key.spacing.x`), vertical direction (`key.spacing.y`) or both
48+ # ' (`key.spacing`).
4549# ' @param direction A character string indicating the direction of the guide.
4650# ' One of "horizontal" or "vertical."
4751# ' @param default.unit A character string indicating [grid::unit()]
@@ -143,6 +147,9 @@ guide_legend <- function(
143147 # Key size
144148 keywidth = NULL ,
145149 keyheight = NULL ,
150+ key.spacing = NULL ,
151+ key.spacing.x = NULL ,
152+ key.spacing.y = NULL ,
146153
147154 # General
148155 direction = NULL ,
@@ -156,12 +163,24 @@ guide_legend <- function(
156163 ...
157164) {
158165 # Resolve key sizes
159- if (! inherits( keywidth , c( " NULL " , " unit" ))) {
166+ if (! (is.null( keywidth ) || is. unit( keywidth ))) {
160167 keywidth <- unit(keywidth , default.unit )
161168 }
162- if (! inherits( keyheight , c( " NULL " , " unit" ))) {
169+ if (! (is.null( keyheight ) || is. unit( keyheight ))) {
163170 keyheight <- unit(keyheight , default.unit )
164171 }
172+
173+ # Resolve spacing
174+ key.spacing.x <- key.spacing.x %|| % key.spacing
175+ if (! is.null(key.spacing.x ) || is.unit(key.spacing.x )) {
176+ key.spacing.x <- unit(key.spacing.x , default.unit )
177+ }
178+ key.spacing.y <- key.spacing.y %|| % key.spacing
179+ if (! is.null(key.spacing.y ) || is.unit(key.spacing.y )) {
180+ key.spacing.y <- unit(key.spacing.y , default.unit )
181+ }
182+
183+
165184 if (! is.null(title.position )) {
166185 title.position <- arg_match0(title.position , .trbl )
167186 }
@@ -187,6 +206,8 @@ guide_legend <- function(
187206 # Key size
188207 keywidth = keywidth ,
189208 keyheight = keyheight ,
209+ key.spacing.x = key.spacing.x ,
210+ key.spacing.y = key.spacing.y ,
190211
191212 # General
192213 direction = direction ,
@@ -226,9 +247,10 @@ GuideLegend <- ggproto(
226247
227248 keywidth = NULL ,
228249 keyheight = NULL ,
250+ key.spacing.x = NULL ,
251+ key.spacing.y = NULL ,
229252
230253 # General
231- direction = NULL ,
232254 override.aes = list (),
233255 nrow = NULL ,
234256 ncol = NULL ,
@@ -249,9 +271,6 @@ GuideLegend <- ggproto(
249271 elements = list (
250272 background = " legend.background" ,
251273 margin = " legend.margin" ,
252- spacing = " legend.spacing" ,
253- spacing.x = " legend.spacing.x" ,
254- spacing.y = " legend.spacing.y" ,
255274 key = " legend.key" ,
256275 key.height = " legend.key.height" ,
257276 key.width = " legend.key.width" ,
@@ -436,13 +455,35 @@ GuideLegend <- ggproto(
436455 elements $ text $ size %|| % 11
437456 gap <- unit(gap * 0.5 , " pt" )
438457 # Should maybe be elements$spacing.{x/y} instead of the theme's spacing?
439- elements $ hgap <- width_cm( theme $ legend.spacing.x %|| % gap )
440- elements $ vgap <- height_cm(theme $ legend.spacing.y %|| % gap )
458+
459+ if (params $ direction == " vertical" ) {
460+ # For backward compatibility, vertical default is no spacing
461+ vgap <- params $ key.spacing.y %|| % unit(0 , " pt" )
462+ } else {
463+ vgap <- params $ key.spacing.y %|| % gap
464+ }
465+
466+ elements $ hgap <- width_cm( params $ key.spacing.x %|| % gap )
467+ elements $ vgap <- height_cm(vgap )
441468 elements $ padding <- convertUnit(
442469 elements $ margin %|| % margin(),
443470 " cm" , valueOnly = TRUE
444471 )
445472
473+ # When no explicit margin has been set, either in this guide or in the
474+ # theme, we set a default text margin to leave a small gap in between
475+ # the label and the key.
476+ if (is.null(params $ label.theme $ margin %|| % theme $ legend.text $ margin ) &&
477+ ! inherits(elements $ text , " element_blank" )) {
478+ i <- match(params $ label.position , .trbl [c(3 , 4 , 1 , 2 )])
479+ elements $ text $ margin [i ] <- elements $ text $ margin [i ] + gap
480+ }
481+ if (is.null(params $ title.theme $ margin %|| % theme $ legend.title $ margin ) &&
482+ ! inherits(elements $ title , " element_blank" )) {
483+ i <- match(params $ title.position , .trbl [c(3 , 4 , 1 , 2 )])
484+ elements $ title $ margin [i ] <- elements $ title $ margin [i ] + gap
485+ }
486+
446487 # Evaluate backgrounds early
447488 if (! is.null(elements $ background )) {
448489 elements $ background <- ggname(
@@ -527,22 +568,23 @@ GuideLegend <- ggproto(
527568 hgap <- elements $ hgap %|| % 0
528569 widths <- switch (
529570 params $ label.position ,
530- " left" = list (label_widths , hgap , widths , hgap ),
531- " right" = list (widths , hgap , label_widths , hgap ),
532- list (pmax(label_widths , widths ), hgap * ( ! byrow ) )
571+ " left" = list (label_widths , widths , hgap ),
572+ " right" = list (widths , label_widths , hgap ),
573+ list (pmax(label_widths , widths ), hgap )
533574 )
534575 widths <- head(vec_interleave(!!! widths ), - 1 )
535576
536577 vgap <- elements $ vgap %|| % 0
537578 heights <- switch (
538579 params $ label.position ,
539- " top" = list (label_heights , vgap , heights , vgap ),
540- " bottom" = list (heights , vgap , label_heights , vgap ),
541- list (pmax(label_heights , heights ), vgap * ( byrow ) )
580+ " top" = list (label_heights , heights , vgap ),
581+ " bottom" = list (heights , label_heights , vgap ),
582+ list (pmax(label_heights , heights ), vgap )
542583 )
543584 heights <- head(vec_interleave(!!! heights ), - 1 )
544585
545586 has_title <- ! is.zero(grobs $ title )
587+
546588 if (has_title ) {
547589 # Measure title
548590 title_width <- width_cm(grobs $ title )
@@ -551,14 +593,14 @@ GuideLegend <- ggproto(
551593 # Combine title with rest of the sizes based on its position
552594 widths <- switch (
553595 params $ title.position ,
554- " left" = c(title_width , hgap , widths ),
555- " right" = c(widths , hgap , title_width ),
596+ " left" = c(title_width , widths ),
597+ " right" = c(widths , title_width ),
556598 c(widths , max(0 , title_width - sum(widths )))
557599 )
558600 heights <- switch (
559601 params $ title.position ,
560- " top" = c(title_height , vgap , heights ),
561- " bottom" = c(heights , vgap , title_height ),
602+ " top" = c(title_height , heights ),
603+ " bottom" = c(heights , title_height ),
562604 c(heights , max(0 , title_height - sum(heights )))
563605 )
564606 }
@@ -595,20 +637,20 @@ GuideLegend <- ggproto(
595637 switch (
596638 params $ label.position ,
597639 " top" = {
598- key_row <- key_row * 2
599- label_row <- label_row * 2 - 2
640+ key_row <- key_row + df $ R
641+ label_row <- key_row - 1
600642 },
601643 " bottom" = {
602- key_row <- key_row * 2 - 2
603- label_row <- label_row * 2
644+ key_row <- key_row + df $ R - 1
645+ label_row <- key_row + 1
604646 },
605647 " left" = {
606- key_col <- key_col * 2
607- label_col <- label_col * 2 - 2
648+ key_col <- key_col + df $ C
649+ label_col <- key_col - 1
608650 },
609651 " right" = {
610- key_col <- key_col * 2 - 2
611- label_col <- label_col * 2
652+ key_col <- key_col + df $ C - 1
653+ label_col <- key_col + 1
612654 }
613655 )
614656
@@ -617,8 +659,8 @@ GuideLegend <- ggproto(
617659 switch (
618660 params $ title.position ,
619661 " top" = {
620- key_row <- key_row + 2
621- label_row <- label_row + 2
662+ key_row <- key_row + 1
663+ label_row <- label_row + 1
622664 title_row <- 2
623665 title_col <- seq_along(sizes $ widths ) + 1
624666 },
@@ -627,8 +669,8 @@ GuideLegend <- ggproto(
627669 title_col <- seq_along(sizes $ widths ) + 1
628670 },
629671 " left" = {
630- key_col <- key_col + 2
631- label_col <- label_col + 2
672+ key_col <- key_col + 1
673+ label_col <- label_col + 1
632674 title_row <- seq_along(sizes $ heights ) + 1
633675 title_col <- 2
634676 },
0 commit comments