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