Interactive Mapping with R & Leaflet

From Local Landmarks to Public Health Insights

Nadika Sharma

2026-05-04

Overview

What We’ll Cover

  • 🗺️ Leaflet — interactive maps in R
  • 📍 Local landmarks in Appleton, WI
  • 🌎 US cities — largest city per state
  • 🏥 Wisconsin health data — county-level insights
  • 📦 Key packages: leaflet, dplyr, readr, tigris, sf
Package Purpose
leaflet Interactive maps
dplyr Data wrangling
readr CSV/TSV reading
sf Spatial data
tigris US shapefiles
scales Number formatting

What is Leaflet?

Leaflet is a JavaScript library for interactive maps wrapped for R via the leaflet package.

Core Functions

Function Role
leaflet() Initialize the map
addTiles() Add a base tile layer
addProviderTiles() Add styled tiles
addMarkers() Pin-drop markers
addCircleMarkers() Sized circle markers
addPolygons() Filled shapes/regions
addLegend() Color legend

The Pipe Pattern

Every Leaflet map is built with pipe chaining:

leaflet(data) |>
  addTiles() |>
  addMarkers(
    lng = ~longitude,
    lat = ~latitude,
    popup = ~name
  )

Map 1: Appleton Landmarks

A simple data frame of three local places with coordinates:

places <- data.frame(
  name = c("Lawrence University",
           "Appleton Public Library",
           "Fox Cities Exhibition Center"),
  lat  = c(44.2619, 44.2625, 44.2606),
  lng  = c(-88.3975, -88.4052, -88.4086),
  type = c("College", "Library", "Event Space")
)
leaflet(places) |>
  addTiles() |>
  addMarkers(
    lng   = ~lng,
    lat   = ~lat,
    popup = ~paste(name, "<br>", type)
  )

Map 1 — Result

Map 2: US Cities Data

We use the GeoNames cities dataset (cities with 5,000+ population):

download.file(
  url      = "https://download.geonames.org/export/dump/cities5000.zip",
  destfile = "cities5000.zip"
)
unzip("cities5000.zip")
cities_raw <- read_tsv(
  "cities5000.txt",
  col_names = FALSE,
  show_col_types = FALSE
)

Map 2: Wrangling the Data

The raw file has no column names, we rename the ones we need:

cities <- cities_raw |>
  transmute(
    city         = X2,
    latitude     = X5,
    longitude    = X6,
    country_code = X9,
    state        = X11,
    population   = X15
  ) |>
  filter(!is.na(population), population > 0)

# Keep only the biggest city per US state
biggest_city_each_state <- cities |>
  filter(country_code == "US",
         !is.na(state), state != "") |>
  group_by(state) |>
  slice_max(population, n = 1, with_ties = FALSE) |>
  ungroup() |>
  mutate(
    popup_text = paste0(
      "<b>", city, "</b><br>",
      "State: ", state, "<br>",
      "Population: ", comma(population)
    )
  )

Map 2: Biggest City Per State

leaflet(biggest_city_each_state) |>
  addProviderTiles(providers$CartoDB.Positron) |>
  setView(lng = -98.5795, lat = 39.8283, zoom = 4) |>
  addCircleMarkers(
    lng         = ~longitude,
    lat         = ~latitude,
    radius      = 7,
    color       = "darkblue",
    fillColor   = "skyblue",
    fillOpacity = 0.85,
    weight      = 1,
    popup       = ~popup_text,
    label       = ~paste0(city, ", ", state)
  )

Map 2 — Result

Map 3: Wisconsin Health Data

We use County Health Rankings data (2025) linked to county shapefiles:

chr_raw <- read_csv(
  "analytic_data2025_v3.csv",
  skip = 1,
  show_col_types = FALSE
)

chr <- chr_raw |> clean_names()
wi_health <- chr |>
  mutate(
    fips = str_pad(as.character(.data[["fipscode"]]),
                   width = 5, pad = "0")
  ) |>
  filter(str_starts(fips, "55")) |>
  select(
    fips,
    county,
    life_expectancy = v147_rawvalue,
    adult_obesity   = v011_rawvalue
  )

Map 3: Getting County Shapefiles

The tigris package downloads US Census shapefiles directly into R as simple features (sf) objects:

options(tigris_use_cache = TRUE)

wi_counties <- counties(
  state = "WI",
  cb    = TRUE,
  class = "sf"
)

wi_map <- wi_counties |>
  left_join(wi_health, by = c("GEOID" = "fips"))

tigris gives us polygon boundaries for every US county, state, zip code, and more.

sf (simple features) is the standard R format for vector spatial data — Leaflet speaks sf natively.

Map 3a: Adult Obesity by County

pal_obesity <- colorNumeric(
  palette  = "YlOrRd",
  domain   = wi_map$adult_obesity,
  na.color = "gray90"
)

leaflet(wi_map) |>
  addProviderTiles(providers$CartoDB.Positron) |>
  addPolygons(
    fillColor   = ~pal_obesity(adult_obesity),
    fillOpacity = 0.75,
    color       = "white",
    weight      = 1,
    popup = ~paste0(
      "<b>", NAME, " County</b><br>",
      "Adult Obesity: ", percent(adult_obesity, accuracy = 0.1), "<br>",
      "Life Expectancy: ", round(life_expectancy, 1), " years"
    ),
    label = ~paste0(NAME, ": ", percent(adult_obesity, accuracy = 0.1))
  ) |>
  addLegend(
    position  = "bottomright",
    pal       = pal_obesity,
    values    = ~adult_obesity,
    title     = "Adult Obesity Rate",
    opacity   = 0.8,
    labFormat = labelFormat(
      transform = function(x) 100 * x,
      suffix    = "%"
    )
  )

Map 3a — Result: Adult Obesity

Map 3b: Life Expectancy by County

pal_life <- colorNumeric(
  palette  = "YlGnBu",
  domain   = wi_map$life_expectancy,
  na.color = "gray90"
)

leaflet(wi_map) |>
  addProviderTiles(providers$CartoDB.Positron) |>
  addPolygons(
    fillColor   = ~pal_life(life_expectancy),
    fillOpacity = 0.75,
    color       = "white",
    weight      = 1,
    popup = ~paste0(
      "<b>", NAME, " County</b><br>",
      "Life Expectancy: ", round(life_expectancy, 1), " years<br>",
      "Adult Obesity: ", percent(adult_obesity, accuracy = 0.1)
    ),
    label = ~paste0(NAME, ": ", round(life_expectancy, 1), " years")
  ) |>
  addLegend(
    position = "bottomright",
    pal      = pal_life,
    values   = ~life_expectancy,
    title    = "Life Expectancy (years)",
    opacity  = 0.8
  )

Map 3b — Result: Life Expectancy

Leaflet vs ggplot2 Maps

Feature Leaflet geom_sf / ggplot2
Interactivity ✅ Zoom, pan, click ❌ Static image
Popups & tooltips ✅ Built-in ❌ Not supported
Base map tiles ✅ OpenStreetMap, CartoDB, etc. ❌ None
Publication plots ⚠️ Limited ✅ Full ggplot2 control
Learning curve 🟢 Easy 🟡 Moderate
Best for Presentations, web, exploration Papers, reports, print

Thank You!

Resources

Code

All code and data available in r_package.qmd