R代码gmapsdistance
R Code gmapsdistance
我有以下代码用于查找两个位置之间的旅行时间。我正在使用 vba 调用脚本,这就是命令 args 显示在顶部的原因,但出于测试目的,我只是设置变量。这一直工作到今天(没有改变任何东西),现在我在 运行 结果行中不断收到此错误: rowXML[[dur]] 中的错误:下标超出范围。
有没有人知道可能导致此问题的原因或它意味着什么?
代码:
#install and load necessary packages
#install.packages("gmapsdistance")
#install.packages("devtools")
args<-commandArgs(trailingOnly=T)
library("gmapsdistance")
library("devtools")
devtools::install_github("rodazuero/gmapsdistance")
#input variables from excel
orig <- args[1]
dest <- args[2]
filePath <- args[3]
api_key <- args[4]
orig <- "London"
dest <- "Paris"
filePath <- "C:/Users/gabby/Documents/SeniorYear/SeniorDesign/TravelTimes/Travel_Times.csv"
api_key <- "############################"
set.api.key(api_key)
#calls google maps and finds the time
results = gmapsdistance(origin = c(orig, dest), destination = c(dest, orig), mode = "driving", traffic_model = "best_guess",
key = api_key, combinations = "pairwise", shape = "wide")
#put results in a data frame
results2 <- data.frame(results)
#rename the column headings
names(results2) <- c("Origin","Destination", "Time", "X1","X2","Distance","X3","X4","Status")
#delete repeated origin/destination columns
results2$X1 <- NULL
results2$X2 <- NULL
results2$X3 <- NULL
results2$X4 <- NULL
#convert seconds to minutes
results2$Time <- results2$Time/60
#convert meters to miles
results2$Distance <- results2$Distance*0.000621371
#add extra column and input the current date/time for documentation
results2[,"Date"] <- NA
results2[1,"Date"] <- format(Sys.time(), "%a %b %d %X %Y %Z")
#write results2 to a csv file and save it in my folder
write.csv(results2, file = filePath)
我得到了一个API密钥,重现了你的问题,然后逐行调试了底层函数的源代码。
错误是由以下原因引起的:
data$Time[i] = as(rowXML[[dur]][1L]$value[1L]$text,
"numeric")
因为对象 dur
仅包含以下内容:
> dur
[1] "duration" "duration_in_traffic"
因此 rowXML[[dur]]
抛出错误。我不确定该指责哪里,但通常 API 的变化比围绕它们构建的包更快。
尽管如此,您仍然可以像我一样使用源代码来获得结果。自己清理结果只需要多几行代码:
xmlChildren(results$row[[1L]])
$status
<status>OK</status>
$duration
<duration>
<value>20185</value>
<text>5 hours 36 mins</text>
</duration>
$distance
<distance>
<value>459271</value>
<text>459 km</text>
</distance>
$duration_in_traffic
<duration_in_traffic>
<value>20957</value>
<text>5 hours 49 mins</text>
</duration_in_traffic>
attr(,"class")
[1] "XMLInternalNodeList" "XMLNodeList"
根据你在评论中的要求,这里有更多关于我为得到这个所做的工作。
首先,从调用此函数中获取参数并从中创建对象(即 运行 每个参数作为创建对象的单独命令)。接下来,加载 XML
和 Rcurl
库。此外,将您的 API 键放入一个名为 key
.
的对象中
之后,您只需获取函数的源代码,然后逐行 运行,跳过定义函数调用的部分。在此过程中,您可以创建少量未使用的参数并将其设置为 ""
.
# function (origin, destination, combinations = "all", mode, key = #get.api.key(),
# shape = "wide", avoid = "", departure = "now", dep_date = "",
# dep_time = "", traffic_model = "best_guess", arrival = "",
# arr_date = "", arr_time = "") # don't run this
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 %in% c("all", "pairwise"))) {
stop("Combinations between origin and destination not recognized. Combinations should be one of ",
"'all', 'pairwise' ")
}
if (!(avoid %in% c("", "tolls", "highways", "ferries", "indoor"))) {
stop("Avoid parameters not recognized. Avoid should be one of ",
"'tolls', 'highways', 'ferries', 'indoor' ")
}
if (!(traffic_model %in% c("best_guess", "pessimistic", "optimistic"))) {
stop("Traffic model not recognized. Traffic model should be one of ",
"'best_guess', 'pessimistic', 'optimistic'")
}
seconds = "now"
seconds_arrival = ""
UTCtime = strptime("1970-01-01 00:00:00", "%Y-%m-%d %H:%M:%OS",
tz = "GMT")
min_secs = round(as.numeric(difftime(as.POSIXlt(Sys.time(),
"GMT"), UTCtime, units = "secs")))
if (dep_date != "" && dep_time != "") {
depart = strptime(paste(dep_date, dep_time), "%Y-%m-%d %H:%M:%OS",
tz = "GMT")
seconds = round(as.numeric(difftime(depart, UTCtime,
units = "secs")))
}
if (departure != "now") {
seconds = departure
}
if (departure != "now" && departure < min_secs) {
stop("The departure time has to be some time in the future!")
}
if (dep_date != "" && dep_time == "") {
stop("You should also specify a departure time in the format HH:MM:SS UTC")
}
if (dep_date == "" && dep_time != "") {
stop("You should also specify a departure date in the format YYYY-MM-DD UTC")
}
if (dep_date != "" && dep_time != "" && seconds < min_secs) {
stop("The departure time has to be some time in the future!")
}
if (arr_date != "" && arr_time != "") {
arriv = strptime(paste(arr_date, arr_time), "%Y-%m-%d %H:%M:%OS",
tz = "GMT")
seconds_arrival = round(as.numeric(difftime(arriv, UTCtime,
units = "secs")))
}
if (arrival != "") {
seconds_arrival = arrival
}
if (arrival != "" && arrival < min_secs) {
stop("The arrival time has to be some time in the future!")
}
if (arr_date != "" && arr_time == "") {
stop("You should also specify an arrival time in the format HH:MM:SS UTC")
}
if (arr_date == "" && arr_time != "") {
stop("You should also specify an arrival date in the format YYYY-MM-DD UTC")
}
if (arr_date != "" && arr_time != "" && seconds_arrival <
min_secs) {
stop("The arrival time has to be some time in the future!")
}
if ((dep_date != "" || dep_time != "" || departure != "now") &&
(arr_date != "" || arr_time != "" || arrival != "")) {
stop("Cannot input departure and arrival times. Only one can be used at a time. ")
}
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"
avoidmsg = ""
if (avoid != "") {
avoidmsg = paste0("&avoid=", avoid)
}
for (i in 1:1:n) {
url = paste0("maps.googleapis.com/maps/api/distancematrix/xml?origins=",
data$or[i], "&destinations=", data$de[i], "&mode=",
mode, "&sensor=", "false", "&units=metric", "&departure_time=",
seconds, "&traffic_model=", traffic_model, avoidmsg)
if (!is.null(key)) {
key = gsub(" ", "", key)
url = paste0("https://", url, "&key=", key)
}
else {
url = paste0("http://", url)
}
webpageXML = xmlParse(getURL(url))
results = xmlChildren(xmlRoot(webpageXML))
request.status = as(unlist(results$status[[1]]), "character")
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"
}
rowXML = xmlChildren(results$row[[1L]])
Status = as(rowXML$status[1]$text, "character")
if (Status == "ZERO_RESULTS") {
data$status[i] = "ROUTE_NOT_FOUND"
}
if (Status == "NOT_FOUND") {
data$status[i] = "PLACE_NOT_FOUND"
}
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")
dur = grep("duration", names(rowXML), value = TRUE)
data$Time[i] = as(rowXML[[dur]][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]
}
output = list(Time = Time, Distance = Distance, Status = Stat)
如果您不局限于使用 gmapsdistance
,我的 googleway
软件包会给您相同的结果。唯一的区别是目前您必须指定 departure_time
。
library(googleway)
orig <- "London"
dest <- "Paris"
api_key <- "your_api_key"
result <- google_distance(origin = c(orig, dest), destination = c(orig, dest),
mode = "driving",
traffic_model = "best_guess",
departure_time = Sys.time() + 60,
key = api_key)
result$rows$elements
# [[1]]
# distance.text distance.value duration.text duration.value status
# 1 1 m 0 1 min 0 OK
# 2 459 km 459271 5 hours 36 mins 20185 OK
#
# [[2]]
# distance.text distance.value duration.text duration.value status
# 1 470 km 470366 5 hours 25 mins 19484 OK
# 2 1 m 0 1 min 0 OK
我有以下代码用于查找两个位置之间的旅行时间。我正在使用 vba 调用脚本,这就是命令 args 显示在顶部的原因,但出于测试目的,我只是设置变量。这一直工作到今天(没有改变任何东西),现在我在 运行 结果行中不断收到此错误: rowXML[[dur]] 中的错误:下标超出范围。
有没有人知道可能导致此问题的原因或它意味着什么?
代码:
#install and load necessary packages
#install.packages("gmapsdistance")
#install.packages("devtools")
args<-commandArgs(trailingOnly=T)
library("gmapsdistance")
library("devtools")
devtools::install_github("rodazuero/gmapsdistance")
#input variables from excel
orig <- args[1]
dest <- args[2]
filePath <- args[3]
api_key <- args[4]
orig <- "London"
dest <- "Paris"
filePath <- "C:/Users/gabby/Documents/SeniorYear/SeniorDesign/TravelTimes/Travel_Times.csv"
api_key <- "############################"
set.api.key(api_key)
#calls google maps and finds the time
results = gmapsdistance(origin = c(orig, dest), destination = c(dest, orig), mode = "driving", traffic_model = "best_guess",
key = api_key, combinations = "pairwise", shape = "wide")
#put results in a data frame
results2 <- data.frame(results)
#rename the column headings
names(results2) <- c("Origin","Destination", "Time", "X1","X2","Distance","X3","X4","Status")
#delete repeated origin/destination columns
results2$X1 <- NULL
results2$X2 <- NULL
results2$X3 <- NULL
results2$X4 <- NULL
#convert seconds to minutes
results2$Time <- results2$Time/60
#convert meters to miles
results2$Distance <- results2$Distance*0.000621371
#add extra column and input the current date/time for documentation
results2[,"Date"] <- NA
results2[1,"Date"] <- format(Sys.time(), "%a %b %d %X %Y %Z")
#write results2 to a csv file and save it in my folder
write.csv(results2, file = filePath)
我得到了一个API密钥,重现了你的问题,然后逐行调试了底层函数的源代码。
错误是由以下原因引起的:
data$Time[i] = as(rowXML[[dur]][1L]$value[1L]$text,
"numeric")
因为对象 dur
仅包含以下内容:
> dur [1] "duration" "duration_in_traffic"
因此 rowXML[[dur]]
抛出错误。我不确定该指责哪里,但通常 API 的变化比围绕它们构建的包更快。
尽管如此,您仍然可以像我一样使用源代码来获得结果。自己清理结果只需要多几行代码:
xmlChildren(results$row[[1L]])
$status <status>OK</status> $duration <duration> <value>20185</value> <text>5 hours 36 mins</text> </duration> $distance <distance> <value>459271</value> <text>459 km</text> </distance> $duration_in_traffic <duration_in_traffic> <value>20957</value> <text>5 hours 49 mins</text> </duration_in_traffic> attr(,"class") [1] "XMLInternalNodeList" "XMLNodeList"
根据你在评论中的要求,这里有更多关于我为得到这个所做的工作。
首先,从调用此函数中获取参数并从中创建对象(即 运行 每个参数作为创建对象的单独命令)。接下来,加载 XML
和 Rcurl
库。此外,将您的 API 键放入一个名为 key
.
之后,您只需获取函数的源代码,然后逐行 运行,跳过定义函数调用的部分。在此过程中,您可以创建少量未使用的参数并将其设置为 ""
.
# function (origin, destination, combinations = "all", mode, key = #get.api.key(), # shape = "wide", avoid = "", departure = "now", dep_date = "", # dep_time = "", traffic_model = "best_guess", arrival = "", # arr_date = "", arr_time = "") # don't run this
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 %in% c("all", "pairwise"))) {
stop("Combinations between origin and destination not recognized. Combinations should be one of ",
"'all', 'pairwise' ")
}
if (!(avoid %in% c("", "tolls", "highways", "ferries", "indoor"))) {
stop("Avoid parameters not recognized. Avoid should be one of ",
"'tolls', 'highways', 'ferries', 'indoor' ")
}
if (!(traffic_model %in% c("best_guess", "pessimistic", "optimistic"))) {
stop("Traffic model not recognized. Traffic model should be one of ",
"'best_guess', 'pessimistic', 'optimistic'")
}
seconds = "now"
seconds_arrival = ""
UTCtime = strptime("1970-01-01 00:00:00", "%Y-%m-%d %H:%M:%OS",
tz = "GMT")
min_secs = round(as.numeric(difftime(as.POSIXlt(Sys.time(),
"GMT"), UTCtime, units = "secs")))
if (dep_date != "" && dep_time != "") {
depart = strptime(paste(dep_date, dep_time), "%Y-%m-%d %H:%M:%OS",
tz = "GMT")
seconds = round(as.numeric(difftime(depart, UTCtime,
units = "secs")))
}
if (departure != "now") {
seconds = departure
}
if (departure != "now" && departure < min_secs) {
stop("The departure time has to be some time in the future!")
}
if (dep_date != "" && dep_time == "") {
stop("You should also specify a departure time in the format HH:MM:SS UTC")
}
if (dep_date == "" && dep_time != "") {
stop("You should also specify a departure date in the format YYYY-MM-DD UTC")
}
if (dep_date != "" && dep_time != "" && seconds < min_secs) {
stop("The departure time has to be some time in the future!")
}
if (arr_date != "" && arr_time != "") {
arriv = strptime(paste(arr_date, arr_time), "%Y-%m-%d %H:%M:%OS",
tz = "GMT")
seconds_arrival = round(as.numeric(difftime(arriv, UTCtime,
units = "secs")))
}
if (arrival != "") {
seconds_arrival = arrival
}
if (arrival != "" && arrival < min_secs) {
stop("The arrival time has to be some time in the future!")
}
if (arr_date != "" && arr_time == "") {
stop("You should also specify an arrival time in the format HH:MM:SS UTC")
}
if (arr_date == "" && arr_time != "") {
stop("You should also specify an arrival date in the format YYYY-MM-DD UTC")
}
if (arr_date != "" && arr_time != "" && seconds_arrival <
min_secs) {
stop("The arrival time has to be some time in the future!")
}
if ((dep_date != "" || dep_time != "" || departure != "now") &&
(arr_date != "" || arr_time != "" || arrival != "")) {
stop("Cannot input departure and arrival times. Only one can be used at a time. ")
}
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"
avoidmsg = ""
if (avoid != "") {
avoidmsg = paste0("&avoid=", avoid)
}
for (i in 1:1:n) {
url = paste0("maps.googleapis.com/maps/api/distancematrix/xml?origins=",
data$or[i], "&destinations=", data$de[i], "&mode=",
mode, "&sensor=", "false", "&units=metric", "&departure_time=",
seconds, "&traffic_model=", traffic_model, avoidmsg)
if (!is.null(key)) {
key = gsub(" ", "", key)
url = paste0("https://", url, "&key=", key)
}
else {
url = paste0("http://", url)
}
webpageXML = xmlParse(getURL(url))
results = xmlChildren(xmlRoot(webpageXML))
request.status = as(unlist(results$status[[1]]), "character")
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"
}
rowXML = xmlChildren(results$row[[1L]])
Status = as(rowXML$status[1]$text, "character")
if (Status == "ZERO_RESULTS") {
data$status[i] = "ROUTE_NOT_FOUND"
}
if (Status == "NOT_FOUND") {
data$status[i] = "PLACE_NOT_FOUND"
}
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")
dur = grep("duration", names(rowXML), value = TRUE)
data$Time[i] = as(rowXML[[dur]][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]
}
output = list(Time = Time, Distance = Distance, Status = Stat)
如果您不局限于使用 gmapsdistance
,我的 googleway
软件包会给您相同的结果。唯一的区别是目前您必须指定 departure_time
。
library(googleway)
orig <- "London"
dest <- "Paris"
api_key <- "your_api_key"
result <- google_distance(origin = c(orig, dest), destination = c(orig, dest),
mode = "driving",
traffic_model = "best_guess",
departure_time = Sys.time() + 60,
key = api_key)
result$rows$elements
# [[1]]
# distance.text distance.value duration.text duration.value status
# 1 1 m 0 1 min 0 OK
# 2 459 km 459271 5 hours 36 mins 20185 OK
#
# [[2]]
# distance.text distance.value duration.text duration.value status
# 1 470 km 470366 5 hours 25 mins 19484 OK
# 2 1 m 0 1 min 0 OK