Often you may coordinates of locations but need their addresses as well. Reverse geocoding finds an address associated with a location on earth.
Use arcgisgeocode::reverse_geocode()
to perform reverse geocoding. Using this fuction you can
- reverse geocode an
sfc_POINT
geometry column from the sf package - reverse geocode a matrix of coordinates
- reverse geocode a single location as a length 2 vector e.g.
c(-117, 34)
Reverse geocode a single point
First, load the R package.
library(arcgisgeocode)
You can reverse geocode a single longitude/latitude pair as a length 2 vector with reverse_geocode()
.
# Find addresses from locations res <- reverse_geocode(c(-117.172, 34.052)) dplyr::glimpse(res)
#> Rows: 1 #> Columns: 23 #> $ match_addr <chr> "600-620 Home Pl… #> $ long_label <chr> "600-620 Home Pl… #> $ short_label <chr> "600-620 Home Pl" #> $ addr_type <chr> "StreetAddress" #> $ type_field <chr> "" #> $ place_name <chr> "" #> $ add_num <chr> "604" #> $ address <chr> "604 Home Pl" #> $ block <chr> "" #> $ sector <chr> "" #> $ neighborhood <chr> "South Redlands" #> $ district <chr> "" #> $ city <chr> "Redlands" #> $ metro_area <chr> "" #> $ subregion <chr> "San Bernardino … #> $ region <chr> "California" #> $ region_abbr <chr> "CA" #> $ territory <chr> "" #> $ postal <chr> "92374" #> $ postal_ext <chr> "" #> $ country_name <chr> "United States" #> $ country_code <chr> "USA" #> $ geometry <POINT [°]> POINT (-117.172 …
It is important to note that when you are not using an sfc_POINT
object, the coordinate reference system is not known. So it is assumed to be EPSG:4326
. If you provide values outside of [-180, 180] and [-90, 90] for longitude or latitude, an error will occur.
Reverse geocode from an sf object
More commonly, you may have an sf object that you want to reverse geocode their locations. To demonstrate this, you will reverse geocode a csv of state capitals.
First, read the csv file into a data.frame and convert it to an sf object.
library(sf) library(dplyr) # USA State Capitals fp <- "https://analysis-1.maps.arcgis.com/sharing/rest/content/items/85bcfca158d641b99e7579b47cfee91e/data" # read the csv capitals <- readr::read_csv(fp) |> # convert to an sf object with EPSG:4326 st_as_sf( coords = c("longitude", "latitude"), crs = 4326 ) capitals
#> Simple feature collection with 50 features and 2 fields #> Geometry type: POINT #> Dimension: XY #> Bounding box: xmin: -157.8574 ymin: 21.30744 xmax: -69.78169 ymax: 58.3016 #> Geodetic CRS: WGS 84 #> # A tibble: 50 × 3 #> name description #> * <chr> <chr> #> 1 Alabama Montgomery #> 2 Alaska Juneau #> 3 Arizona Phoenix #> 4 Arkansas Little Rock #> 5 California Sacramento #> 6 Colorado Denver #> 7 Connecticut Hartford<br> #> 8 Delaware Dover #> 9 Hawaii Honolulu #> 10 Florida Tallahassee #> # ℹ 40 more rows #> # ℹ 1 more variable: #> # geometry <POINT [°]>
Use reverse_geocode()
with the geometry column from the capitals to create a new sf object with the address information.
geocoded <- reverse_geocode(st_geometry(capitals)) glimpse(geocoded)
#> Rows: 50 #> Columns: 23 #> $ match_addr <chr> "Psiquicos del A… #> $ long_label <chr> "Psiquicos del A… #> $ short_label <chr> "Psiquicos del A… #> $ addr_type <chr> "POI", "POI", "P… #> $ type_field <chr> "Other Professio… #> $ place_name <chr> "Psiquicos del A… #> $ add_num <chr> "600", "709", "1… #> $ address <chr> "600 Dexter Ave"… #> $ block <chr> "", "", "", "", … #> $ sector <chr> "", "", "", "", … #> $ neighborhood <chr> "", "", "", "", … #> $ district <chr> "", "", "", "", … #> $ city <chr> "Montgomery", "J… #> $ metro_area <chr> "", "", "", "", … #> $ subregion <chr> "Montgomery Coun… #> $ region <chr> "Alabama", "Alas… #> $ region_abbr <chr> "AL", "AK", "AZ"… #> $ territory <chr> "", "", "", "", … #> $ postal <chr> "36130", "99801"… #> $ postal_ext <chr> "", "", "", "", … #> $ country_name <chr> "United States",… #> $ country_code <chr> "USA", "USA", "U… #> $ geometry <POINT [°]> POINT (-86…
Then, you can use dplyr (or base R via cbind()
) to combine the two datasets. In this example, the geometry column from the reverse geocoding results is drops. This prevents dplyr from renaming the duplicate columns and preserves the sf class.
bind_cols( capitals, st_drop_geometry(geocoded) )
#> Simple feature collection with 50 features and 24 fields #> Geometry type: POINT #> Dimension: XY #> Bounding box: xmin: -157.8574 ymin: 21.30744 xmax: -69.78169 ymax: 58.3016 #> Geodetic CRS: WGS 84 #> # A tibble: 50 × 25 #> name description #> * <chr> <chr> #> 1 Alabama Montgomery #> 2 Alaska Juneau #> 3 Arizona Phoenix #> 4 Arkansas Little Rock #> 5 California Sacramento #> 6 Colorado Denver #> 7 Connecticut Hartford<br> #> 8 Delaware Dover #> 9 Hawaii Honolulu #> 10 Florida Tallahassee #> # ℹ 40 more rows #> # ℹ 23 more variables: #> # geometry <POINT [°]>, #> # match_addr <chr>, #> # long_label <chr>, #> # short_label <chr>, #> # addr_type <chr>, …
Alternatively, you can accomplish this using a more esoteric and tidyverse-centric approach. The below is an option that uses mutate()
to create a new column which is an sf object. Then, it uses tidyr::unnest()
to unnest the newly created sf column.
capitals |> mutate( address_info = st_drop_geometry( reverse_geocode(geometry) ) ) |> tidyr::unnest(address_info)
#> [working] (15 + 0) -> 10 -> 25 | #> ■■■■■… #> Simple feature collection with 50 features and 24 fields #> Geometry type: POINT #> Dimension: XY #> Bounding box: xmin: -157.8574 ymin: 21.30744 xmax: -69.78169 ymax: 58.3016 #> Geodetic CRS: WGS 84 #> # A tibble: 50 × 25 #> name description #> <chr> <chr> #> 1 Alabama Montgomery #> 2 Alaska Juneau #> 3 Arizona Phoenix #> 4 Arkansas Little Rock #> 5 California Sacramento #> 6 Colorado Denver #> 7 Connecticut Hartford<br> #> 8 Delaware Dover #> 9 Hawaii Honolulu #> 10 Florida Tallahassee #> # ℹ 40 more rows #> # ℹ 23 more variables: #> # geometry <POINT [°]>, #> # match_addr <chr>, #> # long_label <chr>, #> # short_label <chr>, #> # addr_type <chr>, …
Reverse geocoding a matrix of coordinates
There are other times where you may have your coordinates stored as a matrix with two columns. reverse_geocode()
accepts a 2 column numeric matrix as an input to its location
argument.
For the sake of example, the coordinates are extracted as a matrix using sf::st_coordinates()
.
coords <- st_coordinates(capitals) head(coords)
#> X Y #> [1,] -86.30057 32.37772 #> [2,] -134.42021 58.30160 #> [3,] -112.09696 33.44814 #> [4,] -92.28899 34.74661 #> [5,] -121.49363 38.57667 #> [6,] -104.98486 39.73923
Pass this matrix directly into reverse_geocode()
.
geocoded <- reverse_geocode(coords)
#> [working] (18 + 0) -> 10 -> 22 | #> ■■■■■…[working] (15 + 0) -> 10 -> 25 | #> ■■■■■…
glimpse(geocoded)
#> Rows: 50 #> Columns: 23 #> $ match_addr <chr> "Psiquicos del A… #> $ long_label <chr> "Psiquicos del A… #> $ short_label <chr> "Psiquicos del A… #> $ addr_type <chr> "POI", "POI", "P… #> $ type_field <chr> "Other Professio… #> $ place_name <chr> "Psiquicos del A… #> $ add_num <chr> "600", "709", "1… #> $ address <chr> "600 Dexter Ave"… #> $ block <chr> "", "", "", "", … #> $ sector <chr> "", "", "", "", … #> $ neighborhood <chr> "", "", "", "", … #> $ district <chr> "", "", "", "", … #> $ city <chr> "Montgomery", "J… #> $ metro_area <chr> "", "", "", "", … #> $ subregion <chr> "Montgomery Coun… #> $ region <chr> "Alabama", "Alas… #> $ region_abbr <chr> "AL", "AK", "AZ"… #> $ territory <chr> "", "", "", "", … #> $ postal <chr> "36130", "99801"… #> $ postal_ext <chr> "", "", "", "", … #> $ country_name <chr> "United States",… #> $ country_code <chr> "USA", "USA", "U… #> $ geometry <POINT [°]> POINT (-86…