192

Is there a way to change the spacing between legend items in ggplot2? I currently have

legend.position ="top" 

which automatically produces a horizontal legend. However, the spacing of the items is very close together and I am wondering how to space them farther apart.

David Arenburg
92.4k18 gold badges145 silver badges202 bronze badges
asked Jul 6, 2012 at 17:26
3
  • It would be useful to have a current solution to this now that opts is depreciated. Commented Jun 3, 2014 at 9:30
  • Here: pastebin.com/NnxMiTeH Commented Dec 18, 2017 at 20:13
  • 3
    Tung's answer, currently at the bottom of this thread, has a July 2018 update. Bugs have been fixed and hacky workarounds like the one in the pastebin above are no longer needed. Commented Sep 27, 2018 at 15:50

9 Answers 9

185

ggplot2 v3.0.0 released in July 2018 has working options to modify legend.spacing.x, legend.spacing.y and legend.text.

Update Dec 2021 - to make legend.spacing.y work, you will need to set byrow = TRUE in the corresponding guide_legend. See also this thread. Example below.

Example: Increase horizontal spacing between legend keys

library(ggplot2)
ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) + 
 geom_bar() +
 coord_flip() +
 scale_fill_brewer("Cyl", palette = "Dark2") +
 theme_minimal(base_size = 14) +
 theme(legend.position = 'top', 
 legend.spacing.x = unit(1.0, 'cm'))

Note: If you only want to expand the spacing to the right of the legend text, use stringr::str_pad()

Example: Increase vertical spacing (mind byrow = TRUE)

library(ggplot2)
ggplot(mtcars, aes(y = factor(cyl), fill = factor(cyl))) + 
 geom_bar() +
 theme(legend.spacing.y = unit(1.0, 'cm')) +
 ## important additional element
 guides(fill = guide_legend(byrow = TRUE))

Example: Move the legend key labels to the bottom and increase vertical spacing

ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) + 
 geom_bar() +
 coord_flip() +
 scale_fill_brewer("Cyl", palette = "Dark2") +
 theme_minimal(base_size = 14) +
 theme(legend.position = 'top', 
 legend.spacing.x = unit(1.0, 'cm'),
 legend.text = element_text(margin = margin(t = 10))) +
 guides(fill = guide_legend(title = "Cyl",
 label.position = "bottom",
 title.position = "left", title.vjust = 1)) 

Example: for scale_fill_xxx & guide_colorbar

ggplot(mtcars, aes(mpg, wt)) +
 geom_point(aes(fill = hp), pch = I(21), size = 5)+
 scale_fill_viridis_c(guide = FALSE) +
 theme_classic(base_size = 14) +
 theme(legend.position = 'top', 
 legend.spacing.x = unit(0.5, 'cm'),
 legend.text = element_text(margin = margin(t = 10))) +
 guides(fill = guide_colorbar(title = "HP",
 label.position = "bottom",
 title.position = "left", title.vjust = 1,
 # draw border around the legend
 frame.colour = "black",
 barwidth = 15,
 barheight = 1.5)) 

The below is obsolete, but is left for curious people.

For vertical legends, settinglegend.key.size only increases the size of the legend keys, not the vertical space between them

ggplot(mtcars) +
 aes(x = cyl, fill = factor(cyl)) +
 geom_bar() +
 scale_fill_brewer("Cyl", palette = "Dark2") +
 theme_minimal(base_size = 14) +
 theme(legend.key.size = unit(1, "cm"))

In order to increase the distance between legend keys, modification of the legend-draw.r function is needed. See this issue for more info

# function to increase vertical spacing between legend keys
# @clauswilke
draw_key_polygon3 <- function(data, params, size) {
 lwd <- min(data$size, min(size) / 4)
 
 grid::rectGrob(
 width = grid::unit(0.6, "npc"),
 height = grid::unit(0.6, "npc"),
 gp = grid::gpar(
 col = data$colour,
 fill = alpha(data$fill, data$alpha),
 lty = data$linetype,
 lwd = lwd * .pt,
 linejoin = "mitre"
 ))
}
### this step is not needed anymore per tjebo's comment below
### see also: https://ggplot2.tidyverse.org/reference/draw_key.html
# register new key drawing function, 
# the effect is global & persistent throughout the R session
# GeomBar$draw_key = draw_key_polygon3
ggplot(mtcars) +
 aes(x = cyl, fill = factor(cyl)) +
 geom_bar(key_glyph = "polygon3") +
 scale_fill_brewer("Cyl", palette = "Dark2") +
 theme_minimal(base_size = 14) +
 theme(legend.key = element_rect(color = NA, fill = NA),
 legend.key.size = unit(1.5, "cm")) +
 theme(legend.title.align = 0.5)
