Skip to content

Instantly share code, notes, and snippets.

@walkerke
Created December 4, 2025 17:23
Show Gist options
  • Select an option

  • Save walkerke/33d16059c7c3b7af21d424540ab52d5d to your computer and use it in GitHub Desktop.

Select an option

Save walkerke/33d16059c7c3b7af21d424540ab52d5d to your computer and use it in GitHub Desktop.
library(shiny)
library(mapgl)
library(tidycensus)
library(bslib)
options(tigris_use_cache = TRUE)
# Get LA income data
la_income <- get_acs(
geography = "tract",
variables = "B19013_001",
state = "CA",
county = "Los Angeles",
geometry = TRUE
)
# Define reusable expressions
income_colors <- interpolate(
column = "estimate",
values = c(20000, 50000, 80000, 120000, 200000),
stops = c("#feedde", "#fdbe85", "#fd8d3c", "#d94701", "#7f2704"),
na_color = "lightgray"
)
income_height <- interpolate(
column = "estimate",
values = c(20000, 50000, 80000, 120000, 200000),
stops = c(0, 500, 2000, 5000, 12000)
)
ui <- page_fillable(
tags$style(HTML("
.tilt-btn {
position: fixed;
top: 20px;
right: 20px;
z-index: 1000;
padding: 12px 24px;
background: #0891b2;
border: none;
border-radius: 8px;
color: white;
font-size: 14px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.tilt-btn:hover {
background: #0e7490;
}
")),
mapboxglOutput("map", height = "100%"),
actionButton("toggle_3d", "Toggle 3D", class = "tilt-btn")
)
server <- function(input, output, session) {
is_3d <- reactiveVal(FALSE)
output$map <- renderMapboxgl({
mapboxgl(
style = mapbox_style("light"),
center = c(-118.25, 34.05),
zoom = 9,
pitch = 0,
bearing = 0
) |>
add_source(
id = "income-source",
data = la_income,
tolerance = 0
) |>
add_fill_extrusion_layer(
id = "income",
source = "income-source",
fill_extrusion_color = income_colors,
fill_extrusion_height = 0,
fill_extrusion_opacity = 0.8,
tooltip = "estimate"
) |>
add_legend(
legend_title = "Median Household Income",
values = c("$20k", "$50k", "$80k", "$120k", "$200k+"),
colors = c("#feedde", "#fdbe85", "#fd8d3c", "#d94701", "#7f2704"),
position = "bottom-left",
width = "300px"
)
})
observeEvent(input$toggle_3d, {
current <- is_3d()
is_3d(!current)
center <- input$map_center
zoom <- input$map_zoom
if (!current) {
# Switch to 3D
mapboxgl_proxy("map") |>
set_paint_property("income", "fill-extrusion-height", income_height) |>
ease_to(
center = c(center$lng, center$lat),
zoom = zoom,
pitch = 60,
bearing = -20,
duration = 1000
)
} else {
# Switch to 2D
mapboxgl_proxy("map") |>
set_paint_property("income", "fill-extrusion-height", 0) |>
ease_to(
center = c(center$lng, center$lat),
zoom = zoom,
pitch = 0,
bearing = 0,
duration = 1000
)
}
})
}
shinyApp(ui, server)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment