Looking at OpenStreeMap underlying data I see that the data that I want is at the relation level and when I query the OSM using osmdata in R I cannot get this data. https://www.openstreetmap.org/relation/15019644
The code that I have is as follows:
bbx <- getbb("Ireland")
y <- bbx %>%
opq(timeout = 25*100,osm_types = 'relation')%>%
add_osm_feature("plant:source","wind") %>%
osmdata_sf()
I can get the osm_point data, but not the osm_relation data that aggregates, and joins the points.
osmdata_sf
seems to transform only polygon and line relations, but you can get point relation data from xml response, transform it to data.frames / tibbles and, if needed, join to sf
point object:
library(osmdata)
library(sf)
library(xml2)
library(dplyr)
library(tidyr)
library(purrr)
# Overpass response as XML
wind_xml <-
getbb("Ireland") |>
opq(timeout = 25*100,osm_types = "relation") |>
add_osm_feature("plant:source","wind") |>
osmdata_xml()
# XML response to "regular" osmdata sf object
wind_sf <- osmdata_sf(doc = wind_xml)
# find all relations with `<member type="node" ... >` nodes,
# use realtion id as list names,
# from every relation find all node members, extract attributes (type, ref, role),
# turn named lists into frames with bind_rows,
# bind resulting frames, use list names for `relation` column
relation_nodes <-
xml_find_all(wind_xml, "//relation[member[@type='node']]") %>%
set_names(map(.,xml_attr, "id")) |>
map(\(x) xml_find_all(x, "./member[@type='node']") |> xml_attrs()) |>
map(bind_rows) |>
list_rbind(names_to = "relation")
relation_nodes
#> # A tibble: 2,578 × 4
#> relation type ref role
#> <chr> <chr> <chr> <chr>
#> 1 6949501 node 2616376676 generator
#> 2 6949501 node 2616376686 generator
#> 3 6949501 node 2616376653 generator
#> 4 6949501 node 2616376627 generator
#> 5 6949501 node 2616376638 generator
#> 6 6949501 node 2616376608 generator
#> 7 6949501 node 2616376612 generator
#> 8 6949501 node 2616376595 generator
#> 9 6949501 node 2616376588 generator
#> 10 6949501 node 2616376560 generator
#> # ℹ 2,568 more rows
# similar aporach as before, but now extract all tag elements,
# pivot wider, tag keys to columns
relation_tags <-
xml_find_all(wind_xml, "//relation[member[@type='node']]") %>%
set_names(map(.,xml_attr, "id")) |>
map(\(x) xml_find_all(x, "./tag") |> xml_attrs()) |>
map(bind_rows) |>
list_rbind(names_to = "relation") |>
pivot_wider(names_from = k, values_from = v)
relation_tags
#> # A tibble: 239 × 37
#> relation name operator plant:output:electri…¹ `plant:source` power `repd:id`
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 6949501 Tangy SSE 18.7 MW wind plant 3467
#> 2 8384695 Slie… Platina 54 MW wind plant <NA>
#> 3 8555637 Coom… <NA> 8.5 MW wind plant <NA>
#> 4 9195703 Bool… Brookfi… 30 MW wind plant <NA>
#> 5 9196204 Ball… Greenco… 48.3 MW wind plant <NA>
#> 6 9285446 Gruig <NA> 25 MW wind plant 3241
#> 7 9285684 Creg… Gaelect… 13.8 MW wind plant 4653
#> 8 9296897 Loug… B9 / Re… 10.5 MW wind plant 4680
#> 9 9296910 Bin … <NA> 9 MW wind plant 3113
#> 10 9298972 Alta… <NA> 26 MW wind plant 3575
#> # ℹ 229 more rows
#> # ℹ abbreviated name: ¹`plant:output:electricity`
#> # ℹ 30 more variables: site <chr>, type <chr>, `plant:method` <chr>,
#> # wikidata <chr>, wikipedia <chr>, alt_name <chr>, fixme <chr>, owner <chr>,
#> # start_date <chr>, `operator:wikidata` <chr>, `operator:wikipedia` <chr>,
#> # website <chr>, turbines <chr>, note <chr>, `alt_name:en` <chr>,
#> # `name:en` <chr>, `name:ga` <chr>, old_operator <chr>, old_website <chr>, …
Form here you can for example join relation_nodes
to osm_points
object and create MULTIPOINT
s of relations:
wind_multipoint_sf <-
wind_sf$osm_points |>
inner_join(relation_nodes, by = join_by(osm_id == ref)) |>
group_by(relation) |>
summarise()
wind_multipoint_sf
#> Simple feature collection with 239 features and 1 field
#> Geometry type: GEOMETRY
#> Dimension: XY
#> Bounding box: xmin: -10.10166 ymin: 51.62229 xmax: -5.656859 ymax: 55.5659
#> Geodetic CRS: WGS 84
#> # A tibble: 239 × 2
#> relation geometry
#> <chr> <GEOMETRY [°]>
#> 1 10102897 POINT (-6.186668 54.93249)
#> 2 10664357 MULTIPOINT ((-8.635368 53.12872), (-8.63826 53.12859), (-8.634468 5…
#> 3 11113896 MULTIPOINT ((-6.365975 52.17676), (-6.363355 52.17386), (-6.360543 …
#> 4 11113897 MULTIPOINT ((-8.226164 54.13107), (-8.228405 54.13296), (-8.231114 …
#> 5 11113898 MULTIPOINT ((-7.79886 52.52894), (-7.795786 52.5316), (-7.771544 52…
#> 6 11198793 MULTIPOINT ((-7.303677 54.92539), (-7.310983 54.92871), (-7.3077 54…
#> 7 11198794 MULTIPOINT ((-7.26855 54.91813), (-7.25883 54.91843), (-7.258841 54…
#> 8 11198795 MULTIPOINT ((-6.744441 54.94007), (-6.748539 54.93631), (-6.745422 …
#> 9 12864417 MULTIPOINT ((-6.257705 55.03091), (-6.256246 55.02987), (-6.254009 …
#> 10 12864418 MULTIPOINT ((-6.44266 55.0026), (-6.450407 55.0003), (-6.450604 54.…
#> # ℹ 229 more rows
Or perhaps just join both relation_nodes
& relation_tags
frames to points sf
object:
wind_joined_sf <-
wind_sf$osm_points |>
as_tibble() |>
st_as_sf() |>
inner_join(relation_nodes, by = join_by(osm_id == ref)) |>
relocate(relation:role, .after = 1) |>
left_join(relation_tags, by = "relation") |>
janitor::remove_empty()
#> value for "which" not specified, defaulting to c("rows", "cols")
wind_joined_sf
#> Simple feature collection with 2578 features and 88 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: -10.10166 ymin: 51.62229 xmax: -5.656859 ymax: 55.5659
#> Geodetic CRS: WGS 84
#> # A tibble: 2,578 × 89
#> osm_id relation type.x role name.x base_height check_date colour
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 370577265 15261309 node generator <NA> <NA> <NA> <NA>
#> 2 370577267 15261309 node generator <NA> <NA> <NA> <NA>
#> 3 410873377 14995512 node generator <NA> <NA> <NA> <NA>
#> 4 410873379 14995512 node generator <NA> <NA> <NA> <NA>
#> 5 410873382 14995512 node generator <NA> <NA> <NA> <NA>
#> 6 410873383 14995512 node generator <NA> <NA> <NA> <NA>
#> 7 432678296 14175147 node generator <NA> <NA> <NA> <NA>
#> 8 885438777 14170264 node generator <NA> <NA> <NA> <NA>
#> 9 885438788 14170264 node generator <NA> <NA> <NA> <NA>
#> 10 885438789 14170264 node generator <NA> <NA> <NA> <NA>
#> # ℹ 2,568 more rows
#> # ℹ 81 more variables: construction <chr>,
#> # `construction:generator:method` <chr>,
#> # `construction:generator:output:electricity` <chr>,
#> # `construction:generator:source` <chr>, `construction:generator:type` <chr>,
#> # `construction:power.x` <chr>, designation <chr>, `disused:power.x` <chr>,
#> # fixme.x <chr>, `generator:height` <chr>, `generator:manufacturer` <chr>, …
glimpse(wind_joined_sf)
#> Rows: 2,578
#> Columns: 89
#> $ osm_id <chr> "370577265", "370577267", …
#> $ relation <chr> "15261309", "15261309", "1…
#> $ type.x <chr> "node", "node", "node", "n…
#> $ role <chr> "generator", "generator", …
#> $ name.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ base_height <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ check_date <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ colour <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ construction <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `construction:generator:method` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `construction:generator:output:electricity` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `construction:generator:source` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `construction:generator:type` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `construction:power.x` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ designation <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `disused:power.x` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ fixme.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `generator:height` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `generator:manufacturer` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `generator:method` <chr> "wind_turbine", "wind_turb…
#> $ `generator:output:electricity` <chr> "0.85 MW", "0.85 MW", "1.3…
#> $ `generator:source` <chr> "wind", "wind", "wind", "w…
#> $ `generator:type` <chr> "horizontal_axis", "horizo…
#> $ has_aeronautical_lights <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ height <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `height:hub` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `height:range` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ man_made <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ manufacturer.x <chr> "Vestas", "Vestas", "Norde…
#> $ `manufacturer:type` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `manufacturer:wikidata` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ model <chr> "V52", "V52", "N60", "N60"…
#> $ `monitoring:weather` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ note.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ old_operator.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ old_website.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ operator.x <chr> "Tornado Electrical Ltd", …
#> $ `operator:website.x` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `operator:wikidata.x` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `operator:wikipedia.x` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ owner.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ power.x <chr> "generator", "generator", …
#> $ ref <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `repd:id.x` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `rotor:diameter` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `rotor:swept_area` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ source.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `source:position` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ start_date.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `tower:construction` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `tower:type` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ year_of_construction.x <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ geometry <POINT [°]> POINT (-7.344967 52.…
#> $ name.y <chr> "Beallough Wind Farm", "Be…
#> $ operator.y <chr> "Tornado Electrical Ltd", …
#> $ `plant:output:electricity` <chr> "1.7 MW", "1.7 MW", "7.7 M…
#> $ `plant:source` <chr> "wind", "wind", "wind", "w…
#> $ power.y <chr> "plant", "plant", "plant",…
#> $ `repd:id.y` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ site <chr> "wind_farm", "wind_farm", …
#> $ type.y <chr> "site", "site", "site", "s…
#> $ `plant:method` <chr> "wind_turbine", "wind_turb…
#> $ wikidata <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ wikipedia <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ alt_name <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ fixme.y <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ owner.y <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ start_date.y <chr> "2008", "2008", NA, NA, NA…
#> $ `operator:wikidata.y` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `operator:wikipedia.y` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ website <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ turbines <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ note.y <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `alt_name:en` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `name:en` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `name:ga` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ old_operator.y <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ old_website.y <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ year_of_construction.y <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ source.y <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `disused:power.y` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ end_date <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `construction:power.y` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `operator:website.y` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ phone <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ `contact:facebook` <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ old_name <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ description <chr> NA, NA, NA, NA, NA, NA, NA…
#> $ manufacturer.y <chr> NA, NA, NA, NA, NA, NA, NA…
Created on 2024-07-17 with reprex v2.1.0