I have a point within a state and I want to find 1) the distance to the nearest state border and 2) the bordering state's name. I am able to do 1). For 2). I am able to get the state name corresponding to the nearest boundary, but sometimes this state is the state the point is in, and not actually the bordering state's name.
Modifying and extending the code from an excellent answer of this post (Calculate distance between points and nearest polygon in R), I do:
library(sp)
library(spData)
library(tidyverse)
states <- as(us_states,"Spatial")
#create some points
pts <- data.frame(x1=c(-100.5, -98.6, -98), x2=c(35, 41, 44))
# compute the shortest distance between points and polygons
# (from ?dist2Line): "returns matrix with distance and lon/lat of the nearest point" &
# "the ID (index) of (one of) the nearest objects"; distance is in meters (default)
dist.mat <- geosphere::dist2Line(p = pts, line = states)
# bind results with original points
pts.wit.dist <- cbind(pts, dist.mat)
pts.wit.dist[1:3,]
pts.sp <- sp::SpatialPoints(coords = pts[,c("x1","x2")], # order matters
proj4string = states@proj4string)
plot(pts.sp, col="red")
plot(states, add=TRUE)
# plot arrows to indicate the direction of the great-circle-distance
for (i in 1:nrow(pts.wit.dist)) {
arrows(x0 = pts.wit.dist[i,1],
y0 = pts.wit.dist[i,2],
x1 = pts.wit.dist[i,4],
y1 = pts.wit.dist[i,5],
length = 0.1,
col = "green")
}
a <- pts.wit.dist
a <- a %>% mutate(miles = distance*0.000621)
#create crosswalk between ID (from dist2Line) and state name (from state shapefile)
state_names <- data.frame(us_states$NAME) %>% mutate(ID=row_number())
names(state_names)[1] <- "state"
b <- left_join(pts.wit.dist, state_names, by="ID")
b
This produces:
> b
x1 x2 distance lon lat ID state
1 -100.5 35 45558.45 -100.00039 35.00162 23 Texas
2 -98.6 41 110992.87 -98.59800 40.00294 37 Nebraska
3 -98.0 44 118342.74 -98.49855 42.99856 22 South Dakota
However, the state
is incorrect in all cases. It should be:
> b
x1 x2 distance lon lat ID state
1 -100.5 35 45558.45 -100.00039 35.00162 23 Oklahoma
2 -98.6 41 110992.87 -98.59800 40.00294 37 Kansas
3 -98.0 44 118342.74 -98.49855 42.99856 22 Nebraska
It's tricky because the borders obviously are borders between two states, and I am not sure how to make it give me the state that is not the one in which the point is contained.
How can I do this?