【问题标题】:Merge and plot multiple isochrones合并和绘制多个等时线
【发布时间】:2019-10-18 10:48:23
【问题描述】:

我喜欢做什么

我喜欢在地图上绘制多个位置的等时线,这样我就可以直观地找到从任意城镇到最近位置的旅行时间。它应该看起来像一个核密度 2D 图:

library(purrr)
library(ggmap)

locations <- tibble::tribble(
  ~city,     ~lon,      ~lat,
  "Hamburg",  9.992246, 53.550354,
  "Berlin",  13.408163, 52.518527,
  "Rostock", 12.140776, 54.088581
)

data <- map2_dfr(locations$lon, locations$lat, ~ data.frame(lon = rnorm(10000, .x, 0.8),
                                                            lat = rnorm(10000, .y, 0.7)))
ger <- c(left = min(locations$lon) - 1,  bottom = min(locations$lat) - 1, 
         right = max(locations$lon) + 1, top = max(locations$lat) + 1)
get_stamenmap(ger, zoom = 7, maptype = "toner-lite") %>% 
  ggmap() + 
  stat_density_2d(data = data, aes(x= lon, y = lat, fill = ..level.., alpha = ..level..), 
                  geom = "polygon") +
  scale_fill_distiller(palette = "Blues", direction = 1, guide = FALSE) +
  scale_alpha_continuous(range = c(0.1,0.3), guide = FALSE)

我尝试了什么

您可以通过 osrm 轻松获取等时线并使用传单绘制它们。然而,这些等时线是相互独立的。当我绘制它们时,它们相互重叠。

library(osrm)
library(leaflet)
library(purrr)
library(ggmap)

locations <- tibble::tribble(
  ~city,     ~lon,      ~lat,
  "Hamburg",  9.992246, 53.550354,
  "Berlin",  13.408163, 52.518527,
  "Rostock", 12.140776, 54.088581
)


isochrone <- map2(locations$lon, locations$lat, 
                  ~ osrmIsochrone(loc = c(.x, .y),
                                  breaks = seq(0, 120, 30))) %>%
  do.call(what = rbind)

isochrone@data$drive_times <- factor(paste(isochrone@data$min, "bis", 
                                           isochrone@data$max, "Minuten"))

factpal <- colorFactor("Blues", isochrone@data$drive_times, reverse = TRUE)

leaflet() %>% 
  setView(mean(locations$lon), mean(locations$lat), zoom = 7) %>%
  addProviderTiles("Stamen.TonerLite") %>%
  addPolygons(fill = TRUE, stroke = TRUE, color = "black",
              fillColor = ~factpal(isochrone@data$drive_times),
              weight = 0.5, fillOpacity = 0.6,
              data = isochrone, popup = isochrone@data$drive_times,
              group = "Drive Time") %>% 
  addLegend("bottomright", pal = factpal, values = isochrone@data$drive_time,   
            title = "Fahrtzeit")

如何合并这些等时线以使它们不重叠?

【问题讨论】:

    标签: r leaflet gis osrm


    【解决方案1】:

    真的很酷的问题。您要做的是按 ID 合并形状,因此所有 0-30 分钟区域都是一个形状,所有 30-60 分钟区域都是另一个形状,依此类推。其他空间包也有办法做到这一点,但它似乎很适合sf,它使用dplyr-style 函数。

    创建isochrone后,可以将其转换为sf对象,制作同类型的距离标签,按ID分组,调用summarise。汇总sf 对象时的默认值只是一个空间联合,因此您不需要在其中提供函数。

    library(sf)
    library(dplyr)
    
    iso_sf <- st_as_sf(isochrone)
    
    iso_union <- iso_sf %>%
      mutate(label = paste(min, max, sep = "-")) %>%
      group_by(id, label) %>%
      summarise()
    

    我没有方便的leaflet,所以这里只是默认的打印方法:

    plot(iso_union["label"], pal = RColorBrewer::brewer.pal(4, "Blues"))
    

    我不确定那些有突然垂直边缘的区域是怎么回事,但那些也在你的情节中。

    【讨论】:

    • 在重叠区域的最小值是正确的。从右到左中心有一个从 30--60 分钟到 90--120 分钟的跳跃。从右上角中心向左也是如此。右上角和右下角看起来不错。你知道添加这种逻辑的方法吗?
    • 是的,我不知道为什么会有这些跳跃。它们似乎在返回的数据中——也许看看 API 文档,看看是否有问题?当我只用汉堡坐标调用osrmIsochrone 时,绘制它会显示相同的突然垂直线。中断也可能是一个问题:当我将中断设置为seq(0, 60, 10 时,不仅仅是奇怪的跳跃。除此之外,我对 API 不是很熟悉
    • sf 包中找到了带有st_difference 的解决方案。将您的答案标记为正确,因为您为我指明了正确的方向。
    • 酷,如果你知道如何完成我无法得到的东西,你可以发布你自己问题的答案并接受那个
    【解决方案2】:

    我很难使用您使用的 map2 方法,因为它既可以进行联合,也可以使用另一种集合理论(例如创建特定间隔的函数)。相反,我建议创建您创建的图层的栅格图层并将一个不透明度应用于该栅格,就像 ggmap 示例一样。有一篇很棒的博文,我从here(以及来自用户:camille)那里偷了很多代码。

    它使用不同的 API,需要 mapbox,但它是免费的。另一个限制是它不会返回您喜欢的大小的 isocrones,但我在另一个位置重新创建了它,三个点更靠近以证明该方法。

    我也没有费心将创建 isocrone Web 请求的过程矢量化,所以我把它留给了更聪明的人。

    # First be sure to get your mapbox token
    
    library(fasterize)
    library(sf)
    library(mapboxapi)
    library(leaflet)
    #mapboxapi::mb_access_token("Go get the token and put it here",
    #                           install = TRUE, overwrite = TRUE)
    
    isos1 <- mb_isochrone(
      location = c("-149.883234, 61.185765"),
      profile = "driving",
      time = c(5,10,15),
    )
    
    isos2 <- mb_isochrone(
      location = c("-149.928200, 61.191227"),
      profile = "driving",
      time = c(5,10,15),
    )
    isos3 <- mb_isochrone(
      location = c("-149.939484, 61.160192"),
      profile = "driving",
      time = c(5,10,15),
    )
    
    library(sf)
    library(dplyr)
    
    isocrones <- rbind(isos1,isos2,isos3)
    
    iso_sf <- st_as_sf(isocrones)
    
    iso_union <- iso_sf %>%
      group_by(time) %>%
      summarise()
    
    isos_proj <- st_transform(iso_sf, 32615)
    
    template <- raster(isos_proj, resolution = 100)
    
    iso_surface <- fasterize(isos_proj, template, field = "time", fun = "min")
    
    pal <- colorNumeric("viridis", isos_proj$time, na.color = "transparent")
    leaflet() %>%
      addTiles() %>%
      addRasterImage(iso_surface, colors = pal, opacity = 0.5) %>%
      addLegend(values = isos_proj$time, pal = pal,
                title = "Minutes of Travel") %>% 
      addMarkers(lat = c(61.185765, 61.191227, 61.160192), lng = c(-149.883234, -149.928200, -149.939484))
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 1970-01-01
      • 2014-08-14
      • 1970-01-01
      • 1970-01-01
      • 2018-03-30
      • 2014-01-13
      相关资源
      最近更新 更多