R ggplot: size of bins and labels in legend of binned variable

74 views Asked by At

I want the legend of a binned variable discrete_var in the bottom of my figure. I want the bins on one row. The problem is that doing this results in different sizes of bins and the labels too close to each other. How can I set the size of bins, or rotate labels to be place under and vertical to the legend bins (which might do the trick)?

shp |>
  ggplot() +
  geom_sf(aes(fill = discrete_var)) +
  scale_fill_brewer(palette = 'Purples', direction = -1, na.value="grey", drop=FALSE) +
  coord_sf(expand = FALSE) +
  theme(legend.position = "bottom") +
  guides(fill=guide_legend(nrow=1,byrow=TRUE, label.position = "bottom"))

enter image description here

This is what I want, but in the bottom of the figure:

enter image description here

2

There are 2 answers

0
Andy Baxter On BEST ANSWER

Making the legend key width wider would be one approach with legend.key.width = unit(2, "cm"):

library(tidyverse)
library(sf)
#> Linking to GEOS 3.11.2, GDAL 3.6.2, PROJ 9.2.0; sf_use_s2() is TRUE

map <- map_data("world")

mapcols <- map |>
  count(region) |>
  mutate(
    discrete_var = cut(40 * n / max(n), breaks = seq(0, 40, 5)),
    discrete_var = gsub("\\((\\d+),(\\d+)\\]", "\\1 to \\2", discrete_var)
  )

shp <-   st_as_sf(maps::map('world', plot = FALSE, fill = TRUE))

shp |> 
  left_join(mapcols, by = join_by(ID == region)) |> 
  ggplot() +
  geom_sf(aes(fill = discrete_var)) +
  scale_fill_brewer(palette = 'Purples', direction = -1, na.value="grey", drop=FALSE) +
  coord_sf(expand = FALSE) +
  theme(legend.position = "bottom", legend.key.width = unit(2, "cm")) +
  guides(fill=guide_legend(nrow=1,byrow=TRUE, label.position = "bottom"))

Or to put the text at an angle use legend.text = element_text(angle = 45, vjust = 0.5):


shp |> 
  left_join(mapcols, by = join_by(ID == region)) |> 
  ggplot() +
  geom_sf(aes(fill = discrete_var)) +
  scale_fill_brewer(palette = 'Purples', direction = -1, na.value="grey", drop=FALSE) +
  coord_sf(expand = FALSE) +
  theme(legend.position = "bottom", legend.text = element_text(angle = 45, vjust = 0.5)) +
  guides(fill=guide_legend(nrow=1,byrow=TRUE, label.position = "bottom"))

Finally, to make vertical, substitute your final line with theme(legend.position = "bottom", legend.direction = "vertical"):


shp |> 
  left_join(mapcols, by = join_by(ID == region)) |> 
  ggplot() +
  geom_sf(aes(fill = discrete_var)) +
  scale_fill_brewer(palette = 'Purples', direction = -1, na.value="grey", drop=FALSE) +
  coord_sf(expand = FALSE) +
  theme(legend.position = "bottom", legend.direction = "vertical") 

0
Allan Cameron On

Another option is to increase keywidth inside guide

shp |>
  ggplot() +
  geom_sf(aes(fill = discrete_var)) +
  scale_fill_brewer(palette = 'Purples', direction = -1, 
                    na.value = "grey", drop = FALSE) +
  coord_sf(expand = FALSE) +
  theme(legend.position = "bottom") +
  guides(fill = guide_legend(nrow = 1, byrow = TRUE, label.position = "bottom",
                             keywidth = unit(2, 'cm')))

enter image description here


Data used

library(rnaturalearth)
library(sf)
library(tidyverse)

set.seed(1)

shp <- ne_countries(returnclass = 'sf') %>%
  mutate(discrete_var = cut(runif(n(), -6, 17),
                            breaks = c(-6, -3, 0, 3, 6, 8, 10, 12, 14, 17),
                            labels = c('< -3', '-3 to 0', '0 to 3',
                                       '3 to 6', '6 to 8', '8 to 10',
                                       '10 to 12', '12 to 14', '>14'))) %>%
  mutate(discrete_var = if_else(name %in% c('Antarctica', 'Greenland'), NA, 
                               discrete_var))