tjebo
24.1k8 gold badges73 silver badges108 bronze badges
answered May 31, 2018 at 2:39
Sign up to request clarification or add additional context in comments.

4 Comments

Your function to increase vertical spacing between legend keys is the only solution I've found that works exactly as I desire and with ease of use. Thanks!
@tjebo which version is that? I'm using ggplot2 3.3.3 and when I try to use it like this geom_bar(..., key_glyph = "polygon3") I get an object 'draw_key_polygon3' of mode 'function' was not found error.
@Anke you still need to define the function as per Tungs answer
Update 2024: You now need to put legend.key.spacing.x or legend.key.spacing.y with ggplot2 3.5.0 (tidyverse.org/blog/2024/02/ggplot2-3-5-0-legends). Also for me, the legend.key.spacing.y worked without having to put byrow = TRUE
85

I think the best option is to use guide_legend within guides:

p + guides(fill=guide_legend(
 keywidth=0.1,
 keyheight=0.1,
 default.unit="inch")
 )

Note the use of default.unit , no need to load grid package.

answered Jul 15, 2015 at 6:03

2 Comments

This may work for horizontal legends. However, for my vertical legend to the right of the plot, this only increases the key' s height, not the spacing between keys. My legend keys are still very close to each other.
As Mushin says, this misses the point, as with other answers, if the legend is VERTICAL it stretches the legend keys (e.g. the line segments) without padding the space between keys.
55

To add spacing between entries in a legend, adjust the margins of the theme element legend.text.

To add 30pt of space to the right of each legend label (may be useful for a horizontal legend):

p + theme(legend.text = element_text(
 margin = margin(r = 30, unit = "pt")))

To add 30pt of space to the left of each legend label (may be useful for a vertical legend):

p + theme(legend.text = element_text(
 margin = margin(l = 30, unit = "pt")))

for a ggplot2 object p. The keywords are legend.text and margin.

[Note about edit: When this answer was first posted, there was a bug. The bug has now been fixed]

PatrickT
10.6k9 gold badges83 silver badges117 bronze badges
answered Mar 21, 2017 at 22:36

2 Comments

See also Tung's answer for a July 2018 update on these matters.
If you want to add space between items in a vertical legend on the bottom and top of each entry, try something like margin = margin(t = 5, b = 5, unit = "pt").
49

A simple fix that I use to add space in horizontal legends, simply add spaces in the labels (see extract below):

 scale_fill_manual(values=c("red","blue","white"),
 labels=c("Label of category 1 ",
 "Label of category 2 ",
 "Label of category 3"))
answered Mar 7, 2015 at 14:45

3 Comments

This is the only answer so far which deals with the question! This might be helpful in case of many entries: scale_fill_manual(values=values, labels=setNames(paste(labels, " "), entries)).
Technically not very nice, especially when you have to introduce those spaces into factor levels, but it's the only working solution so for.
Or we can use str_pad to make life a little bit easier
41

Now that opts is deprecated in ggplot2 package, function theme should be used instead:

library(grid) # for unit()
... + theme(legend.key.height=unit(3,"line"))
... + theme(legend.key.width=unit(3,"line"))
answered Nov 17, 2014 at 11:29

2 Comments

This solution changes the height/width of the boxes as opposed to the spacing between them.
I needed to decrease the spacing between vertical legend items. Setting legend.spacing.y to a negative value didn't work but legend.key.size=unit(.8,"lines") did.
32

Looks like the best approach (in 2018) is to use legend.key.size under the theme object. (e.g., see here).

#Set-up:
 library(ggplot2)
 library(gridExtra)
 gp <- ggplot(data = mtcars, aes(mpg, cyl, colour = factor(cyl))) +
 geom_point()

This is real easy if you are using theme_bw():

 gpbw <- gp + theme_bw()
