NewBee
NewBee

Reputation: 1040

Modify the size of each legend icon in ggplot2

I am using ggplot/usmap libraries to plot highly skewed data onto a map.

Because the data is so skewed, I created uneven interval brackets. See below.

My code:

library(dplyr)
library(tidyverse)
library(usmap)
library(ggplot2)
library(readxl)
library(rgdal)

plot_usmap(regions = "states",
           # fill = 'orange',
           labels = TRUE) +
  
  geom_point(data = grant_sh,
             size = 5,
             aes(x = x,
                 y = y,
                 color = funding_cat)) +

  theme(
    legend.title = element_text(size = 16),
    #change legend title font size
    legend.text = element_text(size = 14),
    #change legend text font size
    legend.position = 'left',
    plot.title = element_text(size = 22),
    plot.subtitle = element_text(size = 16)
  )  + #+
  scale_color_manual(
    values = c('#D4148C',  # pink muesaum
               '#049CFC',   #library,blue
               '#1C8474',
               '#7703fC'),
    name = "Map Key",
    labels = c(
      '$1,500 - $4,000 (n = 7)',
      '$4,001 - $6,000 (n = 12)',
      '$6,001 - $20,000 (n = 6)',
      '$20,001 - $40,000 (n = 25)'
    )
  ) +
  guides(colour = guide_legend(override.aes = list(size = 3)))

Current output:

enter image description here

Desired output: I would like to adjust the legend key to reflect the size of each interval. So, for example 1500-400 would be the smallest icon, and 20,001-40,000 would be the largest.

I want to do this so that the viewer immediately knows that the intervals are not even. Any solution to achieve this outcome is greatly appreciated!

See how the sign/oval next to each interval represents the range of the interval in my example below.

enter image description here

Upvotes: 1

Views: 1114

Answers (1)

stefan
stefan

Reputation: 124433

One option to create this kind of legend would be to make it as a second plot and glue it to the main plot using e.g. patchwork.

Note: Especially with a map as the main plot and the export size if any, this approach requires some fiddling to position the legend, e.g. in my code below a added a helper row to the patchwork design to shift the legend upwards.

UPDATE: Update the code to include the counts in the labels. Added a second approach to make the legend using geom_col and a separate dataframe.

library(dplyr, warn = FALSE)
library(usmap)
library(ggplot2)
library(patchwork)

# Make example data
set.seed(123)

cat1 <- c(1500, 4001, 6001, 20001)
cat2 <- c(4000, 6000, 2000, 40000)
n = c(7, 12, 6, 25)
funding_cat <- paste0("$", cat1, " - $", cat2, " (n=", n, ")")
funding_cat <- factor(funding_cat, levels = rev(funding_cat))

grant_sh <- utils::read.csv(system.file("extdata", "us_states_centroids.csv", package = "usmapdata"))
grant_sh$funding_cat = sample(funding_cat, 51, replace = TRUE, prob = n / sum(n))

# Make legend plot
grant_sh_legend <- data.frame(
  funding_cat = funding_cat,
  n = c(7, 12, 6, 25)
)

legend <- ggplot(grant_sh, aes(y = funding_cat, fill = funding_cat)) +
  geom_bar(width = .6) +
  scale_y_discrete(position = "right") +
  scale_fill_manual(
    values = c('#D4148C',
               '#049CFC',
               '#1C8474',
               '#7703fC')
  ) +
  theme_void() +
  theme(axis.text.y = element_text(hjust = 0),
        plot.title = element_text(size = rel(1))) +
  guides(fill = "none") +
  labs(title = "Map Key")

map <- plot_usmap(regions = "states",
                  labels = TRUE) +
  geom_point(data = grant_sh,
             size = 5,
             aes(x = x,
                 y = y,
                 color = funding_cat)) +
  theme(
    legend.position = 'none',
    plot.title = element_text(size = 22),
    plot.subtitle = element_text(size = 16)
  )  + #+
  scale_color_manual(
    values = c('#D4148C',  # pink muesaum
               '#049CFC',   #library,blue
               '#1C8474',
               '#7703fC'),
    name = "Map Key",
    labels = c(
      '$1,500 - $4,000 (n = 7)',
      '$4,001 - $6,000 (n = 12)',
      '$6,001 - $20,000 (n = 6)',
      '$20,001 - $40,000 (n = 25)'
    )
  ) +
  guides(colour = guide_legend(override.aes = list(size = 3)))

# Glue together
design <- "
#B
AB
#B
"

legend + map + plot_layout(design = design, heights = c(5, 1, 1), widths = c(1, 10))

Using geom_bar the counts are computed from your dataset grant_sh. A second option would be to compute the counts manually or use a manually created dataframe and then use geom_col for the legend plot:

grant_sh_legend <- data.frame(
  funding_cat = funding_cat,
  n = c(7, 12, 6, 25)
)

legend <- ggplot(grant_sh, aes(y = funding_cat, n = n, fill = funding_cat)) +
  geom_col(width = .6) +
  scale_y_discrete(position = "right") +
  scale_fill_manual(
    values = c('#D4148C',
               '#049CFC',
               '#1C8474',
               '#7703fC')
  ) +
  theme_void() +
  theme(axis.text.y = element_text(hjust = 0),
        plot.title = element_text(size = rel(1))) +
  guides(fill = "none") +
  labs(title = "Map Key")

Upvotes: 1

Related Questions