rmapsr-sfcartography

Plotting image files over states in a US Map in R


So, the following graph is the inspiration for this post.

Essentially, what I want to do is utilize my work's sales data to see which of our brands is selling the most in each US state - and have the brand image file in each respective state.

For instance, if the best-selling brand of food we sell in Utah is Nestle - then I want the Nestle logo in that state.

My data set looks like this:

State     Brand      Sales    %TTL
 AK       Nestle     $260      8%
 AL       Mars       $480      10%
 AZ       Coca Cola  $319      12%
 ...
 WY       Nestle     $200      25%

I have the image files from Google, but I have no idea how to make this work. I know there's the cartography package and I've been following guide - but it isn't really 1:1. I can't even get the sample code to execute because it says it can't find the online address

I don't want this done for me - but how do I start? I essentially want it to look like the map in the first image, but have it correspond with images of the brands we work with.

Tableau didn't really have an optimal solution and this was done in R originally, so I'm trying to replicate it, but it's been proving difficult.


Solution

  • Well, see here an adaptation:

    1. First you need to get a sf (a map ) of the US states. I use here USAboundaries but you can use whaterver you prefer.
    2. Note that I needed to fake your data. Use your own.
    3. Use rowwise() and switch() to add a column to your data with the url of the png
    4. On the loop, for each brand: select the corresponding state, create the image overlay and add the layer to the plot.

    See here a reproducible example:

    library(USAboundaries)
    #> The USAboundariesData package needs to be installed.
    #>  Please try installing the package using the following command: 
    #>      install.packages("USAboundariesData", repos = "https://ropensci.r-universe.dev", type = "source")
    library(sf)
    #> Linking to GEOS 3.9.1, GDAL 3.2.1, PROJ 7.2.1; sf_use_s2() is TRUE
    library(tidyverse)
    library(rasterpic)
    library(tidyterra)
    
    # Part 1: The map
    states <- USAboundaries::states_contemporary_lores %>%
      select(State = state_abbr) %>%
      # Filter AK and HW
      filter(!(State %in% c("AK", "HI", "PR"))) %>%
      st_transform("ESRI:102003") 
    
    states
    #> Simple feature collection with 49 features and 1 field
    #> Geometry type: MULTIPOLYGON
    #> Dimension:     XY
    #> Bounding box:  xmin: -2356114 ymin: -1338125 xmax: 2258154 ymax: 1558935
    #> Projected CRS: USA_Contiguous_Albers_Equal_Area_Conic
    #> First 10 features:
    #>    State                       geometry
    #> 1     CA MULTIPOLYGON (((-2066285 -2...
    #> 2     WI MULTIPOLYGON (((708320.1 91...
    #> 3     ID MULTIPOLYGON (((-1673882 95...
    #> 4     MN MULTIPOLYGON (((-91052.17 1...
    #> 5     IA MULTIPOLYGON (((-50588.83 5...
    #> 6     MO MULTIPOLYGON (((19670.04 34...
    #> 7     MD MULTIPOLYGON (((1722285 240...
    #> 8     OR MULTIPOLYGON (((-2285910 94...
    #> 9     MI MULTIPOLYGON (((882371.5 99...
    #> 10    MT MULTIPOLYGON (((-1474367 14...
    
    # Base map
    plot <- ggplot(states) +
      geom_sf(fill = "grey90") +
      theme_minimal() +
      theme(panel.background = element_rect(fill = "lightblue"))
    
    plot
    

    # Part 2: your data (I have to fake it)
    # Use here your own data
    
    # Assign 3 random brands
    brands <- data.frame(State = states$State)
    set.seed(1234)
    
    brands$Brand <- sample(c("Nestle", "Mars", "Coca Cola"), nrow(brands), replace = TRUE)
    
    # Part 3: find your pngs
    logos <- brands %>%
      rowwise() %>%
      mutate(png = switch(Brand,
        "Nestle" = "https://1000marcas.net/wp-content/uploads/2020/01/Logo-Nestle.png",
        "Mars" = "https://1000marcas.net/wp-content/uploads/2020/02/Logo-Mars.png",
        "Coca Cola" = "https://w7.pngwing.com/pngs/873/613/png-transparent-world-of-coca-cola-fizzy-drinks-diet-coke-coca-cola-text-logo-cola.png",
        "null"
      ))
    
    # Now loop
    for (i in seq_len(nrow(logos))) {
      logo <- logos[i, ]
      shape <- states[states$State == logo$State, ]
    
      img <- rasterpic_img(shape, logo$png, mask = TRUE)
    
      plot <- plot + geom_spatraster_rgb(data = img)
    }
    
    plot
    

    Created on 2022-06-03 by the reprex package (v2.0.1)