I am trying to get the coordinates of businesses by their name. I have reviewed several questions on using 'geocode' but they all seem to work based on the address. See below two examples trying to get the coordinates of The Westbury Hotel London:
library(ggmap)
geocode("London")
geocode("The Westbury Hotel London") # Returns coordinates of Westbury Road in London
A more complex approach:
require(RJSONIO)
library(ggmap)
geocodeAddress <- function(address) {
require(RJSONIO)
url <- "http://maps.google.com/maps/api/geocode/json?address="
url <- URLencode(paste(url, address, "&sensor=false", sep = ""))
x <- fromJSON(url, simplify = FALSE)
if (x$status == "OK") {
out <- c(x$results[[1]]$geometry$location$lng,
x$results[[1]]$geometry$location$lat)
} else {
out <- NA
}
Sys.sleep(0.2) # API only allows 5 requests per second
out
}
geocodeAddress("The Westbury Hotel London") # Returns London coordinates
Other questions mentioned that it is possible to get coordinates from places with 'geocode' but, at least in my case, it is not working. Any idea on how to get coordinates by business name from google maps hugely appreciated.
You can use the Google Places API to search for places using my googleway package. You'll have to do some work with the results, or refine your query if you want to get the exact business you're after as the API usually returns multiple possible results.
You need a Google API key to use their service
library(googleway)
## your API key
api_key <- "your_api_key_goes_here"
## general search on the name
general_result <- google_places(search_string = "The Westbury Hotel London",
key = api_key)
general_result$results$name
# [1] "The Westbury" "Polo Bar" "The Westbury"
general_result$results$geometry$location
# lat lng
# 1 53.34153 -6.2614740
# 2 51.51151 -0.1426609
# 3 51.59351 -0.0983930
## more refined search using a location
location_result <- google_places(search_string = "The Wesbury Hotel London",
location = c(51.5,0),
key = api_key)
location_result$results$name
# [11] "The Marylebone" "The Chelsea Harbour Hotel"
# "Polo Bar" "The Westbury" "The Gallery at The Westbury"
location_result$results$geometry$location
# lat lng
# 1 51.51801 -0.1498050
# 2 51.47600 -0.1819235
# 3 51.51151 -0.1426609
# 4 51.59351 -0.0983930
# 5 51.51131 -0.1426318
location_result$results$formatted_address
# [1] "37 Conduit St, London W1S 2YF, United Kingdom" "37 Conduit St, London, Mayfair W1S 2YF, United Kingdom"
# [3] "57 Westbury Ave, London N22 6SA, United Kingdom"
Related
I'm trying to reverse geocode with R. I first used ggmap but couldn't get it to work with my API key. Now I'm trying it with googleway.
newframe[,c("Front.lat","Front.long")]
Front.lat Front.long
1 -37.82681 144.9592
2 -37.82681 145.9592
newframe$address <- apply(newframe, 1, function(x){
google_reverse_geocode(location = as.numeric(c(x["Front.lat"],
x["Front.long"])),
key = "xxxx")
})
This extracts the variables as a list but I can't figure out the structure.
I'm struggling to figure out how to extract the address components listed below as variables in newframe
postal_code, administrative_area_level_1, administrative_area_level_2, locality, route, street_number
I would prefer each address component as a separate variable.
Google's API returns the response in JSON. Which, when translated into R naturally forms nested lists. Internally in googleway this is done through jsonlite::fromJSON()
In googleway I've given you the choice of returning the raw JSON or a list, through using the simplify argument.
I've deliberately returned ALL the data from Google's response and left it up to the user to extract the elements they're interested in through usual list-subsetting operations.
Having said all that, in the development version of googleway I've written a few functions to help accessing elements of various API calls. Here are three of them that may be useful to you
## Install the development version
# devtools::install_github("SymbolixAU/googleway")
res <- google_reverse_geocode(
location = c(df[1, 'Front.lat'], df[1, 'Front.long']),
key = apiKey
)
geocode_address(res)
# [1] "45 Clarke St, Southbank VIC 3006, Australia"
# [2] "Bank Apartments, 275-283 City Rd, Southbank VIC 3006, Australia"
# [3] "Southbank VIC 3006, Australia"
# [4] "Melbourne VIC, Australia"
# [5] "South Wharf VIC 3006, Australia"
# [6] "Melbourne, VIC, Australia"
# [7] "CBD & South Melbourne, VIC, Australia"
# [8] "Melbourne Metropolitan Area, VIC, Australia"
# [9] "Victoria, Australia"
# [10] "Australia"
geocode_address_components(res)
# long_name short_name types
# 1 45 45 street_number
# 2 Clarke Street Clarke St route
# 3 Southbank Southbank locality, political
# 4 Melbourne City Melbourne administrative_area_level_2, political
# 5 Victoria VIC administrative_area_level_1, political
# 6 Australia AU country, political
# 7 3006 3006 postal_code
geocode_type(res)
# [[1]]
# [1] "street_address"
#
# [[2]]
# [1] "establishment" "general_contractor" "point_of_interest"
#
# [[3]]
# [1] "locality" "political"
#
# [[4]]
# [1] "colloquial_area" "locality" "political"
After reverse geocoding into newframe$address the address components could be extracted further as follows:
# Make a boolean array of the valid ("OK" status) responses (other statuses may be "NO_RESULTS", "REQUEST_DENIED" etc).
sel <- sapply(c(1: nrow(newframe)), function(x){
newframe$address[[x]]$status == 'OK'
})
# Get the address_components of the first result (i.e. best match) returned per geocoded coordinate.
address.components <- sapply(c(1: nrow(newframe[sel,])), function(x){
newframe$address[[x]]$results[1,]$address_components
})
# Get all possible component types.
all.types <- unique(unlist(sapply(c(1: length(address.components)), function(x){
unlist(lapply(address.components[[x]]$types, function(l) l[[1]]))
})))
# Get "long_name" values of the address_components for each type present (the other option is "short_name").
all.values <- lapply(c(1: length(address.components)), function(x){
types <- unlist(lapply(address.components[[x]]$types, function(l) l[[1]]))
matches <- match(all.types, types)
values <- address.components[[x]]$long_name[matches]
})
# Bind results into a dataframe.
all.values <- do.call("rbind", all.values)
all.values <- as.data.frame(all.values)
names(all.values) <- all.types
# Add columns and update original data frame.
newframe[, all.types] <- NA
newframe[sel,][, all.types] <- all.values
Note that I've only kept the first type given per component, effectively skipping the "political" type as it appears in multiple components and is likely superfluous e.g. "administrative_area_level_1, political".
You can use ggmap:revgeocode easily; look below:
library(ggmap)
df <- cbind(df,do.call(rbind,
lapply(1:nrow(df),
function(i)
revgeocode(as.numeric(
df[i,2:1]), output = "more")
[c("administrative_area_level_1","locality","postal_code","address")])))
#output:
df
# Front.lat Front.long administrative_area_level_1 locality
# 1 -37.82681 144.9592 Victoria Southbank
# 2 -37.82681 145.9592 Victoria Noojee
# postal_code address
# 1 3006 45 Clarke St, Southbank VIC 3006, Australia
# 2 3833 Cec Dunns Track, Noojee VIC 3833, Australia
You can add "route" and "street_number" to the variables that you want to extract but as you can see the second address does not have street number and that will cause an error.
Note: You may also use sub and extract the information from the address.
Data:
df <- structure(list(Front.lat = c(-37.82681, -37.82681), Front.long =
c(144.9592, 145.9592)), .Names = c("Front.lat", "Front.long"), class = "data.frame",
row.names = c(NA, -2L))
Say I have a vector of cities and countries, which may or may not include names of places that have since changed names:
locations <- c("Paris, France", "Sarajevo, Yugoslavia", "Rome, Italy", "Leningrad, Soviet Union", "St Petersburg, Russia")
The problem is that I can't use something like ggmap::geocode since it doesn't appear to work well for locations whose names have changed:
ggmap::geocode(locations, source = "dsk")
lon lat
1 2.34880 48.85341 #Works for Paris
2 NA NA #Didn't work for Sarajevo
3 12.48390 41.89474 #Works for Rome
4 98.00000 60.00000 #Didn't work for the old name of St Petersburg seems to just get the center of Russia
5 30.26417 59.89444 #Worked for St Petersburg
Is there an alternative functions I could use? If I have to "update" the names of the cities & countries, is there an easy method of going through this? I have hundreds of locations that I was looking to collect the longitude and latitude coordinates.
This might not be what you had in mind, but if you use the exact same code with only the city names (and not the countries), at least the two cases that you mentioned (Sarajevo and Leningrad) seem to work fine. You could try to run the function with a modified locations vector including just the city names, and see if you still get errors. Something like this:
(cities <- gsub(',.*', '', locations))
## [1] "Paris" "Sarajevo" "Rome" "Leningrad" "St Petersburg"
cbind(ggmap::geocode(cities, source = 'dsk'), cities)
## lon lat cities
## 1 2.34880 48.85341 Paris
## 2 18.35644 43.84864 Sarajevo
## 3 12.48390 41.89474 Rome
## 4 30.26417 59.89444 Leningrad
## 5 30.26417 59.89444 St Petersburg
I have some Chinese addresses to get geocode. I'm pretty sure once it worked by codes like this
geocode("黎明侨村",source = "google")
but somehow now it doesn't work at more, which throws error like:
http://maps.googleapis.com/maps/api/staticmap?center=wenzhou&zoom=13&size=640x640&scale=2&maptype=roadmap&language=en-EN&sensor=false
Noted the message shows :"language=en-EN",I wonder is there a parameter to change the language to Chinese? Many thanks.
PS. I've already set R locale to china.
Sys.getlocale()
[1] "LC_COLLATE=Chinese (Simplified)_China.936;LC_CTYPE=Chinese
(Simplified)_China.936;LC_MONETARY=Chinese
(Simplified)_China.936;LC_NUMERIC=C;LC_TIME=Chinese
(Simplified)_China.936"
There doesn't appear to be a 'language' argument for ggmap::geocde.
However, you can use my googleway package as it does expose the language argument.
To use it, you will also need a Google Maps Geocode API key
library(googleway)
## your api key goes here
api_key <- ""
google_geocode(address = "黎明侨村", language = "CN", key = api_key)
# $results
# address_components
# 1 Chezhan Avenue, Lucheng, Wenzhou, Zhejiang, China, 325003, Chezhan Ave, Lucheng, Wenzhou, Zhejiang, CN, 325003, route, political, sublocality, sublocality_level_1, locality, political, administrative_area_level_1, political, country, political, postal_code
# formatted_address geometry.location.lat geometry.location.lng
# 1 China, Zhejiang, Wenzhou, Lucheng, Chezhan Ave, 黎明侨村巷第86号 邮政编码: 325003 28.01603 120.6839
# geometry.location_type geometry.viewport.northeast.lat geometry.viewport.northeast.lng geometry.viewport.southwest.lat
# 1 APPROXIMATE 28.01738 120.6852 28.01468
# geometry.viewport.southwest.lng place_id types
# 1 120.6825 ChIJtSTHeutkTzQRafAmWKVXhaI establishment, point_of_interest
#
# $status
# [1] "OK"
I'm trying to write a simple code to check if a street address exists:
In my first try I put the write address and it gives me the correct adress:
addr <- '2147 Newhall Street,Santa Clara,CA 95050'
url = paste('http://maps.google.com/maps/api/geocode/xml?address=', addr,'&sensor=false',sep='')
doc = xmlTreeParse(url)
root = xmlRoot(doc)
lat = xmlValue(root[['result']][['geometry']][['location']][['lat']])
long = xmlValue(root[['result']][['geometry']][['location']][['lng']])
lat
"37.3386004"
long
"-121.9405759"
But if I write a wrong street address it's still giving me co-ordinates:
addr <- 'xyz,Santa Clara,CA 95050' # set your address here
url = paste('http://maps.google.com/maps/api/geocode/xml?address=', addr,'&sensor=false',sep='')
doc = xmlTreeParse(url)
root = xmlRoot(doc)
lat = xmlValue(root[['result']][['geometry']][['location']][['lat']])
long = xmlValue(root[['result']][['geometry']][['location']][['lng']])
lat
"37.3539663"
long
"-121.9529992"
I'm sure the street address above does not exist, but I'm still getting some coordinates. Is there anyway I can return an NA value or some flag if there is no valid street address?
There's already a nice wrapper of the Google Maps geocoding API in the ggmap package. If you set its output parameter to more, it will return a loctype which indicates if the address is precisely matched (rooftop) or an approximation (approximate, range_interpolated, geometric_center). See the documentation for further detail.
library(ggmap)
addr <- '2147 Newhall Street,Santa Clara,CA 95050'
geocode(addr, 'more')
# Information from URL : http://maps.googleapis.com/maps/api/geocode/json?address=2147%20Newhall%20Street,Santa%20Clara,CA%2095050&sensor=false
# lon lat type loctype address north
# 1 -121.9406 37.3386 street_address rooftop 2147 newhall st, santa clara, ca 95050, usa 37.33995
# south east west street_number route locality
# 1 37.33725 -121.9392 -121.9419 2147 Newhall Street Santa Clara
# administrative_area_level_2 administrative_area_level_1 country postal_code
# 1 Santa Clara County California United States 95050
addr <- 'xyz,Santa Clara,CA 95050'
geocode(addr, 'more')
# Information from URL : http://maps.googleapis.com/maps/api/geocode/json?address=xyz,Santa%20Clara,CA%2095050&sensor=false
# lon lat type loctype address north south
# 1 -121.953 37.35397 postal_code approximate santa clara, ca 95050, usa 37.37448 37.32314
# east west postal_code locality administrative_area_level_2
# 1 -121.9309 -121.9703 95050 Santa Clara Santa Clara County
# administrative_area_level_1 country
# 1 California United States
I have a GPS coordinates of several points and I want to know if they are on a highway, or trunk road, or minor road, and it would be even greater if I could identify a road name. I'm using R leaflet to draw maps and I can see with OpenStreetMap that different types of roads are colored differently, and I wonder how I can extract this information. It's not a problem to use Google maps instead if it will solve my problem.
I would appreciate any help.
You can use revgeocode() from ggmap:
library(ggmap)
gc <- c(-73.596706, 45.485501)
revgeocode(gc)
Which gives:
#[1] "4333 Rue Sherbrooke O, Westmount, QC H3Z 1E2, Canada"
Note: As per mentioned in the comments, this method uses Google Maps API, not OpenStreetMap. You have a limit of 2500 queries per day. You can always check how many queries you have left using geocodeQueryCheck()
From the package documentation:
reverse geocodes a longitude/latitude location using Google Maps. Note
that in most cases by using this function you are agreeing to the
Google Maps API Terms of Service at
https://developers.google.com/maps/terms.
Update
If you need more detailed information, use output = "all" and extract the components you need:
lst <- list(
g1 = c(-73.681069, 41.433155),
g2 = c(-73.643196, 41.416240),
g3 = c(-73.653324, 41.464168)
)
res <- lapply(lst, function(x) revgeocode(x, output = "all")[[1]][[1]][[1]][[2]])
Which gives:
#$g1
#$g1$long_name
#[1] "Highway 52"
#
#$g1$short_name
#[1] "NY-52"
#
#$g1$types
#[1] "route"
#
#
#$g2
#$g2$long_name
#[1] "Carmel Avenue"
#
#$g2$short_name
#[1] "US-6"
#
#$g2$types
#[1] "route"
#
#
#$g3
#$g3$long_name
#[1] "Wakefield Road"
#
#$g3$short_name
#[1] "Wakefield Rd"
#
#$g3$types
#[1] "route"
Using Google's API it's not possible to identify the type of road (yet - they may introduce that capability in the future).
But you can use their Roads API to get the road details for a given set of coordinates.
I've written the googleway package that accesses the roads API through the functions google_snapToRoads() and google_nearestRoads(), and if you have a premium account you can use google_speedLimits()
In all calls to Google's API you need a Google API key enabled on each API you are using.
library(googleway)
df_points <- data.frame(lat = c(60.1707, 60.172, 60.192),
lon = c(24.9426, 24.86, 24.89))
## plot the points on a map
google_map(key = map_key) %>%
add_markers(df_points)
nearRoads <- google_nearestRoads(df_points, key = api_key)
nearRoads
# $snappedPoints
# location.latitude location.longitude originalIndex placeId
# 1 60.17070 24.94272 0 ChIJNX9BrM0LkkYRIM-cQg265e8
# 2 60.17229 24.86028 1 ChIJpf7azXMKkkYRsk5L-U5W4ZQ
# 3 60.17229 24.86028 1 ChIJpf7azXMKkkYRs05L-U5W4ZQ
# 4 60.19165 24.88997 2 ChIJN1s1vhwKkkYRKGm4l5KmISI
# 5 60.19165 24.88997 2 ChIJN1s1vhwKkkYRKWm4l5KmISI
In these results, the originalIndex value tells you which of the orignal df_points the value is refering to (where 0 == the first row of df_points, 1 == the second row of df_points)
The placeId value is Google's unique key that identifies each place in their database. So you can then use Google's Places API to get the information about those places
roadDetails <- lapply(nearRoads$snappedPoints$placeId, function(x){
google_place_details(place_id = x, key = api_key)
})
## road address
lapply(roadDetails, function(x){
x[['result']][['formatted_address']]
})
# [[1]]
# [1] "Rautatientori, 00100 Helsinki, Finland"
#
# [[2]]
# [1] "Svedjeplogsstigen 7-9, 00340 Helsingfors, Finland"
#
# [[3]]
# [1] "Svedjeplogsstigen 18-10, 00340 Helsingfors, Finland"
#
# [[4]]
# [1] "Meilahdentie, 00250 Helsinki, Finland"
#
# [[5]]
# [1] "Meilahdentie, 00250 Helsinki, Finland"