I was recently doing a project utilizing the Yelp API and analyzing restaurant data through R. Leaflet proved to be very helpful in providing interactive maps to visualize data. It didn’t hurt that the maps were very easy to generate and customize as well. In this post I’ll go through some of the uses I had for Leaflet with my data.
Yelp’s API provided helpful information but there were several steps I needed to take in order to get the data I needed.
Retrieving my Data
Only 20 restaurants would be returned with each request, which you can edit to a maximum of 50, but I wanted a larger set of data than that. Using offset to pickup where the last request had left off, I made four requests, allowing myself to get 200 restaurants for my data set.
Cleaning my Data
Now I needed to make some changes to my data. I needed longitude and latitude in their own columns, to make using leaflet as simple as possible. Additionally, Yelp listed all of the categories of cuisine that a restaurant fell under in one list. I wanted to separate this out to make it easier to compare different types of cuisine, by only taking the first category a restaurant fell under. I used the dplyr, tidyr, and stringr libraries to accomplish this.
library(dplyr)
library(tidyr)
library(stringr)
philly1 <- readRDS("philly1.rds")
philly2 <- readRDS("philly2.rds")
philly3 <- readRDS("philly3.rds")
philly4 <- readRDS("philly4.rds")
manipulate_data <- function(data) {
sep <- data$businesses %>%
select(id, name, categories, image_url, url, review_count, rating, price, coordinates, location) %>%
mutate(latitude = coordinates$latitude) %>%
mutate(longitude = coordinates$longitude) %>%
mutate(categories=strsplit(as.character(categories), "title = ")) %>%
unnest(categories) %>%
filter(!str_detect(categories, "^list")) %>%
mutate(categories=strsplit(as.character(categories), ",")) %>%
unnest(categories)
sep$categories <- gsub("^c", "", sep$categories)
sep$categories <- gsub("[[:punct:]]", "", sep$categories)
sep$categories <- str_trim(sep$categories)
return(sep)
}
philly1_clean <- manipulate_data(philly1)
philly2_clean <- manipulate_data(philly2)
philly3_clean <- manipulate_data(philly3)
philly4_clean <- manipulate_data(philly4)
philly1_clean <- distinct(philly1_clean, name, .keep_all = TRUE)
philly2_clean <- distinct(philly2_clean, name, .keep_all = TRUE)
philly3_clean <- distinct(philly3_clean, name, .keep_all = TRUE)
philly4_clean <- distinct(philly4_clean, name, .keep_all = TRUE)
Finally, I was ready to combine all of my data into one dataframe. I did do this step last on purpose because I was having issues combining data frames when categories was still a list.
philly_restaurants <- do.call("rbind", list(philly1_clean, philly2_clean, philly3_clean, philly4_clean))
Basic Leaflet Map
Be sure to install Leaflet. To create my basic leaflet map of my data you use leaflet(), addTiles(), and finally addMarkers() listing longitude and latitude as the arguments.
library(leaflet)
philly_restaurants %>%
leaflet() %>%
addTiles() %>%
addMarkers(lng = ~longitude, lat = ~latitude)
While this does the job of mapping all of the restaurants in my data set, there is not much information communicated here. Below I go through some features I would like to add to my map and how to do it.
Popup
It would be helpful for each marker to be labelled with the name of the restaurant it is representing. This can be accomplished with the popup argument for addMarkers().
philly_restaurants %>%
leaflet() %>%
addTiles() %>%
addMarkers(lng = ~longitude, lat = ~latitude,
popup = philly_restaurants$name)
This is a good start, but I’d like more information in the popup window than just the name. You can include as much in the popup as you would like. I decided to do the name, rating, and type of cuisine. Below you’ll say how you can use formatting as well for the popup.
philly_restaurants %>%
leaflet() %>%
addTiles() %>%
addMarkers(lng = ~longitude, lat = ~latitude,
popup = paste(philly_restaurants$name, "<br/>Rating: ",
philly_restaurants$rating, "<br/>",
philly_restaurants$categories))
Circle Markers
My map is already looking much better, but I’ve decided I don’t like the default markers and instead would like to use dots that I can size and color. This can be accomplished with addCircleMarkers() and the size and color arguments.
philly_restaurants %>%
leaflet() %>%
addTiles() %>%
addCircleMarkers(lng = ~longitude, lat = ~latitude,
radius = 3,
color = "Red",
popup = paste(philly_restaurants$name, "<br/>Rating: ",
philly_restaurants$rating, "<br/>",
philly_restaurants$categories))
Adding Color Scale
Now I can navigate about my map to find information about each restaurant, but it would be nice if the visual itself would give more information without having to click about. I will add a color scale for the markers depending on the rating of the restaurant. To do this I will use the RColorBrewer library to get a set palette, and then set the color of the markers to the palette dependent on the rating.
library(RColorBrewer)
pal <- colorNumeric(palette = "YlOrRd", domain = c(3.00:5.00))
philly_restaurants %>%
leaflet() %>%
addTiles() %>%
addCircleMarkers(lng = ~longitude, lat = ~latitude,
radius = 3,
color = ~pal(rating),
popup = paste(philly_restaurants$name, "<br/>Rating: ",
philly_restaurants$rating, "<br/>",
philly_restaurants$categories))
Changing Default Map
I can see the range of colors of my dots, although it is challenging since the map itself is so colorful as well. To fix this I want to change to a different map, which can be done by changing addTiles() to addProviderTiles() and designating the map you’d like to use. In my case I’m going with a black and white map to make my marker colors stand out. I also added the fillOpacity argument to make the dots as dark as possible.
philly_restaurants %>%
leaflet() %>%
addProviderTiles("Stamen.Toner") %>%
addCircleMarkers(lng = ~longitude, lat = ~latitude,
radius = 3,
color = ~pal(rating),
fillOpacity = 1,
popup = paste(philly_restaurants$name, "<br/>Rating: ",
philly_restaurants$rating, "<br/>",
philly_restaurants$categories))
Adding a Legend
That makes things much clearer! Now the last piece is to add a legend so you know what that array of colors means. To do this you will use addLegend(). Notice the arguments I used to tailor the legend to my needs.
philly_restaurants %>%
leaflet() %>%
addProviderTiles("Stamen.Toner") %>%
addCircleMarkers(lng = ~longitude, lat = ~latitude,
radius = 3,
color = ~pal(rating),
fillOpacity = 1,
popup = paste(philly_restaurants$name, "<br/>Rating: ",
philly_restaurants$rating, "<br/>",
philly_restaurants$categories)) %>%
addLegend(title = "Rating",
pal = pal,
values = c(3.00:5.00),
position = "topleft")
// add bootstrap table styles to pandoc tables function bootstrapStylePandocTables() { $('tr.header').parent('thead').parent('table').addClass('table table-condensed'); } $(document).ready(function () { bootstrapStylePandocTables(); });
Do you want to learn more about how we can make your next project a success? Contact us to get started.