ropenstreetmaposmdata

Get relation data from osmdata


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.


Solution

  • 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 MULTIPOINTs 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