Utilități
Apoi facem două funcții care ne vor permite să interogărilem API -ul Wikidata pentru a -i asocia identificatorii OSM la o entitate Wikidata. Există trei proprietăți necesare (pentru noduri, moduri și relații). O entitate poate avea zero, una, două sau trei dintre aceste proprietăți, iar pentru fiecare proprietate poate avea unul sau mai multe ID -uri.
#' Get the OpenStreetMap IDs of a wikidata item #' #' @param item (char) wikidata ID (e.g. "Q19368619") #' #' @returns (vec) #' OSM ID (possibly several), prefixed with #' "n" for "node", #' "w" for "way" and #' "r" for relation #' NULL if no OSM ID or #' NA if not available, #' @example get_wd_osm_id("Q19368619") get_wd_osm_id <- purrr::possibly(function(item) { # avoid spending time querying if no wikidata item if (is.na(item) | item == "" | !stringr::str_detect(item, "Q(0-9)+")) { return(NA_character_) } else { i <- WikidataR::get_item(item) # P402 relation relation <- purrr::pluck(i, 1, "claims", "P402", "mainsnak", "datavalue", "value") relation <- if (!is.null(relation)) { paste0("r", relation) } else { NULL } # P10689 way way <- purrr::pluck(i, 1, "claims", "P10689", "mainsnak", "datavalue", "value") way <- if (!is.null(way)) { paste0("w", way) } else { NULL } # P11693 node node <- purrr::pluck(i, 1, "claims", "P11693", "mainsnak", "datavalue", "value") node <- if (!is.null(node)) { paste0("n", node) } else { NULL } return(purrr::compact(c(relation, way, node))) } }, otherwise = NA_character_) #' Add a column with the OpenStreetMap IDs from wikidata #' #' For all features of an osmdata sf object having a wikidata ID, get the #' associated OSM IDs recorded in wikidata #' #' @param osmdata_features (sf) osmdata sub-object (osm_points, osm_lines,...) #' with a `wikidata` column #' #' @returns (sf) input object with a new column `wd_osm_id` as a list-column of #' character IDs (or NULL) #' @examples add_osmid_from_wikidata(my_osmdata_sf$osm_points) add_osm_id_from_wikidata <- function(osmdata_features) { geom_type <- sf::st_geometry_type(osmdata_features, by_geometry = FALSE) osmdata_features |> tibble::as_tibble(.name_repair = janitor::make_clean_names) |> dplyr::mutate( wd_osm_id = purrr::map( wikidata, slowly(get_wd_osm_id), .progress = glue::glue("Getting OSM ID for {geom_type}..."))) } #' Add a prefix to the OSM ID according to the element geometry type #' #' It will allow us to compare `osm_id` and `wd_osm_id` #' #' @param x (sf) OSM data sub-object #' #' @returns x with the `osm_id` field prefixed with "n" for "node", #' "w" for "way" and "r" for relation #' @examples prefix_osm_id(osm_wd$osm_points) prefix_osm_id <- function(x, p = c("n", "w", "r")) { geom_type <- sf::st_geometry_type(osmdata_features, by_geometry = FALSE) p <- case_when(geom_type == "POINT" ~ "n", geom_type %in% c("LINESTRING", "POLYGON") ~ "w", geom_type %in% c("MULTILINESTRING", "MULTIPOLYGON") ~ "r", .default = "") x |> mutate(osm_id = glue("{p}{osm_id}")) }
Cu aceste funcții, putem să ne uităm la datele noastre OSM, să îi păstrăm pe cei care au un atribut Wikidata, iar pentru aceste entități obține ID -urile OSM, permițându -ne să verificăm dacă sunt similare sau, pentru cei care lipsesc, adăugând ID -ul manual în Wikidata. Deoarece datele OSM sunt expediate în diferite obiecte, în funcție de tipul de geometrie, trebuie să le facem pentru fiecare dintre ele.
osm_wd_augmented <- list( prefix_osm_id(osm_wd$osm_points, "n"), prefix_osm_id(osm_wd$osm_lines, "w"), prefix_osm_id(osm_wd$osm_polygons, "w"), prefix_osm_id(osm_wd$osm_multilines, "r"), prefix_osm_id(osm_wd$osm_multipolygons, "r")) |> map((x) { x |> filter(!is.na(wikidata) & wikidata != "") |> add_osm_id_from_wikidata() |> select(osm_id, name, wikidata, wd_osm_id) |> unnest(wd_osm_id, keep_empty = TRUE)}) |> list_rbind() |> distinct()
Obținem o nouă variabilă wd_osm_id
a cărui semnificație este „Este unul dintre identificatorii OSM din entitatea Wikidata, care este indicată în elementul OSM„
Cazuri de utilizare
De exemplu, dacă dorim să vedem elementele OSM având o entitate Wikidata care nu se leagă înapoi:
osm_wd_augmented |> filter(is.na(wd_osm_id)) |> arrange(name)
# A tibble: 29 × 4 osm_id name wikidata wd_osm_id1 w194448267 Cenischia Q3539637 2 n41645050 Champagny-en-Vanoise Q34791526 3 w108980863 Chapelle Notre-Dame de la Visitation Q13518652 4 w131213010 Chapelle Saint-Antoine Q22975798 5 w131213054 Chapelle Saint-Sébastien Q22968509 6 n4573291011 Cinéma Chantelouve Q61858809 7 r2149907 Communauté de Communes Terra Modana Q17355571 8 w37792978 Dora di Bardonecchia Q3714186 9 w131215535 Espace Baroque Q22968504 10 r377905 GR 55 La Vanoise Q124149580 # ℹ 19 more rows
Unele sunt poate legitime (?), Dar unii altele ar putea avea nevoie de editare …
Un alt exemplu, verificați incoerența dintre osm_id
şi wd_osm_id
:
osm_wd_augmented |> filter(osm_id != wd_osm_id) |> arrange(name)
# A tibble: 25 × 4 osm_id name wikidata wd_osm_id1 n26691864 Albertville Q159469 r111528 2 n26691864 Albertville Q159469 r17160712 3 n41644953 Aussois Q567783 r89823 4 r2149905 Communauté de Communes de Haute Maurienne-Va… Q2987514 r6876759 5 n11646993705 Dent Parrachée Q1189850 n6705389… 6 w1257820968 Ferrovia del Moncenisio Q950823 r15987785 7 w1257820969 Ferrovia del Moncenisio Q950823 r15987785 8 w1257820970 Ferrovia del Moncenisio Q950823 r15987785 9 w1257820971 Ferrovia del Moncenisio Q950823 r15987785 10 w993297614 Glacier de Méan-Martin Q348352… w42239115 # ℹ 15 more rows
Acesta ar putea indica faptul că elementele OSM au fost puternic editate sau șterse/recreate fără a actualiza entitatea Wikidata corespunzătoare.
Corecțiile necesită manual înainte și înapoi între site -urile R, OSM și Wikidata, dar aceste utilități fac destul de ușor îmbunătățirea calității datelor.