Background

For this exercise I created an interactive map to compare local venues for the spookiest, beer-infused Halloween weekend.

I collected input from a local Facebook group using a Google Form, checked out spots in person, and compiled a list of ratings for each venue based on: overall spook-factor, opportunities for Instagram-worthy photos, food and drink options, safety, and walkability. I assigned weighted scores to each venue (based on a top-secret algorithm), made filters to explore different categories and created a proposed bar-hop route based on the top 5 rated venues.

Interactive Map

Toggle through menus and click on pins for info at each venue!

For the proposed route, there were lots of rabbit holes I started to go down and decided not to pursue for the sake of time management and getting lost in Stack Overflow message boards or asking ChatGPT for help. But I think a fun Friday night based on this brief search would start at Mr. Billy’s Bar and Grill on Dover Rd for a pre-game, followed by Shelby’s Trio for a great view and a more cocktail-party style Halloween party, then Calle Taco for some mid-evening tacos & margs, hitting up Blackhorse for beers and a DJ, and ending the night at Electric Cowboy to do the Monster Mash and potentially win $500 for the best costume!

The Process

Google Forms

I created two Google Forms: The first one I posted to a local Facebook group, and also completed myself for each venue within a 10-mile radius of downtown Clarksville. The form included categorical questions such as whether or not the venue had Halloween-themes events, food, or any deals (ie., happy hours, themed cocktails, etc.,).


The second one I used myself to visit bars and field-verify latitudes and longitudes I a prior collected from Google Maps. (I did not visit all venues, I visited ~10 that were closest to my house).


I linked the Forms to Google Sheets and exported them as .csv files to use in R. Additionally, I later decided to add event links for the venues with Halloween-themed events so I created a .csv with the venue lat/longs, ID, and the link.

Code

First I weighted each of the “ratings” questions and then calculated the weighted sum for each venue. I then merged this data frame with my lat/long dataframe and grouped the data by unique venue IDs.

# calculating overall score
scores <- scores %>%
  mutate(
# rating weights for overall score
    w.spook = 0.25, 
    w.vibes = 0.25, 
    w.drink = 0.20, 
    w.food = 0.15, 
    w.walk = 0.10, 
    w.safety = 0.05,
# weighted sum of ratings
    num = 
  w.spook*spook.factor + 
  w.vibes*vibes + 
  w.drink*coalesce(drink.rating,0) + # coalesce replaces NA's with 0's
  w.food*coalesce(food.rating, 0) +
  w.walk*walkability +
  w.safety*safety,
# the sum of all weights that were actually used (excludes food rating for bars that don't serve food or fields that were left blank)
    den = 
  w.spook*(!is.na(spook.factor)) + 
  w.vibes*(!is.na(vibes)) +
  w.drink*(!is.na(drink.rating)) +
  w.food*(!is.na(food.rating)) +
  w.walk*(!is.na(walkability)) + 
  w.safety*(!is.na(safety)),
# overall score
    overall.score = round(num/den, 2)) %>%
  select(-w.spook, -w.vibes, -w.drink, -w.food, -w.walk, -w.safety, -num, -den)


Next I filtered out the top 10 venues and made a line for proposed route between the top 5 venues.

# create top 10 list + row.id for label in leaflet
top.bars <- bars.df %>%
  filter(overall.score > 3.1) %>%
  ungroup() %>%
  mutate(row.id = row_number())

# create top 5 list to make a route between them
top <- top.bars %>%
  slice(1:5)

# set a route order to draw the lines
top$route.order <- c(2,5,4,1,3)

# convert to shapefile
top.sf <- st_as_sf(top, coords = c("longitude", "latitude"), crs = 4326)

# create a line 
route.line <- top.sf %>%
  arrange(route.order) %>%    
  summarise(do_union = FALSE) %>%
  st_cast("LINESTRING")


For the final step before I wrote the leaflet map I designated some custom icons for the different categories (toggle menus), which I sourced from Flaticon.com.

halloween.icon <- makeIcon(iconUrl = "images/pin.png", iconWidth = 30, iconHeight = 30)
bar.icon <- makeIcon(iconUrl = "images/beer.png",iconWidth = 30, iconHeight = 30)
food.icon <- makeIcon(iconUrl = "images/food.png",iconWidth = 30, iconHeight = 30)
deals.icon <- makeIcon(iconUrl = "images/deals.png",iconWidth = 30, iconHeight = 30)
star.icon <- makeIcon(iconUrl = "images/star.png",iconWidth = 30, iconHeight = 30)

