user14345711
user14345711

Reputation: 19

How to get the neighboring counties of all counties based on the content of the file?

I have a shp file. I want to get the names of neighboring counties in all regions according to the latitude and longitude in the file. I found that some regions obviously have neighboring counties, but I didn’t get the neighboring counties when I ran the code. I don't know what was wrong.

library(tidyverse)
library(plyr)
library(sf)
library(readxl)

> county <-st_read('D:/county.shp',stringsAsFactors = FALSE)
> neighbor_counties <- function(subcounty){
   name <- st_touches(subcounty, county)
   county[unlist(name), ]$NAME
 }

> output <- vector("list", nrow(county))
> names(output) <- county$NAME
> for (i in seq_len(nrow(county))) {
   output[[i]] <- suppressWarnings(neighbor_counties(county[i,]))
  }
> output
> head(output)

> neighbor <- output %>%
   ldply(data.frame) %>%
   set_names("ori_county", "neighbor_county")

Upvotes: 0

Views: 723

Answers (1)

Jindra Lacko
Jindra Lacko

Reputation: 8749

Your example is not exactly reproducible, but we are lucky to have the nc.shp shapefile that ships with {sf} available.

So consider this code; it is built on sf::st_touches() function, with the county shapefile passed as argument twice (once for the touching counties, and once for the counties being touched). Sparse = TRUE makes it return a list of indexes of neighboring counties.

To find names of neighbors of a particular county you need to know the index of the county of interest, and then subset the list of neighbors accordingly. You will get indices of the neighboring counties.

As for the second part of your question (expressed in comments) = how to get from a list of indices to a data frame of neighbors - I suggest creating a function returning a data frame, and then applying it via purrr::map_dfr() to the vector of indices as starting points; consider the code provided and amend as necessary. It should give you a start...

library(sf)

shape <- st_read(system.file("shape/nc.shp", package="sf")) # included with sf package

# a list of neighbors 
neighbors <- st_touches(shape, # first 
                        shape, # second
                        sparse = T)

# neighbors of County Mecklenburg (as in Charlotte of Mecklenburg-Strelitz)

# index of Mecklenburg cnty
idx_strelitz <- which(shape$NAME == 'Mecklenburg') 

# index of neighbors of Mecklenburg cnty
nbr_mecklenburg <- neighbors[idx_strelitz][[1]]

# names of neighbours of cnty Meckl.
shape$NAME[nbr_mecklenburg]
# [1] "Iredell"  "Lincoln"  "Cabarrus" "Gaston"   "Union"   

# a visual check
plot(st_geometry(shape))
plot(shape[idx_strelitz, ], col = "blue", add = T)
plot(shape[nbr_mecklenburg,], col = "red", add = T)

NC with red & blue counties

# second question: get pairs of names as a data frame

# a function returning data frame of neighbors of a given cnty
nbr_pairs <- function(idx)  {
  data.frame(ori_county = rep(shape$NAME[idx], length(neighbors[[idx]])), 
             neighbor_county = shape$NAME[neighbors[[idx]]])
}

# check - cnty Mecklemburg
nbr_pairs(idx_strelitz)
#    ori_county neighbor_county
# 1 Mecklenburg         Iredell
# 2 Mecklenburg         Lincoln
# 3 Mecklenburg        Cabarrus
# 4 Mecklenburg          Gaston
# 5 Mecklenburg           Union

# apply to list of indices
pairs_of_names <- purrr::map_dfr(seq_along(neighbors),
                                 nbr_pairs)

Upvotes: 2

Related Questions