rggplot2usmap

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


Solution

  • 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")