Search code examples
rggplot2gradientcolormap

Creating gradient map using ggplot2 where locations are abbreviated US states


I'm trying to create a map using a gradient color scheme for fatality counts per state as a result of shootings. My dataset has all 50 states + DC, and it uses the two letter abbreviation for each state. I made a variable below that counts the number of events per state.

enter image description here

Using this, I'm attempting to make a map where the states with higher counts are colored in darker blues and the lower counts are lighter blues.

library(maps)
library(dplyr)
library(mapproj)

fatalities_by_state <- shootings_clean %>%
  count(state)

map_data <- map_data("state")

merged_data <- merge(map_data, fatalities_by_state, by.x = "region", by.y = "state", all.x = TRUE)

ggplot() +
  geom_polygon(data = merged_data,
               aes(x = long, y = lat, group = group, fill = log(n)),
               color = "black", size = 0.2) +
  theme_classic() + 
  scale_fill_gradient(low = "lightblue", high = "darkblue", name = "Fatalities") +
  coord_map() +
  labs(title = "Fatalities by State", fill = "Log Count") +
  theme(plot.title = element_text(hjust = 0.5))

However, the outcome is as follows.

enter image description here

How can I edit my code so the actual colors show up so the higher the fatality count is, the darker the color is, and vice versa? Is there a way I can add labels where when you hover over the state, it shows the State Name and number of Fatalities?

Thanks in advance.


Solution

  • Couple of issues here:

    • you're trying to merge map_data$region, which has full state names, with fatalities_by_state$state, which has two-letter abbreviations e.g. they don't match and will result in NA values;
    • I'm guessing you have data for the non-contiguous states? In which case, it would be better to include them;
    • when working with sf objects, it is better to plot them as such e.g. geom_sf()

    Here is a full repex that addresses these issues. If you want to omit the non-contiguous states, comment below and I'll update the answer. Also, if you want to know how to create an interactive map, this should be a separate question. But you shouldn't need to post a separate question, just search for questions related to plotting sf objects using the plotly package. There are many plotly solutions on SO. Other options include using leaflet or mapview, which are relatively straightforward to use.

    library(dplyr)
    library(sf)
    library(usmap)
    library(ggplot2)
    
    # US state data as sf object from the usmap library
    map_data <- us_map() %>%
      rename(state = "abbr")
    
    # Create example fatalities data
    set.seed(1)
    fatalities_by_state <- data.frame(state = map_data$state,
                                      n = sample(59:1700, 51))
    # Join
    merged_data <- left_join(map_data, fatalities_by_state, by = "state")
    
    # Plot
    ggplot() +
      geom_sf(data = merged_data,
              aes(fill = log(n)),
              color = "black",
              linewidth = 0.2) +
      theme_classic() + 
      scale_fill_gradient(low = "lightblue", 
                          high = "darkblue", 
                          name = "Fatalities\nLog Count") +
      labs(title = "Fatalities by State") +
      theme(plot.title = element_text(hjust = 0.5))
    

    Result: result