【问题标题】:R: Connecting Dots on a MapR:连接地图上的点
【发布时间】:2022-03-05 04:53:23
【问题描述】:

我正在使用 R 编程语言。

使用“传单”库,我为这 5 个城市制作了以下地图:

library(dplyr)
library(leaflet)

map_data <- data.frame("Lat" = c(43.6426, 43.6424, 43.6544, 43.6452, 43.6629), "Long" = c(-79.3871, -79.3860, -79.3807, -79.3806,-79.3957 ), type = c(1,2,3,4,5))

map_data$type = as.factor(map_data$type)



leaflet(map_data) %>%
    addTiles() %>% addCircleMarkers(stroke = FALSE, label = ~type,fillOpacity = 0.8, labelOptions = labelOptions(direction = "center",style = list('color' = "white"),noHide = TRUE, offset=c(0,0), fill = TRUE, opacity = 1, weight = 10, textOnly = TRUE))

在我创建的上面这张地图上,我现在想根据它们的“编号”在地图(路线)上“连接”所有这些“点”(即城市) (例如将1与2连接,2与3连接,3与4连接,4与5连接,5与1连接),并输出路线的“总距离”。我发现以前的帖子显示了如何做到这一点:How to show path and distance on map with leaflet, shiny apps?

我试图调整这篇文章中的代码以适应我的问题:

library(osrm)

route = osrmRoute(c(-79.3871, -79.3860, -79.3807, -79.3806,-79.3957 ), c(43.6426, 43.6424, 43.6544, 43.6452, 43.6629),  overview = 'full')


route_summary = osrmRoute(c(-79.3871, -79.3860, -79.3807, -79.3806,-79.3957 ), c(43.6426, 43.6424, 43.6544, 43.6452, 43.6629), overview = FALSE)

leaflet() %>% addTiles() %>% 
    addCircleMarkers(c(-79.3871, -79.3860, -79.3807, -79.3806,-79.3957 ), c(43.6426, 43.6424, 43.6544, 43.6452, 43.6629), stroke = FALSE, label = ~type,fillOpacity = 0.8, 
                     labelOptions = labelOptions(direction = "center",style = list('color' = "white"),noHide = TRUE, offset=c(0,0), fill = TRUE, opacity = 1, weight = 10, textOnly = TRUE)) %>% 
    addPolylines(route$lon,route$lat, 
                 label = paste(round(route_summary[1]/60), 'hr - ', round(route_summary[2]), 'km'), 
                 labelOptions = labelOptions(noHide = TRUE))

但这会返回以下错误:

Error in UseMethod("metaData") : 
  no applicable method for 'metaData' applied to an object of class "NULL"

谁能告诉我如何解决这个问题?

我想使用“leaflet”而不是“rshiny”来做到这一点。最后,我希望最终的地图看起来像这样(这应该代表旅行商问题中的“单一路径”):

注意:我开始认为问题可能是“osrmRoute()”函数可能无法工作超过 2 个点?

【问题讨论】:

  • 为此,您不需要 OSRM,因为这不是基于道路网络 + 道路限制 + lua 配置文件 + ...它只是基本点连接。您可以使用 sf 包来做到这一点
  • @det:谢谢你的回复!我以前从未使用过 sf 包,我将开始阅读它。它与此问题中的基本传单地图兼容吗?非常感谢!
  • 是否可以在这里修改这篇文章中的代码? stackoverflow.com/questions/32275213/…我会试试这个!
  • 在我的帖子中查看编辑
  • @Det:非常感谢您的编辑!我玩弄了您的代码以获取每个连接上显示的总距离 - 我做的是否正确?非常感谢您的帮助!

标签: r leaflet data-visualization geospatial


【解决方案1】:

一种方法是让您进行 API 调用:

https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md

我将概述您如何做到这一点:

数据

df <- data.frame(
  lon = c(-79.3871, -79.3860, -79.3807, -79.3806,-79.3957), 
  lat = c(43.6426, 43.6424, 43.6544, 43.6452, 43.6629)
)

网址调用

root <- "http://router.project-osrm.org/route/v1/driving/"

options <- c(
  continue_straight = "true",
  overview = "full",
  annotations = "true",
  steps = "true"
) 
  
coords <- df %>% 
  slice(c(seq_len(n()), 1)) %>%
  pmap_chr(str_c, sep = ",") %>% str_c(collapse = ";")
options <- options %>%
  imap_chr(~str_c(.y, "=", .x)) %>%
  str_c(collapse = "&") %>%
  str_c("?", .)

res <- rjson::fromJSON(file = str_c(root, coords, options))

请注意,我已将第一个点添加为第 6 行以制作圆形路线。

地图

res$routes[[1]]$geometry %>%
  googlePolylines::decode() %>%
  .[[1]] %>%
  leaflet() %>%
  addTiles() %>%
  addPolylines(lng = ~lon, lat = ~lat) %>%
  addCircleMarkers(
    data = df,
    stroke = FALSE, 
    label = seq_len(nrow(df)),
    fillOpacity = 0.8, 
    labelOptions = labelOptions(
      direction = "center",
      style = list('color' = "white"),
      noHide = TRUE, 
      offset=c(0,0), 
      fill = TRUE, 
      opacity = 1, 
      weight = 10, 
      textOnly = TRUE
    )
  )   

距离

res$routes[[1]]$distance

