Open kieranzu opened 5 years ago
I have identified what the issue here is. The current Google Distance Matrix API will be billed at $0.01 for an advanced API call and $0.005 for a standard call. If no date/time/traffic model is provided the gmapsdistance function will send the API call with Traffic model = "None" and the current time and date. The inclusion of a traffic model and specified time and date however is classified as an advanced call and so is billed at twice the price. A simple api call requires simply the origin, destination, mode of travel and API Key. This then is billed at the lower tariff. I have changed the function to include fewer variables to ensure it results in only an standard API call. I suggest that this is either incorporated as a separate function in the package or there is a way to specify whether a simple or advance API call is required withing the gmapsdistance function.
Also note that the "&sensorfalse element of the api call is now also defunct
require("pacman")
p_load("dplyr",
"gmapsdistance",
"RODBC",
"data.table",
"XML",
"RCurl")
gmapsdistancesimple = function(origin, destination, combinations = "all", mode, key = get.api.key(), shape = "wide") {
# If mode of transportation not recognized:
if (!(mode %in% c("driving", "walking", "bicycling", "transit"))) {
stop(
"Mode of transportation not recognized. Mode should be one of ",
"'bicycling', 'transit', 'driving', 'walking' "
)
}
# If combinations not recognized:
if (!(combinations %in% c("all", "pairwise"))) {
stop(
"Combinations between origin and destination not recognized. Combinations should be one of ",
"'all', 'pairwise' "
)
}
if(combinations == "pairwise" && length(origin) != length(destination)){
stop("Size of origin and destination vectors must be the same when using the option: combinations == 'pairwise'")
}
if(combinations == "all"){
data = expand.grid(or = origin, de = destination)
} else if(combinations == "pairwise"){
data = data.frame(or = origin, de = destination)
}
n = dim(data)
n = n[1]
data$Time = NA
data$Distance = NA
data$status = "OK"
for (i in 1:1:n){
# Set up URL
url = paste0("maps.googleapis.com/maps/api/distancematrix/xml?origins=", data$or[i],
"&destinations=", data$de[i],
"&mode=", mode,
"&units=metric")
# Add Google Maps API key if it exists
if (!is.null(key)) {
# use https and google maps key (after replacing spaces just in case)
key = gsub(" ", "", key)
url = paste0("https://", url, "&key=", key)
} else {
# use http otherwise
url = paste0("http://", url)
}
# Call the Google Maps Webservice and store the XML output in webpageXML
webpageXML = xmlParse(getURL(url));
# Extract the results from webpageXML
results = xmlChildren(xmlRoot(webpageXML))
# Check the status of the request and throw an error if the request was denied
request.status = as(unlist(results$status[[1]]), "character")
# Check for google API errors
if (!is.null(results$error_message)) {
stop(paste(c("Google API returned an error: ", xmlValue(results$error_message)), sep = ""))
}
if (request.status == "REQUEST_DENIED") {
set.api.key(NULL)
data$status[i] = "REQUEST_DENIED"
# stop(as(results$error_message[1]$text, "character"))
}
# Extract results from results$row
rowXML = xmlChildren(results$row[[1L]])
Status = as(rowXML$status[1]$text, "character")
if (Status == "ZERO_RESULTS") {
# stop(paste0("Google Maps is not able to find a route between ", data$or[i]," and ", data$de[i]))
data$status[i] = "ROUTE_NOT_FOUND"
}
if (Status == "NOT_FOUND") {
# stop("Google Maps is not able to find the origin (", data$or[i],") or destination (", data$de[i], ")")
data$status[i] = "PLACE_NOT_FOUND"
}
# Check whether the user is over their query limit
if (Status == "OVER_QUERY_LIMIT") {
stop("You have exceeded your allocation of API requests for today.")
}
if(data$status[i] == "OK"){
data$Distance[i] = as(rowXML$distance[1]$value[1]$text, "numeric")
data$Time[i] = as(rowXML[['duration']][1L]$value[1L]$text, "numeric")
}
}
datadist = data[c("or", "de", "Distance")]
datatime = data[c("or", "de", "Time")]
datastat = data[c("or", "de", "status")]
if(n > 1){
if(shape == "wide" && combinations == "all"){
Distance = reshape(datadist,
timevar = "de",
idvar = c("or"),
direction = "wide")
Time = reshape(datatime,
timevar = "de",
idvar = c("or"),
direction = "wide")
Stat = reshape(datastat,
timevar = "de",
idvar = c("or"),
direction = "wide")
} else{
Distance = datadist
Time = datatime
Stat = datastat
}
} else{
Distance = data$Distance[i]
Time = data$Time[i]
Stat = data$status[i]
}
# Make a list with the results
output = list(
Time = Time,
Distance = Distance,
Status = Stat
)
return(output)
}
this issue has been resolved in version 4.0.0 / on CRAN as of 2022-04-26; the cheaper call is given priority whenever possible
I have encountered an issue where trying to do a standard API call results in google thinking the call is for the advanced distance matrix and thus charging twice as much. Having spoken to google maps support and reviewed your package documentation I am unclear as to why this is. I wondered if you could shed some light on this. If there is no time or traffic condition stated does it use a default value. If so is this causing the issue? Below is an example of the code that will cause the issue to arise.