Построение улиц с помощью 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).
Ответы
Ответ 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)
). Как будто бы вы сделали бы, если бы пытались нарисовать улицу карандашом, не снимая его с листа бумаги.