Построение улиц с помощью ggmap и geom_path

Мне нравится строить улицы с ggmap в определенной области. Я получил данные от osm через appass. Он работает очень хорошо для большинства улиц с geom_path. Однако некоторые улицы перепутаны. Любые намеки приветствуются.

Посмотрите на http://overpass-turbo.eu/ для желаемого результата. Вы можете найти запрос в R-коде ниже.

library(httr)
library(tidyverse)
#> ── Attaching packages ─────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
#> ✔ ggplot2 2.2.1     ✔ purrr   0.2.4
#> ✔ tibble  1.4.2     ✔ dplyr   0.7.4
#> ✔ tidyr   0.8.0     ✔ stringr 1.3.0
#> ✔ readr   1.1.1     ✔ forcats 0.3.0
#> ── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
#> ✖ dplyr::filter() masks stats::filter()
#> ✖ dplyr::lag()    masks stats::lag()
library(ggmap)
library(rlist)


# Get data from overpass api
query <- paste('[out:json];',
  '(way["highway"~"primary|residential"](53.5970, 9.9010, 53.6050, 9.9080););',
  '(._;>;);',
  'out body;')
url <- 'http://overpass-api.de/api/interpreter'
r <- POST(url = url, body = query, encode = 'json')


# Tidy data
nodes <- content(r)$elements %>% list.filter(type == 'node')
ways <- content(r)$elements %>% list.filter(type == 'way')

df_nodes <- nodes %>% 
  list.select(type, id, lat, lon) %>%
  bind_rows()

df_ways <- ways %>% 
  lapply(function(x) list.append(x, street = x$tags$name)) %>%
  list.select(street, nodes)
df_ways <- map(df_ways, function(x) x %>% as_tibble) %>% 
  bind_rows() %>% 
  mutate(id = unlist(nodes))

df <- df_ways %>% left_join(df_nodes, by = 'id')
head(df)
#> # A tibble: 6 x 6
#>   street           nodes            id type    lat   lon
#>   <chr>            <list>        <dbl> <chr> <dbl> <dbl>
#> 1 Reichsbahnstraße <int [1]>  38893884 node   53.6  9.91
#> 2 Reichsbahnstraße <int [1]>  55079985 node   53.6  9.91
#> 3 Reichsbahnstraße <int [1]>  38893882 node   53.6  9.91
#> 4 Reichsbahnstraße <int [1]>  38893881 node   53.6  9.91
#> 5 Reichsbahnstraße <int [1]> 380820539 node   53.6  9.91
#> 6 Reichsbahnstraße <int [1]>  38893879 node   53.6  9.91


# Get map
lat <- (max(df$lat)+min(df$lat))/2
lon <- (max(df$lon)+min(df$lon))/2
hamburg <- get_map(location = c(lon = lon, lat = lat), zoom = 16)
#> Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=53.601726,9.90531&zoom=16&size=640x640&scale=2&maptype=terrain&language=en-EN&sensor=false


# Plot
ggmap(hamburg) +
  geom_path(data = df, aes(x = lon, y = lat, color = street), size = 2)
#> Warning: Removed 3 rows containing missing values (geom_path).

'Actual Output''Desired Output'

Ответы

Ответ 1

У вас будет такая проблема, когда на улице много ветвей, так как geom_path() будет просто связывать каждую две последовательные точки с прямой линией.

В качестве примера возьмем "Reichsbahnstraße":

lon <- df %>% filter(street == "Reichsbahnstraße") %>% .$lon
lat <- df %>% filter(street == "Reichsbahnstraße") %>% .$lat
lat[1] == lat[41] & lon[1] == lon[41]
# returns TRUE

geom_path() начинается с точки 1 (точка пересечения, см. ниже), рисует одну часть улицы (собирается на северо-восток), а затем снова возвращается к точке пересечения (индекс 41), чтобы нарисовать следующую ветку.

Что бы вы могли сделать, чтобы избежать этого, вернитесь к точке пересечения по той же дороге, прежде чем рисовать другую ветку (например, вместо c(7, 8, 9, 10, 7, 6) выполните c(7, 8, 9, 10, 9, 8, 7, 6)). Как будто бы вы сделали бы, если бы пытались нарисовать улицу карандашом, не снимая его с листа бумаги.

enter image description here