@@ -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 ) {
0 commit comments