Мне нравится наносить изохроны из нескольких мест на карту, чтобы я мог визуально определить время в пути от произвольного города до ближайшего места. Это должно выглядеть как двухмерный график плотности ядра:
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")

Как я могу объединить эти изохроны, чтобы они не перекрывались?





Действительно классный вопрос. Что вы хотите сделать, так это объединить фигуры по идентификатору, чтобы все области 0–30 минут были одной фигурой, все области 30–60 минут — другой и так далее. Есть способы сделать это с помощью других пространственных пакетов, но, похоже, он хорошо подходит для sf, который использует функции в стиле dplyr.
После того, как вы создадите isochrone, вы можете преобразовать его в объект sf, сделать метку расстояния того же типа, сгруппировать по идентификатору и вызвать 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"))

Я не уверен, что случилось с областями с резкими вертикальными краями, но они есть и на вашем графике.
Да я не знаю, почему такие скачки. Кажется, они есть в данных по мере их поступления — может быть, взглянуть на документацию API, чтобы увидеть, есть ли проблема? Когда я вызываю osrmIsochrone только с координатами Гамбурга, на графике отображаются те же резкие вертикальные линии. Также может быть проблема с перерывами: когда я устанавливаю перерывы на seq(0, 60, 10, появляются не только странные скачки. Кроме того, я не очень хорошо знаком с API.
Нашел решение с пакетом with st_difference from sf. Пометил ваш ответ как правильный, потому что вы указали мне правильное направление.
Круто, если вы поняли, как закончить то, что я не смог получить, вы можете опубликовать ответ на свой вопрос и принять его.
Мне было трудно использовать метод map2, который вы использовали, потому что он выполняет как объединение, так и, я думаю, другую теорию множеств, например, функцию для создания определенных интервалов. Вместо этого я бы рекомендовал создать растровый слой из созданных вами слоев и применить одну непрозрачность к этому одному растру, как это делает пример ggmap. В блоге есть отличный пост о том, что я украл много кода у здесь (вместе с пользователем: camille).
Он использует другой API, для которого требуется mapbox, но он бесплатный. Еще одно ограничение заключается в том, что он не будет возвращать изокроны нужного вам размера, но я воссоздал его в другом месте, где три точки расположены ближе друг к другу, чтобы проверить метод.
Я также не стал векторизовать процесс создания веб-запроса isocrone, поэтому я оставляю это кому-то более умному.
# 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))
В перекрывающихся областях минимальное значение является правильным. Справа в левый центр скачок с 30--60 минут до 90--120 минут. То же самое влево от правого верхнего центра. Верхний правый и нижний правый выглядят хорошо. Вы знаете, как добавить эту логику?