Introduction

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.

Data

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.

Setup

Load packages

These are the R packages used in this report.

library(tidyverse)  # data wrangling
library(readxl)     # read Excel files
library(sf)         # work with spatial data
library(leaflet)    # make interactive maps

Data Preparation

Import the data

Read in the restaurant table from the Excel file.

# Read the restaurant data from the data folder
restaurants <- read_excel(here::here("data", "Restaurants_TableToExcel.xlsx"))

Clean the data

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

Build the popup text

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:

  • Price changed from a number to dollar signs with a price range.
  • Cuisine shows both cuisines if a restaurant has two.
  • Hours shows each group of days on its own line.
  • Season only shows if a restaurant isn’t open year-round.
  • Website shows as a “Facebook page” or “Visit website” link.
  • Kid-friendly only shows if the restaurant has a kids menu.
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)
    )
  )

Convert to spatial data

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.

# Turn the table into points using longitude and latitude
restaurants_sf <- restaurants %>%
  st_as_sf(coords = c("Longitude", "Latitude"), crs = 4326)

Interactive Map

Set the icons and colors

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")

Make the map

The map uses:

  • A dark gray basemap to match the report and make the colored icons stand out.
  • Icon markers with a different icon and color for each atmosphere.
  • Labels that show the restaurant name when you hover over a point.
  • Popups that show the restaurant’s details when you click a point.
  • A legend that shows which color goes with which atmosphere.
  • A title at the top of the map.

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 &copy; 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.

Results

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:

Discussion

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.

References

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/