#Change spacing size:
 g1bw <- gpbw + theme(legend.key.size = unit(0, 'lines'))
 g2bw <- gpbw + theme(legend.key.size = unit(1.5, 'lines'))
 g3bw <- gpbw + theme(legend.key.size = unit(3, 'lines'))
 grid.arrange(g1bw,g2bw,g3bw,nrow=3)

enter image description here

However, this doesn't work quite so well otherwise (e.g., if you need the grey background on your legend symbol):

 g1 <- gp + theme(legend.key.size = unit(0, 'lines'))
 g2 <- gp + theme(legend.key.size = unit(1.5, 'lines'))
 g3 <- gp + theme(legend.key.size = unit(3, 'lines'))
 grid.arrange(g1,g2,g3,nrow=3)
#Notice that the legend symbol squares get bigger (that's what legend.key.size does). 
#Let's [indirectly] "control" that, too:
 gp2 <- g3
 g4 <- gp2 + theme(legend.key = element_rect(size = 1))
 g5 <- gp2 + theme(legend.key = element_rect(size = 3))
 g6 <- gp2 + theme(legend.key = element_rect(size = 10))
 grid.arrange(g4,g5,g6,nrow=3) #see picture below, left

Notice that white squares begin blocking legend title (and eventually the graph itself if we kept increasing the value).

 #This shows you why:
 gt <- gp2 + theme(legend.key = element_rect(size = 10,color = 'yellow' ))

enter image description here

I haven't quite found a work-around for fixing the above problem... Let me know in the comments if you have an idea, and I'll update accordingly!

  • I wonder if there is some way to re-layer things using $layers...
answered May 29, 2018 at 22:40

1 Comment

Make the legend.key transparent: theme(legend.key = element_rect(size = 30,color=alpha("transparent",0)))
25

As of ggplot2 3.5.0 (2024), legend spacing has been reworked. For overview purposes, I'll repeat the graphic from the release blog.

enter image description here

To manipulate spacing between different legends, use the legend.spacing setting.

library(ggplot2)
p <- ggplot(mpg, aes(displ, hwy, colour = class, shape = factor(cyl))) +
 geom_point() +
 guides(colour = guide_legend(ncol = 2))
p + theme(
 legend.spacing = unit(1, "cm")
)

To control spacing of key-label pairs within legends, uses the legend.key.spacing settings. For historical reasons the y-spacing does not inherit from the main legend.key.spacing setting, so you'd have to explicitly state legend.key.spacing.y in that case.

p + theme(
 legend.key.spacing.x = unit(1, "cm"),
 legend.key.spacing.y = unit(1, "cm")
)

To manipulate the spacing between the labels and the keys, use the text margins.

p + theme(
 legend.text = element_text(margin = margin(l = 1, unit = "cm"))
)

Created on 2024年02月27日 with reprex v2.1.0

answered Feb 27, 2024 at 12:43

Comments

17

From Koshke's work on ggplot2 and his blog (Koshke's blog)

... + theme(legend.key.height=unit(3,"line")) # Change 3 to X
... + theme(legend.key.width=unit(3,"line")) # Change 3 to X

Type theme_get() in the console to see other editable legend attributes.

PatrickT
10.6k9 gold badges83 silver badges117 bronze badges
answered Jul 6, 2012 at 18:36

3 Comments

Thanks for the suggestion and link to Koshke's blog! Unfortunately however this seems to change the size of the boxes but not the spacing between items.
You may be able to "fake" it with some type of overlaying grob. But I don't think theres a way to get extra spacing inside of the legend. This is the only mention of it I could find in ggplot2's mailing list: groups.google.com/forum/?fromgroups#!topic/ggplot2/PhkJpP8zJuM
I can use this to increase spacing between legends successfully. Using negative numbers helped decrease spacing between legends.
6

Use any of these

legend.spacing = unit(1,"cm")
legend.spacing.x = unit(1,"cm")
legend.spacing.y = unit(1,"cm")
answered Nov 26, 2017 at 9:30

1 Comment

My issue with this is that the labels for the legends end up occupying the middle portion of the extra white space, as opposed to generating space between the colored boxes of the legend. I've found the answer offered here about padding under theme(legend.text) to be the most satisfying for this.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.