Fairbanks has a lot of restaurants for its size, but they aren’t spread out evenly, and different parts of town have different kinds of places to eat. In this report, I made an interactive map of 126 local restaurants in the Fairbanks area, with a different icon and color for each type of atmosphere, from food trucks to upscale sit-down restaurants. The goal was to show where restaurants are clustered and which areas have which kinds of restaurants, while letting the reader click on any restaurant to see its details.
The map was made with the leaflet package, following Mike Johnson’s Interactive Mapping in R tutorial.
The data is a restaurant dataset I put together for the Fairbanks area. It focuses on local restaurants, so fast food and chain restaurants were left out on purpose. Each row is one restaurant, with its location (latitude and longitude), cuisine, price level, atmosphere, area of town, address, phone number, website, hours, and other details. Coordinates were found by geocoding each restaurant’s address in ArcGIS. Price levels were based mostly on my own experience eating at these restaurants, with Fodor’s and Restaurantji used as a reference. The table was exported from ArcGIS to Excel.
Read in the restaurant table from the Excel file.
The exported table had some columns that were only used in ArcGIS
(ObjectID, GlobalID, and
PhotoCredit). I removed those and kept the columns needed
for the map.
I also turned Atmosphere into a factor (a set of
categories with a set order). This controls the order of the categories
in the legend. I put them in order from most casual to most formal.
restaurants <- restaurants %>%
# Remove ArcGIS-only columns
select(-ObjectID, -GlobalID, -PhotoCredit) %>%
# Set the order of the atmosphere categories for the legend
mutate(
Atmosphere = factor(
Atmosphere,
levels = c(
"Food truck/Walk-up",
"Fast casual",
"Café/Coffee shop",
"Casual sit-down",
"Bar/Pub",
"Upscale sit-down"
)
)
)This is how many restaurants are in each atmosphere category:
# Count restaurants in each category and show as a table
restaurants %>%
count(Atmosphere) %>%
knitr::kable(
col.names = c("Atmosphere", "Number of Restaurants"),
align = c("l", "c")
)| Atmosphere | Number of Restaurants |
|---|---|
| Food truck/Walk-up | 9 |
| Fast casual | 28 |
| Café/Coffee shop | 15 |
| Casual sit-down | 55 |
| Bar/Pub | 8 |
| Upscale sit-down | 11 |
When a reader clicks on a restaurant, a popup shows its details. The
popup is built with a little HTML (the code used to format web pages):
<b> makes text bold, <br> starts a
new line, and <a> makes a clickable link.
Some restaurants are missing information, like a phone number or
alcohol. To keep “NA” from showing up in the popups, I wrote a small
function, popup_line(), that only adds a line when there’s
a value for it.
# Make one popup line (like "Cuisine: Thai"), or nothing if the value is missing
popup_line <- function(label, value) {
if_else(is.na(value), "", paste0("<b>", label, ":</b> ", value, "<br>"))
}Next, I made a few columns easier to read in the popup:
restaurants <- restaurants %>%
mutate(
# Price number to dollar signs and range
price_label = case_when(
Price == 1 ~ "$ (under $15)",
Price == 2 ~ "$$ ($15-30)",
Price == 3 ~ "$$$ ($30-50)",
Price == 4 ~ "$$$$ (over $50)"
),
# Show both cuisines if there are two
cuisine_label = if_else(
is.na(Cuisine2),
Cuisine,
paste0(Cuisine, " / ", Cuisine2)
),
# Put each group of days on its own line
hours_label = paste0("<br>", str_replace_all(Hours, "; ", "<br>")),
# Only show the season if it isn't year-round
season_label = if_else(Seasonal == "Year-round", NA, Seasonal),
# Website link text
website_label = if_else(
is.na(Website),
NA,
paste0(
"<a href='", Website, "' target='_blank'>",
if_else(str_detect(Website, "facebook"), "Facebook page", "Visit website"),
"</a>"
)
),
# Only show kid-friendly if there is a kids menu
kids_label = if_else(KidsMenu == "Yes", "Yes", NA),
# Put the full popup together
popup = paste0(
"<b style='font-size:15px'>", Name, "</b><br>",
popup_line("Cuisine", cuisine_label),
popup_line("Price", price_label),
popup_line("Atmosphere", Atmosphere),
popup_line("Meals", Meals),
popup_line("Service", ServiceType),
popup_line("Alcohol", Alcohol),
popup_line("Hours", hours_label),
popup_line("Season", season_label),
popup_line("Address", Address),
popup_line("Phone", Phone),
popup_line("Website", website_label),
popup_line("Kid-friendly", kids_label)
)
)Finally, I turned the table into spatial data using the latitude and
longitude columns. crs = 4326 tells R that the coordinates
are regular latitude and longitude (WGS 84), which is what leaflet
uses.
Atmosphere is a categorical variable. The categories are different types, not higher or lower amounts, so I gave each one its own color and icon instead of using a light-to-dark color ramp. A light-to-dark ramp would make it look like some categories are “more” than others. The icons also make the categories easier to tell apart, even for readers who have trouble seeing some colors.
# One icon and color for each atmosphere category
atmosphere_icons <- awesomeIconList(
"Food truck/Walk-up" = makeAwesomeIcon(icon = "truck", markerColor = "green", library = "fa"),
"Fast casual" = makeAwesomeIcon(icon = "shopping-bag", markerColor = "red", library = "fa"),
"Café/Coffee shop" = makeAwesomeIcon(icon = "coffee", markerColor = "orange", library = "fa"),
"Casual sit-down" = makeAwesomeIcon(icon = "cutlery", markerColor = "blue", library = "fa"),
"Bar/Pub" = makeAwesomeIcon(icon = "beer", markerColor = "cadetblue", library = "fa"),
"Upscale sit-down" = makeAwesomeIcon(icon = "glass", markerColor = "purple", library = "fa")
)
# Legend colors that match the marker colors above, in the same order
legend_colors <- c("#72B026", "#D63E2A", "#F69730", "#38AADD", "#436978", "#D252B9")The map uses:
The map starts zoomed in on central Fairbanks, since a few restaurants are far out of town and would make the starting view too zoomed out.
leaflet(data = restaurants_sf, height = 600) %>%
# Dark gray basemap from Esri
addTiles(
urlTemplate = "https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Dark_Gray_Base/MapServer/tile/{z}/{y}/{x}",
attribution = "Tiles © Esri"
) %>%
# Start centered on Fairbanks
setView(lng = -147.76, lat = 64.845, zoom = 11) %>%
# Restaurant icons
addAwesomeMarkers(
icon = ~atmosphere_icons[as.character(Atmosphere)],
label = ~Name, # shows on hover
popup = ~popup # shows on click
) %>%
# Legend for the atmosphere colors
addLegend(
position = "bottomright",
colors = legend_colors,
labels = levels(restaurants_sf$Atmosphere),
title = "Atmosphere",
opacity = 1
) %>%
# Map title
addControl(
html = "Local Restaurants of Fairbanks, Alaska, by Atmosphere",
position = "topright",
className = "map-title"
)Figure 1. Interactive map of 126 local restaurants in the Fairbanks, Alaska area, with a different icon and color for each type of atmosphere. Hover over a point to see the restaurant name, or click it for cuisine, price, hours, address, and website. Zoom out to see restaurants outside of town. Data: compiled by the author; coordinates geocoded in ArcGIS; price levels based on the author’s experience.
Most of the restaurants are in the main part of Fairbanks, with the biggest groups downtown (23), along the Old Steese Highway and Bentley area (20), along College Road (19), and in North Pole (16). Casual sit-down restaurants were the most common type (55 of 126), followed by fast casual (28).
The map also shows some patterns by atmosphere:
The map shows that everyday restaurants in Fairbanks follow the main roads and shopping areas, while many of the nicer, sit-down “special occasion” restaurants are outside of town. Downtown has the most variety. Because the map is interactive, a reader can zoom into one part of town and click on a restaurant to see its hours and website, which a static map can’t do.
Since the dataset only includes local restaurants, the map shows where to find local food, not every place to eat in Fairbanks. Price levels are approximate since they are based mostly on my own experience, and reflect the cost of a typical meal for one person. Most restaurants are also rated $$, so price wasn’t a useful variable to map, which is why I used atmosphere instead.
Johnson, M. Interactive mapping in R. https://mikejohnson51.github.io/leaflet-intro/index.html
RStudio. Leaflet for R. https://rstudio.github.io/leaflet/
Fodor’s Travel. https://www.fodors.com/
Restaurantji. https://www.restaurantji.com/