@@ -514,74 +514,86 @@ Guides <- ggproto(
514
514
515
515
# we grouped the legends by the positions, for inside legends, they'll be
516
516
# 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" ) ) {
519
519
# the actual inside position and justification can be set in each guide
520
520
# by `theme` argument, here, we won't use `calc_element()` which will
521
521
# use inherits from `legend.justification` or `legend.position`, we only
522
522
# follow the inside elements from the guide theme
523
523
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 ]]
532
531
)
533
532
}
534
533
}
535
534
536
535
positions <- positions [keep ]
537
536
inside_positions <- inside_positions [keep ]
538
537
inside_justs <- inside_justs [keep ]
539
- groups <- groups [keep ]
540
538
541
539
# 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
553
548
554
549
# Set spacing
555
550
theme $ legend.spacing <- theme $ legend.spacing %|| % unit(0.5 , " lines" )
556
551
theme $ legend.spacing.y <- calc_element(" legend.spacing.y" , theme )
557
552
theme $ legend.spacing.x <- calc_element(" legend.spacing.x" , theme )
558
553
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
567
588
},
568
589
569
590
# Render the guides into grobs
570
- draw = function (self , theme , positions = NULL , direction = NULL ,
591
+ draw = function (self , theme , positions , direction = NULL ,
571
592
params = self $ params ,
572
593
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 ))
578
595
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"
585
597
}
586
598
587
599
grobs <- vector(" list" , length(guides ))
@@ -597,8 +609,8 @@ Guides <- ggproto(
597
609
# here, we put `inside_position` and `inside_just` in the last, so that it
598
610
# won't break current implement of patchwork, which depends on the top three
599
611
# 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
+
602
614
if (is.zero(grobs ) || length(grobs ) == 0 ) {
603
615
return (zeroGrob())
604
616
}
@@ -626,36 +638,19 @@ Guides <- ggproto(
626
638
stretch_x <- any(unlist(lapply(widths , unitType )) == " null" )
627
639
stretch_y <- any(unlist(lapply(heights , unitType )) == " null" )
628
640
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
+
629
645
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 ]
652
650
global_margin <- margin()
653
651
} 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 ]
659
654
# Legends to the side of the plot need a margin for justification
660
655
# relative to the plot panel
661
656
global_margin <- margin(
@@ -697,7 +692,7 @@ Guides <- ggproto(
697
692
698
693
# Set global justification
699
694
vp <- viewport(
700
- x = x , y = y , just = global_just ,
695
+ x = global_xjust , y = global_yjust , just = global_just ,
701
696
height = max(heights ),
702
697
width = vp_width
703
698
)
@@ -735,7 +730,7 @@ Guides <- ggproto(
735
730
736
731
# Set global justification
737
732
vp <- viewport(
738
- x = x , y = y , just = global_just ,
733
+ x = global_xjust , y = global_yjust , just = global_just ,
739
734
height = vp_height ,
740
735
width = max(widths )
741
736
)
@@ -776,7 +771,6 @@ Guides <- ggproto(
776
771
guides $ name <- " guide-box"
777
772
guides
778
773
},
779
-
780
774
# # Utilities -----------------------------------------------------------------
781
775
782
776
print = function (self ) {
0 commit comments