Объединить и построить несколько изохрон

Что я люблю делать

Мне нравится наносить изохроны из нескольких мест на карту, чтобы я мог визуально определить время в пути от произвольного города до ближайшего места. Это должно выглядеть как двухмерный график плотности ядра:

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")

Объединить и построить несколько изохрон

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
0
986
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Действительно классный вопрос. Что вы хотите сделать, так это объединить фигуры по идентификатору, чтобы все области 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"))

Я не уверен, что случилось с областями с резкими вертикальными краями, но они есть и на вашем графике.

В перекрывающихся областях минимальное значение является правильным. Справа в левый центр скачок с 30--60 минут до 90--120 минут. То же самое влево от правого верхнего центра. Верхний правый и нижний правый выглядят хорошо. Вы знаете, как добавить эту логику?

Birger 03.06.2019 07:24

Да я не знаю, почему такие скачки. Кажется, они есть в данных по мере их поступления — может быть, взглянуть на документацию API, чтобы увидеть, есть ли проблема? Когда я вызываю osrmIsochrone только с координатами Гамбурга, на графике отображаются те же резкие вертикальные линии. Также может быть проблема с перерывами: когда я устанавливаю перерывы на seq(0, 60, 10, появляются не только странные скачки. Кроме того, я не очень хорошо знаком с API.

camille 03.06.2019 19:07

Нашел решение с пакетом with st_difference from sf. Пометил ваш ответ как правильный, потому что вы указали мне правильное направление.

Birger 04.06.2019 20:50

Круто, если вы поняли, как закончить то, что я не смог получить, вы можете опубликовать ответ на свой вопрос и принять его.

camille 04.06.2019 21:48

Мне было трудно использовать метод 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))

Другие вопросы по теме