Unambiguous Neighborhoods with sfdep

Extra Writeups
Author

Jeff Jacobs

Published

October 14, 2025

Initialization Code

library(tidyverse) |> suppressPackageStartupMessages()
library(mapview) |> suppressPackageStartupMessages()
library(rnaturalearth) |> suppressPackageStartupMessages()
library(spdep) |> suppressPackageStartupMessages()

Finding Neighbors in Asia

asia_countries_sf <- ne_countries(continent = "Asia", scale=50)
mapview(asia_countries_sf, label="geounit")
library(spdep)
asia_countries_nb <- asia_countries_sf |>
  spdep::poly2nb(
    queen = TRUE,
    row.names=asia_countries_sf$geounit
  )
asia_countries_nb
Neighbour list object:
Number of regions: 53 
Number of nonzero links: 164 
Percentage nonzero weights: 5.838377 
Average number of links: 3.09434 
7 regions with no links:
Taiwan Sri Lanka Singapore Philippines Japan Bahrain Indian Ocean
Territories
9 disjoint connected subgraphs
nb_cents <- sf::st_point_on_surface(asia_countries_sf) |>
  sf::st_as_sf()
Warning: st_point_on_surface assumes attributes are constant over geometries
Warning in st_point_on_surface.sfc(st_geometry(x)): st_point_on_surface may not
give correct results for longitude/latitude data
nb_lines <- spdep::nb2lines(
  asia_countries_nb,
  coords=st_coordinates(nb_cents),
  as_sf=TRUE
)
nb_lines$edgelabel <- paste0(nb_lines$i_ID, "-", nb_lines$j_ID)
mapview(nb_cents, label="geounit") + mapview(nb_lines, label="edgelabel")
print(asia_countries_nb)
Neighbour list object:
Number of regions: 53 
Number of nonzero links: 164 
Percentage nonzero weights: 5.838377 
Average number of links: 3.09434 
7 regions with no links:
Taiwan Sri Lanka Singapore Philippines Japan Bahrain Indian Ocean
Territories
9 disjoint connected subgraphs
asia_nb_names <- attributes(asia_countries_nb)$region.id
afg_index <- which(asia_nb_names == "Afghanistan")
asia_countries_sf$neighbors <- "other"
asia_countries_sf$neighbors[afg_index] <- "area"
asia_countries_sf$neighbors[asia_countries_nb[[afg_index]]] <- "neighbors"
afg_sf <- asia_countries_sf |> filter(neighbors != "other")
ggplot(afg_sf) +
  geom_sf(aes(fill = neighbors)) +
  theme_bw() +
  scale_fill_manual(
    values = c("gray30", "gray", "white")
  )

mapview(afg_sf, zcol="neighbors", label="geounit")
nb_weights <- asia_countries_nb |>
  spdep::nb2listw(zero.policy=TRUE)
afg_df <- tibble(
  nb_name=asia_countries_sf$geounit[nb_weights$neighbours[[afg_index]]],
  nb_index=nb_weights$neighbours[[afg_index]],
  nb_weight=nb_weights$weights[[afg_index]]
)
afg_df
nb_name nb_index nb_weight
Uzbekistan 3 0.1666667
Turkmenistan 5 0.1666667
Tajikistan 9 0.1666667
Pakistan 18 0.1666667
Iran 34 0.1666667
China 40 0.1666667
nb_dist_weights <- asia_countries_nb |>
  spdep::nb2listwdist(nb_cents, zero.policy=TRUE)
afg_dist_df <- tibble(
  nb_name=asia_countries_sf$geounit[nb_dist_weights$neighbours[[afg_index]]],
  nb_index=nb_dist_weights$neighbours[[afg_index]],
  nb_weight=nb_dist_weights$weights[[afg_index]]
)
afg_dist_df
nb_name nb_index nb_weight
Uzbekistan 3 0.1306825
Turkmenistan 5 0.1251905
Tajikistan 9 0.1321491
Pakistan 18 0.1657872
Iran 34 0.0890133
China 40 0.0298321