ggplot & maps

Recently, I was attempting to layer plots created using ggplot onto a map. I came across this example, and it was exactly what I wanted. It produced this plot using a package called ggsubplot

However, after trying to install and use ggsubplot I found out that it has been deprecated for some time (now incompatable with current versions of ggplot2) and has been since removed from CRAN, as detailed here.

Therefore, I found an alternative approach to layer plots made using ggplot onto a map - by employing the googleway package. This takes extra steps - but allows you to add ggplots to googlemaps.

To demonstrate this I will use example data from Yelp - plotting barbers in Manchester, first using markers, then plotting graph showing price and rating information.

Extracting example data

I have used Yelp data for this example, as it is ideal as it has geographic information, along with additional data to create a plot for each location. This was extracted pro grammatically in R using the Yelp API.

In order to use the Yelp API, you need to create an app through their development area. This allows you to create a client id and api key which you can use to extract data.

I create the following function, which relies on the httr and jsonlite packages to extract the data, along with the tidyverse to clean it. It requires 6 inputs:

  • term - what are you searching for

  • location - the area where you want to search

  • limit - how many results do you want to find

  • radius - radius of the location

  • client_id - client id key from Yelp

  • api - api key from Yelp

library(httr)
library(jsonlite)
library(tidyverse) 

yelp_search<-function(term,location,limit, radius,client_id,api){
  yelp <- "https://api.yelp.com"

  url <- modify_url(yelp, path = c("v3", "businesses", "search"),
                    query = list(term = term, location = location, 
                                 limit = limit,
                                 radius = radius))
  res <- GET(url, add_headers('Authorization' = paste("bearer", api)))
  
  resTEXT<-httr::content(res, as="text")
  JLres<-jsonlite::fromJSON(resTEXT, flatten=TRUE)
  
  BUS<-JLres$businesses
  cat_list<-list()
  for (i in 1:length(BUS$name)){
    categories1<-BUS$categories[[i]] %>%
      as.vector()
    c2<-as.vector(categories1$title)
    c3<-paste0(c2, collapse = ", ")
    cat_list[[i]]<-c3
    }
    
  c4<-unlist(cat_list)
  

  BUSINESS_DF<-select(BUS,name,rating,review_count,price,phone,
                      latitude=coordinates.latitude,
                      longitude=coordinates.longitude,
                      postcode=location.zip_code)%>%
    mutate(categories=c4)%>%
    as_tibble()
  
  BUSINESS_DF$price_num<-nchar(BUSINESS_DF$price)
  
  return(BUSINESS_DF)
  
  }

In this example we are extracting data for barber shops in Manchester, UK. I filter, only examining the data where there is price information.

term <- "barber"
location <- "Manchester, UK"
limit <- 20
radius <- 8000
#api and client_id are obtained from Yelp developer page

yelp_df <- yelp_search(term,location,limit,radius,client_id,api)%>%
  filter(!is.na(price_num))
name rating review_count price phone latitude longitude postcode categories price_num
The Cornershop Barber Shop 3.5 12 £ 4.41612e+11 53.48280 -2.234542 M1 1JF Barbers 1
Mr Male Grooming 5.0 6 £££ 4.41618e+11 53.48012 -2.253904 M3 3AQ Barbers, Hair Salons 3
Close Male Grooming 4.5 6 ££ 4.41612e+11 53.48409 -2.231907 M4 5AZ Hair Salons, Barbers 2
BarberBarber 3.5 9 £££ 4.41618e+11 53.48281 -2.246458 M3 2BW Barbers 3
KMC Barbers 5.0 1 ££ NA 53.42315 -2.183590 SK4 4NZ Barbers 2
Urban Gent Hairdressing 5.0 2 ££ 4.47583e+11 53.48128 -2.249401 M3 2PB Barbers, Blow Dry/Out Services, Hair Extensions 2
Maclure Barbers 3.5 6 £££ 4.41614e+11 53.48315 -2.235488 M4 1NB Barbers 3
Flanagans 3.0 3 ££ 4.41618e+11 53.48171 -2.248858 M3 2PW Barbers 2
Palace Barbers 3.0 3 £ 4.47962e+11 53.48314 -2.231941 M4 1PW Barbers 1

Map with markers

the first thing that you can do with googleway is to map the data on google maps with markers.

You can include additional information that will appear when you click on the marker. To do this we add an extra column to the dataframe with the info that will appear when you click on the marker. In this case it is the name and rating.

yelp_df$info<-paste0("<b>Name: </b>",yelp_df$name," ",
                "<b>Rating: </b>",yelp_df$rating)

We then plot this data with googleway. However, before using googleway you need to register with google maps and obtain an api key, details on how to do this are provided here

In this example we refer to the google map api as key.

library(googleway)
library(tidyverse)

set_key(key = key) #key is the api

google_map() %>%
  add_markers(
    data = yelp_df,
    info_window = "info"
  )

You can also alter the colours of the markers, instructions on how to do this can be found here

Map with plots

To replace the markers with plots, there are a number of steps we have to take:

  • Create the plots with ggplot
  • Save plots to a file and create a link for the file
  • Re-plot with googleway

Create the plots

We create the plots with ggplot In this example, I am plotting a bar plot for each firm, with firm rating, number of reviews and price. The theme is altered to remove text from the plot, and to make the background transparent.

In ggsave the width and height is the size of the plot/file. You might want to adjust to find the most suitable size.

library(tidyverse)
library(reshape2)
for(i in 1:length(yelp_df$name)) {
  name_place<-yelp_df$name[[i]]
  yp<-select(yelp_df,name,rating,review_count,price_num)%>%
    melt()
  p <- ggplot(subset(yp, name==name_place), 
              aes(variable, value,  fill = variable)) + 
    geom_bar(stat="identity", show.legend=FALSE)+
    theme(axis.title.x=element_blank(),
          axis.text.x=element_blank(),
          axis.text.y=element_blank(),
          axis.ticks.y=element_blank(),
          axis.ticks.x=element_blank(),
          axis.title.y=element_blank(),
          panel.background = element_rect(fill = "transparent"), # bg of the panel
          plot.background = element_rect(fill = "transparent", color = NA), # bg of the plot
          panel.grid.major = element_blank(), # get rid of major grid
          panel.grid.minor = element_blank(), # get rid of minor grid
          legend.background = element_rect(fill = "transparent"), # get rid of legend bg
          legend.box.background = element_rect(fill = "transparent") # get rid of legend panel bg
)
  file_name<-paste0("figure_",i,"_",name_place,".png")%>%
    tolower()%>%
    gsub("[[:space:]]", "", .)
  
  ggsave(file_name, p,width=0.6,height=0.3,
           bg = "transparent")
}

I then create a link to the images. To do this I have created a GitHub repository, where I have saved the images. This allows me to use the following link structure.

path_to_images <-"https://raw.githubusercontent.com/matthewsmith430/vis_image/master/"

for (i in 1:length(yelp_df$name)){
  name_place<-yelp_df$name[[i]]
  
  
  file_name<-paste0("figure_",i,"_",name_place,".png")%>%
    tolower()%>%
    gsub("[[:space:]]", "", .)
  
  yelp_df$image[i]<-paste0(path_to_images, file_name)
  
}

Add plots to the map

library(googleway)
library(tidyverse)

set_key(key = key) #key is the api

google_map() %>%
  add_markers(
    data = yelp_df,
    marker_icon = "image",
    info_window = "info"
  )

The plots show the number of reviews, price and rating. The colours are:

  • Green = Review Count

  • Red = Rating

  • Blue = Price

R  ggplot  maps