And finally I wrote the giant leaflet code:

map <- 
  leaflet(bars.df) %>% 
  addTiles() %>%
  addProviderTiles(providers$CartoDB.DarkMatter, group = "Dark") %>%
  addProviderTiles(providers$CartoDB.Positron, group = "Light") %>%
  addMarkers(data = bars.df,
             lng = bars.df$longitude, 
             lat = bars.df$latitude,
             icon = bar.icon,
             label = ~bars.df$venue.id,
             popup = ~paste0(
               "<b>", bars.df$venue.id, "</b><br>",
               "<b>★ ", bars.df$overall.score, "</b><br>",
               "Spook Factor: ★ ", round(bars.df$spook.factor,2), "<br>",
               "Aesthetic: ★ ", round(bars.df$vibes,2), "<br>",
               "Drinks: ★ ", round(bars.df$drink.rating,2), "<br>",
               "Food: ★ ", round(bars.df$food.rating,2), "<br>",
               "Walkability: ★ ", round(bars.df$walkability,2), "<br>",
               "Safety: ★ ", round(bars.df$safety,2), "<br>"),
             group = "All Venues") %>%
  addMarkers(data = subset(bars.df, halloween.events == "Yes"),
             lng = ~longitude, 
             lat = ~latitude,
             icon = halloween.icon,
             label = ~venue.id,
             popup = ~paste0(
               "<b>", venue.id, "</b><br>",
               "Spook Factor: ★ ", round(spook.factor,2), "<br>",
             "<a href='", event.links$event.link, "' target='_blank'>Visit Event Page</a>"),
             group = "Halloween Events") %>%
  addMarkers(data = subset(bars.df, food == "Yes"),
             lng = ~longitude, 
             lat = ~latitude,
             icon = food.icon,
             label = ~venue.id,
             popup = ~paste0(
               "<b>", venue.id, "</b><br>",
               "Food: ★ ", round(food.rating,2), "<br>"),
             group = "Food") %>%
  addMarkers(data = subset(bars.df, deals == "Yes"),
             lng = ~longitude, 
             lat = ~latitude,
             icon = deals.icon,
             label = ~venue.id,
             popup = ~paste0(
               "<b>", venue.id, "</b><br>",
               "Drinks: ★ ", round(drink.rating,2), "<br>",
               "Happy Hour/Event Deals"),
             group = "Deals") %>%
  addMarkers(data = top.bars,
             lng = top.bars$longitude, 
             lat = top.bars$latitude,
             icon = star.icon,
             label = ~top.bars$venue.id,
             popup = ~paste0(
               "<b>",top.bars$row.id, ". ", top.bars$venue.id, "</b><br>",
               "★ ", round(top.bars$overall.score,2),  "<br>"),
             group = "Top 10 Venues") %>%
  addPolylines(data = route.line,
               color = "orange",
               weight = 2.5,
               opacity = 0.8,
    dashArray = "10,6",
    group = "Proposed Route") %>%
  addMarkers(data = top,
             lng = ~longitude, 
             lat = ~latitude,
             icon = star.icon,
             popup = ~paste0(
               "<b>", top$route.order, ". ", venue.id, "</b><br>",
               "★ ", round(overall.score,2),  "<br>"),
             group = "Proposed Route") %>%
  addLayersControl(
    baseGroups = c("Dark","Light"),
    options = layersControlOptions(collapsed = FALSE),
    overlayGroups = c("All Venues", "Halloween Events", "Food", "Deals", "Top 10 Venues", "Proposed Route")) %>%
  hideGroup(c("Halloween Events", "Food", "Deals", "Top 10 Venues", "Proposed Route")) %>%
setView(lng = -87.356249, lat = 36.527874, zoom = 12) %>%
  addFullscreenControl(position = "topleft") %>%
  addScaleBar()
Credit for Icons:
Halloween Events Icon: Pumpkin icons created by Freepik - Flaticon
All Venues Icon: Maps and location icons created by Freepik - Flaticon
Food Venues Icon: Location icons created by Freepik - Flaticon
Deals Icon: Money icons created by Freepik - Flaticon
Top Bars Icon: Favourite icons created by Freepik - Flaticon