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_POINTgeometry 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, Redlands, California, 92374" #> $ long_label <chr> "600-620 Home Pl, Redlands, CA, 92374, USA" #> $ 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 County" #> $ 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 34.05204)
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 geometry #> * <chr> <chr> <POINT [°]> #> 1 Alabama Montgomery (-86.30057 32.37772) #> 2 Alaska Juneau (-134.4202 58.3016) #> 3 Arizona Phoenix (-112.097 33.44814) #> 4 Arkansas Little Rock (-92.28899 34.74661) #> 5 California Sacramento (-121.4936 38.57667) #> 6 Colorado Denver (-104.9849 39.73923) #> 7 Connecticut Hartford<br> (-72.6822 41.76405) #> 8 Delaware Dover (-75.51972 39.15731) #> 9 Hawaii Honolulu (-157.8574 21.30744) #> 10 Florida Tallahassee (-84.2813 30.43812) #> # ℹ 40 more rows
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> "Goat Hill Museum Store", "Juneau Post Office - Federal S… #> $ long_label <chr> "Goat Hill Museum Store, 600 Dexter Ave, Montgomery, AL, … #> $ short_label <chr> "Goat Hill Museum Store", "Juneau Post Office - Federal S… #> $ addr_type <chr> "POI", "POI", "POI", "POI", "POI", "POI", "POI", "POI", "… #> $ type_field <chr> "Other Shops and Service", "Post Office", "Specialty Stor… #> $ place_name <chr> "Goat Hill Museum Store", "Juneau Post Office - Federal S… #> $ add_num <chr> "600", "", "1700", "500", "1315", "", "210", "411", "415"… #> $ address <chr> "600 Dexter Ave", "", "1700 W Washington St", "500 Capito… #> $ block <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ sector <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ neighborhood <chr> "", "", "", "", "Downtown Sacramento", "", "Downtown Hart… #> $ district <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ city <chr> "Montgomery", "Juneau", "Phoenix", "Little Rock", "Sacram… #> $ metro_area <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ subregion <chr> "Montgomery County", "Juneau City and Borough", "Maricopa… #> $ region <chr> "Alabama", "Alaska", "Arizona", "Arkansas", "California",… #> $ region_abbr <chr> "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "HI", "FL… #> $ territory <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ postal <chr> "36130", "", "85007", "72201", "95814", "80203", "06106",… #> $ postal_ext <chr> "", "", "", "", "", "", "1501", "3623", "", "", "", "0001… #> $ country_name <chr> "United States", "United States", "United States", "Unite… #> $ country_code <chr> "USA", "USA", "USA", "USA", "USA", "USA", "USA", "USA", "… #> $ geometry <POINT [°]> POINT (-86.30052 32.3777), POINT (-134.4203 58.3015…
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 geometry match_addr long_label short_label #> * <chr> <chr> <POINT [°]> <chr> <chr> <chr> #> 1 Alab… Montgomery (-86.30057 32.37772) Goat Hill Muse… Goat Hill… Goat Hill … #> 2 Alas… Juneau (-134.4202 58.3016) Juneau Post Of… Juneau Po… Juneau Pos… #> 3 Ariz… Phoenix (-112.097 33.44814) Arizona Capito… Arizona C… Arizona Ca… #> 4 Arka… Little Rock (-92.28899 34.74661) Arkansas State… Arkansas … Arkansas S… #> 5 Cali… Sacramento (-121.4936 38.57667) California Sta… Californi… California… #> 6 Colo… Denver (-104.9849 39.73923) Credit Repair Credit Re… Credit Rep… #> 7 Conn… Hartford<b… (-72.6822 41.76405) State of Conne… State of … State of C… #> 8 Dela… Dover (-75.51972 39.15731) Pnc Bank ATM Pnc Bank … Pnc Bank A… #> 9 Hawa… Honolulu (-157.8574 21.30744) Queen Liliuoka… Queen Lil… Queen Lili… #> 10 Flor… Tallahassee (-84.2813 30.43812) Florida Capito… Florida C… Florida Ca… #> # ℹ 40 more rows #> # ℹ 19 more variables: addr_type <chr>, type_field <chr>, place_name <chr>, #> # add_num <chr>, address <chr>, block <chr>, sector <chr>, #> # neighborhood <chr>, district <chr>, city <chr>, metro_area <chr>, #> # subregion <chr>, region <chr>, region_abbr <chr>, territory <chr>, #> # postal <chr>, postal_ext <chr>, country_name <chr>, country_code <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)
#> 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 geometry match_addr long_label short_label #> <chr> <chr> <POINT [°]> <chr> <chr> <chr> #> 1 Alab… Montgomery (-86.30057 32.37772) Goat Hill Muse… Goat Hill… Goat Hill … #> 2 Alas… Juneau (-134.4202 58.3016) Juneau Post Of… Juneau Po… Juneau Pos… #> 3 Ariz… Phoenix (-112.097 33.44814) Arizona Capito… Arizona C… Arizona Ca… #> 4 Arka… Little Rock (-92.28899 34.74661) Arkansas State… Arkansas … Arkansas S… #> 5 Cali… Sacramento (-121.4936 38.57667) California Sta… Californi… California… #> 6 Colo… Denver (-104.9849 39.73923) Credit Repair Credit Re… Credit Rep… #> 7 Conn… Hartford<b… (-72.6822 41.76405) State of Conne… State of … State of C… #> 8 Dela… Dover (-75.51972 39.15731) Pnc Bank ATM Pnc Bank … Pnc Bank A… #> 9 Hawa… Honolulu (-157.8574 21.30744) Queen Liliuoka… Queen Lil… Queen Lili… #> 10 Flor… Tallahassee (-84.2813 30.43812) Florida Capito… Florida C… Florida Ca… #> # ℹ 40 more rows #> # ℹ 19 more variables: addr_type <chr>, type_field <chr>, place_name <chr>, #> # add_num <chr>, address <chr>, block <chr>, sector <chr>, #> # neighborhood <chr>, district <chr>, city <chr>, metro_area <chr>, #> # subregion <chr>, region <chr>, region_abbr <chr>, territory <chr>, #> # postal <chr>, postal_ext <chr>, country_name <chr>, country_code <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) glimpse(geocoded)
#> Rows: 50 #> Columns: 23 #> $ match_addr <chr> "Goat Hill Museum Store", "Juneau Post Office - Federal S… #> $ long_label <chr> "Goat Hill Museum Store, 600 Dexter Ave, Montgomery, AL, … #> $ short_label <chr> "Goat Hill Museum Store", "Juneau Post Office - Federal S… #> $ addr_type <chr> "POI", "POI", "POI", "POI", "POI", "POI", "POI", "POI", "… #> $ type_field <chr> "Other Shops and Service", "Post Office", "Specialty Stor… #> $ place_name <chr> "Goat Hill Museum Store", "Juneau Post Office - Federal S… #> $ add_num <chr> "600", "", "1700", "500", "1315", "", "210", "411", "415"… #> $ address <chr> "600 Dexter Ave", "", "1700 W Washington St", "500 Capito… #> $ block <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ sector <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ neighborhood <chr> "", "", "", "", "Downtown Sacramento", "", "Downtown Hart… #> $ district <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ city <chr> "Montgomery", "Juneau", "Phoenix", "Little Rock", "Sacram… #> $ metro_area <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ subregion <chr> "Montgomery County", "Juneau City and Borough", "Maricopa… #> $ region <chr> "Alabama", "Alaska", "Arizona", "Arkansas", "California",… #> $ region_abbr <chr> "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "HI", "FL… #> $ territory <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "… #> $ postal <chr> "36130", "", "85007", "72201", "95814", "80203", "06106",… #> $ postal_ext <chr> "", "", "", "", "", "", "1501", "3623", "", "", "", "0001… #> $ country_name <chr> "United States", "United States", "United States", "Unite… #> $ country_code <chr> "USA", "USA", "USA", "USA", "USA", "USA", "USA", "USA", "… #> $ geometry <POINT [°]> POINT (-86.30052 32.3777), POINT (-134.4203 58.3015…