library(leaflet)
# Combine mits + apps into a single point dataset with outcome label
make_map_df <- function(df, side, addr_col) {
coords <- df |> st_transform(4326) |> st_coordinates()
df |>
st_drop_geometry() |>
transmute(
unique_id,
side,
label_addr = .data[[addr_col]],
assignment_method,
lon = coords[, "X"],
lat = coords[, "Y"]
)
}
points_for_map <- bind_rows(
make_map_df(mits_final, "Mitigation", "Match_addr"),
make_map_df(apps_final, "Application", "address")
) |>
mutate(
outcome = case_when(
assignment_method == "direct_single_parcel" ~ "Direct (single hit)",
assignment_method == "direct_multi_resolved" ~ "Direct (multi-parcel resolved)",
assignment_method == "nearest_high_addr" ~ "Rescued (address match)",
assignment_method == "nearest_high_dist" ~ "Rescued (nearest centroid)",
assignment_method == "unassigned" ~ "Unassigned"
)
)
outcome_pal <- colorFactor(
palette = c("Direct (single hit)" = "#1B7837",
"Direct (multi-parcel resolved)" = "#5AAE61",
"Rescued (address match)" = "#2166AC",
"Rescued (nearest centroid)" = "#67A9CF",
"Unassigned" = "#B2182B"),
domain = points_for_map$outcome
)
flood_boundary_wgs <- st_read(flood_boundary_path, quiet = TRUE) |>
st_transform(4326)
leaflet() |>
addProviderTiles(providers$CartoDB.Positron, group = "Light") |>
addProviderTiles(providers$Esri.WorldImagery, group = "Satellite") |>
# Flood study area
addPolygons(
data = flood_boundary_wgs,
fillColor = "lightblue",
fillOpacity = 0.15,
color = "navy",
weight = 1.5,
opacity = 0.6,
group = "Flood study area"
) |>
# Assigned records — clustered for performance
addCircleMarkers(
data = points_for_map |> filter(outcome != "Unassigned"),
lng = ~lon, lat = ~lat,
radius = 3,
color = ~outcome_pal(outcome),
fillOpacity = 0.7,
stroke = FALSE,
label = ~glue::glue("{side} #{unique_id} — {outcome}"),
popup = ~glue::glue(
"<b>{side} #{unique_id}</b><br>",
"<b>outcome:</b> {outcome}<br>",
"<b>addr:</b> {label_addr}"
),
clusterOptions = markerClusterOptions(maxClusterRadius = 40),
group = "Assigned records"
) |>
# Unassigned records — unclustered and prominent
addCircleMarkers(
data = points_for_map |> filter(outcome == "Unassigned"),
lng = ~lon, lat = ~lat,
radius = 6,
color = "#7C0024",
fillColor = "#B2182B",
fillOpacity = 0.9,
stroke = TRUE,
weight = 2,
label = ~glue::glue("{side} #{unique_id} — UNASSIGNED"),
popup = ~glue::glue(
"<b>{side} #{unique_id}</b><br>",
"<b>UNASSIGNED</b><br>",
"<b>addr:</b> {label_addr}"
),
group = "Unassigned records"
) |>
addLayersControl(
baseGroups = c("Light", "Satellite"),
overlayGroups = c("Flood study area", "Assigned records", "Unassigned records"),
options = layersControlOptions(collapsed = FALSE)
) |>
addLegend(
"bottomright",
pal = outcome_pal,
values = points_for_map$outcome,
title = "Assignment outcome",
opacity = 0.85
)