Latitude Longitude Coordinates to State Code in R

Latitude Longitude Coordinates to State Code in R

Here are two options, one using sf and one using sp package functions. sf is the more modern (and, here in 2020, recommended) package for analyzing spatial data, but in case it's still useful, I am leaving my original 2012 answer showing how to do this with sp-related functions.


Method 1 (using sf):

library(sf)
library(spData)

## pointsDF: A data.frame whose first column contains longitudes and
## whose second column contains latitudes.
##
## states: An sf MULTIPOLYGON object with 50 states plus DC.
##
## name_col: Name of a column in `states` that supplies the states'
## names.
lonlat_to_state <- function(pointsDF,
states = spData::us_states,
name_col = "NAME") {
## Convert points data.frame to an sf POINTS object
pts <- st_as_sf(pointsDF, coords = 1:2, crs = 4326)

## Transform spatial data to some planar coordinate system
## (e.g. Web Mercator) as required for geometric operations
states <- st_transform(states, crs = 3857)
pts <- st_transform(pts, crs = 3857)

## Find names of state (if any) intersected by each point
state_names <- states[[name_col]]
ii <- as.integer(st_intersects(pts, states))
state_names[ii]
}

## Test the function with points in Wisconsin, Oregon, and France
testPoints <- data.frame(x = c(-90, -120, 0), y = c(44, 44, 44))
lonlat_to_state(testPoints)
## [1] "Wisconsin" "Oregon" NA

If you need higher resolution state boundaries, read in your own vector data as an sf object using sf::st_read() or by some other means. One nice option is to install the rnaturalearth package and use it to load a state vector layer from rnaturalearthhires. Then use the lonlat_to_state() function we just defined as shown here:

library(rnaturalearth)
us_states_ne <- ne_states(country = "United States of America",
returnclass = "sf")
lonlat_to_state(testPoints, states = us_states_ne, name_col = "name")
## [1] "Wisconsin" "Oregon" NA

For very accurate results, you can download a geopackage containing GADM-maintained administrative borders for the United States from this page. Then, load the state boundary data and use them like this:

USA_gadm <- st_read(dsn = "gadm36_USA.gpkg", layer = "gadm36_USA_1")
lonlat_to_state(testPoints, states = USA_gadm, name_col = "NAME_1")
## [1] "Wisconsin" "Oregon" NA

Method 2 (using sp):

Here is a function that takes a data.frame of lat-longs within the lower 48 states, and for each point, returns the state in which it is located.

Most of the function simply prepares the SpatialPoints and SpatialPolygons objects needed by the over() function in the sp package, which does the real heavy lifting of calculating the 'intersection' of points and polygons:

library(sp)
library(maps)
library(maptools)

# The single argument to this function, pointsDF, is a data.frame in which:
# - column 1 contains the longitude in degrees (negative in the US)
# - column 2 contains the latitude in degrees

lonlat_to_state_sp <- function(pointsDF) {
# Prepare SpatialPolygons object with one SpatialPolygon
# per state (plus DC, minus HI & AK)
states <- map('state', fill=TRUE, col="transparent", plot=FALSE)
IDs <- sapply(strsplit(states$names, ":"), function(x) x[1])
states_sp <- map2SpatialPolygons(states, IDs=IDs,
proj4string=CRS("+proj=longlat +datum=WGS84"))

# Convert pointsDF to a SpatialPoints object
pointsSP <- SpatialPoints(pointsDF,
proj4string=CRS("+proj=longlat +datum=WGS84"))

# Use 'over' to get _indices_ of the Polygons object containing each point
indices <- over(pointsSP, states_sp)

# Return the state names of the Polygons object containing each point
stateNames <- sapply(states_sp@polygons, function(x) x@ID)
stateNames[indices]
}

# Test the function using points in Wisconsin and Oregon.
testPoints <- data.frame(x = c(-90, -120), y = c(44, 44))

lonlat_to_state_sp(testPoints)
[1] "wisconsin" "oregon" # IT WORKS

is there an R code to separate coordinates latitudes and longitudes with differing lengths?

I already answered your updated question in a comment to my original answer, but I can appreciate that it may have been hard to understand as a comment.

First, we'll combine the steps that I laid out earlier into a function parse_line().

parse_line <- function(line){
coord_pairs <- strsplit(line, split = ";")
# Separate the latitude-longitude components
coords <- strsplit(unlist(coord_pairs), split = ",") # We have to unlist coord_pairs because strsplit() expects a character vector

# coords is a list of two-element vectors (lat and long)
# Combine the elements of coords into a matrix, then coerce to a dataframe

df <- as.data.frame(do.call(rbind, coords))
}