这是以米为单位(文档)

编辑

可能有更好的方法来标记折线,但我现在没有时间:

library(sf)

segment_df <- df %>% rbind(df[1,])

d <- segment_df %>%
  st_as_sf(coords = c("lon", "lat"), crs = 4326) %>%
  {st_distance(.[-6,], .[-1,], by_element = TRUE)} %>%
  as.vector() %>%
  round()

m <- leaflet() %>% addTiles()
for(i in seq_len(nrow(segment_df) - 1))
  m <- m %>% addPolylines(
    data = segment_df[i:(i+1),], 
    lng = ~lon, lat = ~lat, color = "red", label = paste(d[[i]], "m"),
    labelOptions(noHide = TRUE, direction = 'top')
  )

m <- m %>% addCircleMarkers(
    data = df,
    stroke = FALSE, 
    label = seq_len(nrow(df)),
    fillOpacity = 0.8, 
    labelOptions = labelOptions(
      direction = "center",
      style = list('color' = "white"),
      noHide = TRUE, 
      offset=c(0,0), 
      fill = TRUE, 
      opacity = 1, 
      weight = 10, 
      textOnly = TRUE
    )
  ) 

如果您只想显示总距离,那么这更容易并且不需要循环,只需将循环替换为:

segment_df %>%
  leaflet() %>%
  addTiles() %>%
  addPolylines(
    lng = ~lon, lat = ~lat, color = "red", 
    label = paste(sum(d), "m"),
    labelOptions = labelOptions(noHide = TRUE, direction = 'top')
  )

我希望您了解(并从地图上看到)这是不可驾驶的。

【讨论】:

  • @det:非常感谢您的回答!我只想问几件事:
  • 1) 是否可以使用与我相同的“图标”?是否可以保留“圆圈图标”上的数字?所以它看起来像这样? i.stack.imgur.com/Pu2hM.jpg
  • 2) 是否可以在地图上显示距离?就像我链接的 stackoverflow 帖子 (i.stack.imgur.com/Pu2hM.jpg) 中显示的一样?
  • 3) 最后,我所说的“循环路线”是什么意思——我只是想制作类似于旅行商问题的“路线”——看起来像这样:physics.aps.org/assets/a38de7c6-00ac-45fb-9bcf-3b3e14a72b41/…。我要做的是将每个点连接到下一个点: ( 1,2), (2,3), (3,4), (4,5), (5,1) 。路线本身不必是“圆形” - 只需以正确的顺序连接点
  • 不明白为什么不把addCircles 替换为addCirclesMarkers 就像你在代码中那样。 res$routes[[1]]$legs %&gt;% map_dbl("distance") 将为您提供两个连续点之间的距离。路线是圆形的,这并不意味着它不会自己交叉。您获得的路线将是按顺序访问您的点的最快路线,您可以将选项 continue straight 设置为 false。
【解决方案2】:

这是我根据@det 的回答尝试的答案:

library(sf)
library(geosphere)
library(dplyr)
library(leaflet)
library(data.table)
library(VPF)



#add a 6th row that is equal to the 1st row -  so that the path loops back

   map_data <- data.frame("Lat" = c(43.6426, 43.6424, 43.6544, 43.6452, 43.6629, 43.6426), "Long" = c(-79.3871, -79.3860, -79.3807, -79.3806,-79.3957, -79.3871 ), type = c(1,2,3,4,5,1))

map_data$type = as.factor(map_data$type)


m1 = leaflet(map_data) %>% addTiles() %>% addCircleMarkers(stroke = FALSE, label = ~type,fillOpacity = 0.8, 
color = ~ifelse(type==1,"red","blue"), labelOptions = labelOptions(direction = "center",style = list('color' = "white"),
noHide = TRUE, offset=c(0,0), fill = TRUE, opacity = 1, weight = 10, textOnly = TRUE))


   m1 %>% addTiles() %>%
    addPolylines(data = map_data, lng = ~Long, lat = ~Lat, group = ~type)

现在,我想计算行程的总距离并将其显示在地图上:

#distances  (https://stackoverflow.com/questions/42119438/calculate-distance-between-two-long-lat-coordinates-in-a-dataframe)

result = rbind(
  cbind(map_data[1:nrow(map_data)-1,c(1,2)], map_data[-1,c(1,2)]),
  cbind(map_data[nrow(map_data), c(1,2)], map_data[1,c(1,2)])
)
colnames(result) <- c("start_lat", "start_long", "end_lat", "end_long")

result$id = as.factor(c(1,2,3,4,5,1))

result = data.frame(result)
 
for (i in 1:nrow(result)) {
    
    a<-result$start_long[i]
    b<-result$start_lat[i]
    c<-result$end_long[i]
    d<-result$end_lat[i]
    
    result$distance[i]<-distm(c(a,b),c(c,d), fun = distHaversine)
}

#total distance of trip in meters
d = result$distance

total_d = signif(sum(d),3)

m1 %>% addPolylines(
    data = map_data, 
    lng = ~Long, lat = ~Lat, color = "blue", label = paste0(total_d, " meters"),
    labelOptions(noHide = TRUE, direction = 'top')
  )

我想我终于明白了 - 非常感谢 @Det!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-19
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 2018-08-14
    • 1970-01-01
    • 2014-06-25
    • 2021-03-07
    相关资源
    最近更新 更多