Skip to content

Reverse geocoding

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…

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.