Then we'll use parse_line() as a building block for a similar function parse_lines().

parse_lines <- function(cluster_ids, lines){
parsed_dfs <- Map(function(x, y) cbind(x, parse_line(y)), cluster_ids, lines)
# Iterates over all the pairs of cluster_ids and lines
# and adds the cluster_id as a column to the dataframe produced by calling
# parse_line() on the corresponding line
combined_df <- do.call(rbind, parsed_dfs) # Combines the list of dataframes into a single dataframe
colnames(combined_df) <- c("Cluster_ID", "Latitude", "Longitude") # Adds appropriate column names
return(combined_df)
}

parse_lines(cluster_ids, lat_long)

How do I automatically determine a state given the latitude and longitude / coordinates?

Use function over from sp package:

library(geojsonio)
library(sp)

# get usa polygon data
# http://eric.clst.org/tech/usgeojson/
usa <- geojson_read(
"http://eric.clst.org/assets/wiki/uploads/Stuff/gz_2010_us_040_00_500k.json",
what = "sp"
)

df$state <- NA

# compare points
for (i in 1:nrow(df)) {
coords <- c(df$origin_lon[i], df$origin_lat[i])
if(any(is.na(coords))) next
point <- sp::SpatialPoints(
matrix(
coords,
nrow = 1
)
)
sp::proj4string(point) <- sp::proj4string(usa)
polygon_check <- sp::over(point, usa)
df$state[i] <- as.character(polygon_check$NAME)
}

> head(df)
origin_coords origin_lat origin_lon state
1 31.9618,-83.0588 31.9618 -83.0588 Georgia
2 44.8782,-69.4718 44.8782 -69.4718 Maine
3 37.3894,-121.8868 37.3894 -121.8868 California
4 36.0485,-93.5044 36.0485 -93.5044 Arkansas
5 37.652,-120.7292 37.6520 -120.7292 California
6 33.7942,-84.2018 33.7942 -84.2018 Georgia

Convert latitude and longitude coordinates to country name in R

Thanks for the carefully constructed question.
It required just a couple of line changes to be able to use rworldmap (containing up-to-date countries) see below. I'm not an expert on CRS but I don't think the change I had to make to the proj4string makes any difference. Others might like to comment on that.

This worked for me & gave :

> coords2country(points)
[1] United Kingdom Belgium Germany Austria
[5] Republic of Serbia

All the best,
Andy

library(sp)
library(rworldmap)

# The single argument to this function, points, is a data.frame in which:
# - column 1 contains the longitude in degrees
# - column 2 contains the latitude in degrees
coords2country = function(points)
{
countriesSP <- getMap(resolution='low')
#countriesSP <- getMap(resolution='high') #you could use high res map from rworldxtra if you were concerned about detail

# convert our list of points to a SpatialPoints object

# pointsSP = SpatialPoints(points, proj4string=CRS(" +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0"))

#setting CRS directly to that from rworldmap
pointsSP = SpatialPoints(points, proj4string=CRS(proj4string(countriesSP)))


# use 'over' to get indices of the Polygons object containing each point
indices = over(pointsSP, countriesSP)

# return the ADMIN names of each country
indices$ADMIN
#indices$ISO3 # returns the ISO3 code
#indices$continent # returns the continent (6 continent model)
#indices$REGION # returns the continent (7 continent model)
}

Convert latitude/longitude to state plane coordinates

When you set the coordinates for your data, you have to set the latitude before the longitude.

In other words, change:

coordinates(data) <- ~ long + lat

to

coordinates(data) <- ~ lat+long

And it should work.

library(rgdal)
library(sp)
data = data.frame(long=c(41.20,40.05), lat=c(-86.14,-88.15))
coordinates(data) <- ~ lat+long
proj4string(data) <- CRS("+init=epsg:4326")
data.proj <- spTransform(data, CRS("+init=epsg:2790"))
data.proj

Gave me this output:

SpatialPoints:
lat long
[1,] 483979.0 505572.6
[2,] 315643.7 375568.0
Coordinate Reference System (CRS) arguments: +init=epsg:2790 +proj=tmerc
+lat_0=36.66666666666666 +lon_0=-88.33333333333333 +k=0.9999749999999999 +x_0=300000
+y_0=0 +ellps=GRS80 +units=m +no_defs

Getting Latitude and Longitude in R with only city, state

If you'd like to go ahead and add state abbreviation, this should work for you:

df <- DF %>%
geocode(city = Cities, state = st, method = "census")


Related Topics



Leave a reply



Submit