Post #23. ggplot Legend Tips Series No.8: The nuts and bolts of legend item spacing

2023 Legend Tips Series

Here are all the nuts and bolts you need for working on legend item spacing!

Gen-Chang Hsu
2023-01-13

Introduction

Welcome to my first blog post in 2023! I have been slacking off a little bit lately and feel so glad to ring in the new year with another Legend Tips Series post.

In this post, I will show you how to adjust the spacing between discrete legend items (legend title, keys, and labels) as well as between multiple legends. This is going to be a handy one and let’s get to it!

The nuts and bolts of legend spacing

1. Single discrete legend

We’ll start with a single legend: There are four main arguments in theme() when it comes to adjusting the spacing between legend title, keys, and labels: legend.title, legend.text, legend.spacing.x, and legend.spacing.y. I’ll demonstrate them in the following section for a vertical legend, a horizontal legend, and a legend with a matrix layout.


(1) Vertical legend

To adjust the spacing between legend title and the first legend key, change the bottom margin of the title by specifying margin = margin(b = ) in the legend.title argument. To adjust the spacing between legend keys and labels, use legend.spacing.x = unit() and specify an appropriate value. Similarly, to adjust the spacing between legend keys, use legend.spacing.y = unit() and specify an appropriate value. Note that for legend.spacing.y = unit() to work, you MUST specify byrow = T in the corresponding guides (in this case “color” guide). Otherwise, nothing will happen!

library(tidyverse)

### Default plot
P_vertical_default <- ggplot(data = iris) + 
  geom_point(aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + 
  geom_smooth(aes(x = Sepal.Length, y = Sepal.Width, color = Species, fill = after_scale(color)), method = "lm", se = T) + 
  scale_color_brewer(palette = "Set1") +
  labs(x = "Sepal length", y = "Sepal width") + 
  theme_classic(base_size = 13)

### Adjust the spacing between legend items
P_vertical_adjusted <- P_vertical_default + 
  theme(legend.title = element_text(margin = margin(b = 10)),  # adjust the spacing between the legend title and the first legend key 
        legend.spacing.x = unit(0.2, "inch"),  # adjust the horizontal spacing between legend keys and labels
        legend.spacing.y = unit(0.2, "inch")) +  # adjust the vertical spacing between legend keys
  guides(color = guide_legend(byrow = T))  # "byrow = T" is necessary for "legend.spacing.y" to work for vertical legends  

P_vertical_default; P_vertical_adjusted


(2) Horizontal layout

Similar to vertical legends, to adjust the spacing between legend title and the first legend key, change the right margin of the title by specifying margin = margin(r = ) in the legend.title argument. To adjust the spacing between legend keys and labels, use legend.spacing.x = unit() and specify an appropriate value. Additionally, you can use legend.text = element_text(margin = margin(r = )) to fine tune the spacing between the label (e.g., the label “setosa”) and the adjacent key (e.g., the blue key for “versicolor”). legend.spacing.y = unit() is not relevant to horizontal legends here.

### Default plot
P_horizontal_default <- ggplot(data = iris) + 
  geom_point(aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + 
  geom_smooth(aes(x = Sepal.Length, y = Sepal.Width, color = Species, fill = after_scale(color)), method = "lm", se = T) + 
  scale_color_brewer(palette = "Set1") +
  labs(x = "Sepal length", y = "Sepal width") + 
  theme_classic(base_size = 13) + 
  theme(legend.position = "top",
        legend.direction = "horizontal")

### Adjust the spacing between legend items
P_horizontal_adjusted <- P_horizontal_default + 
  theme(legend.title = element_text(margin = margin(r = 10)),  # adjust the spacing between legend title and the first legend key
        legend.spacing.x = unit(0.2, "inch"),  # adjust the spacing between legend keys and labels
        legend.text = element_text(margin = margin(r = 15)))  # fine tune the spacing between legend labels and adjacent legend keys
        
P_horizontal_default; P_horizontal_adjusted


(3) Matrix layout

We’ve seen both vertical and horizontal legends, how about a combination of both (matrix layout)? That’s actually easy-peasy: just put everything we did earlier together!

### Default plot
P_matrix_default <- ggplot(data = iris) + 
  geom_point(aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + 
  geom_smooth(aes(x = Sepal.Length, y = Sepal.Width, color = Species, fill = after_scale(color)), method = "lm", se = T) + 
  scale_color_brewer(palette = "Set1") +
  labs(x = "Sepal length", y = "Sepal width") + 
  theme_classic(base_size = 13) + 
  theme(legend.position = "top",
        legend.direction = "horizontal") + 
  guides(color = guide_legend(nrow = 2, ncol = 2, byrow = T))

### Adjust the spacing between legend items
P_matrix_adjusted <- P_matrix_default + 
  theme(legend.title = element_text(margin = margin(r = 10)),  # adjust the spacing between legend title and the first legend key
        legend.spacing.x = unit(0.2, "inch"),  # adjust the horizontal spacing between legend keys and labels
        legend.spacing.y = unit(0.2, "inch"),  # adjust the vertical spacing between legend keys
        legend.text = element_text(margin = margin(r = 15)))  # fine tune the spacing between the legend label and the adjacent legend key
        
P_matrix_default; P_matrix_adjusted

Multiple legends

In the previous section, we focused on adjusting the spacing between the items within a legend. What if we have multiple legends and we want to change the spacing between them? Let’s see an example now:

### Default plot
P_multiple_default <- ggplot(data = iris) + 
  geom_point(aes(x = Sepal.Length, y = Sepal.Width, color = Species, alpha = Sepal.Length*Sepal.Width)) + 
  geom_smooth(aes(x = Sepal.Length, y = Sepal.Width, color = Species, fill = after_scale(color)), method = "lm", se = T) + 
  scale_color_brewer(palette = "Set1") +
  scale_alpha_continuous(name = "Sepal L*W") +
  labs(x = "Sepal length", y = "Sepal width") + 
  theme_classic(base_size = 13)

P_multiple_default

Say we would like to increase the spacing between the two legends. We can use the same hack as before by increasing the top margin of the legend title, which will create more white space above both the title “Sepal L*W” and “Species”. However, because of this extra white space, the legends will be squeezed down a bit. To solve this problem, I used legend.box.margin = margin(b = 50) to increase the margin below the legend box to push the legends up.

### Adjust the spacing between legends
P_multiple_adjusted <- P_multiple_default +
  theme(legend.title = element_text(margin = margin(t = 30)),  # create more white space above the legend titles
        legend.box.margin = margin(b = 50))  # increase the margin below the legend box to push the legends up

P_multiple_adjusted

Summary

To recap, we learned how to adjust the spacing between the title, keys, and labels within a legend, as well as the spacing between multiple legends. Next time when you’re making ggplots, remember to apply these tips to polish your figure!

Hope you learn something useful from this post and don’t forget to leave your comments and suggestions below if you have any!

Corrections

If you see mistakes or want to suggest changes, please create an issue on the source repository.