Reutilitzant dades públiques: escoles a OpenStreetMap

OpenStreetMap
OpenData
Dades Obertes
R
Author

Marc Bosch Matas

Published

December 11, 2022

Avui comparteixo una de les coses que faig quan la vida em deixa: editar OpenStreetMap. Si coneixeu aquest projecte, consisteix en una gran base de dades geolocalitzada que editem persones de tot arreu utilitzant fonts de coneixement lliures. Bàsicament ho faig per activisme: OpenStreetMap pot ser una alternativa a Google Maps i altres projectes que donen beneficis a les grans tecnològiques. No corre el risc que ho compri l’Elon Musk de torn ni de patir censures arbitràries. Més important, qualsevol persona el pot editar, i el criteri de què és important el marquem les persones que hi participem. D’altra banda, els editors i editores catalans som una colla de gent bastant simpàtica i ens toca més l’aire que si editéssim la Viquipèdia. D’altra banda, també fem molta cosa amb ordinadors per tenir el màxim de dades possibles amb el mínim esforç.

Fa no massa, vam obtenir permís per fer servir el Directori de Centres Educatius del Departament d’Educació. En aquest post, explicaré com agafem les dades i les preparem per a pujar-les a OpenStreetMap. Per exemple, amb el cas de Palafrugell. Així, el que farem serà el següent.

  1. Baixar totes les dades de centres educatius de Palafrugell que tenen un número de referència del departament d’Educació utilitzant l’API Overpass.

  2. Baixar les dades del Directori de Centres correspondent als centres que volem completar.

  3. Tractar les dades i afegir les que falten a la taula d’OpenStreetMap.

  4. Comprovar que tot estigui bé i pujar les dades fent servir l’editor JOSM.

Codi R
library(sf) # tractar shapefiles
library(osmdata) # baixar data d'OSM
library(tmap) # fer mapes
library(tmaptools) # baixar mapa base
library(tidyverse) # tractar taules
library(httr) # baixar dades d'internet
library(jsonlite) # convertir JSONs a taules
library(rvest) # llegir webs

Comencem per baixar les dades d’OpenStreetMap i representar-les en un mapa.

Codi R
escoles <- opq("Palafrugell") |> 
  add_osm_features("[\"amenity\"=\"school\"][\"ref\"]") |> # this is a lot more cumbersome but allows to filter for missing tags
  osmdata_sf()

escoles_punts <- escoles$osm_points
escoles_pol <- escoles$osm_polygons
escoles_mpol <- escoles$osm_multipolygons

escoles_osm <- escoles_pol |> 
  st_drop_geometry() |> 
  bind_rows(st_drop_geometry(escoles_mpol))
knitr::kable(escoles_osm, style = "pipe")
osm_id name addr.city addr.housenumber addr.postcode addr.street amenity leisure name.ca name.etymology.wikidata operator ref religion sport surface website wheelchair wikidata wikipedia type
167703123 167703123 Escola Josep Barceló i Matas NA NA NA NA school NA NA Q19300295 NA 17002491 NA NA NA NA NA Q111283965 NA NA
235507099 235507099 Vedruna Palafrugell NA NA NA NA school NA Vedruna Palafrugell NA NA 17002511 NA NA NA NA NA Q111594946 NA NA
367243676 367243676 Escola Carrilet NA NA NA NA school NA Escola Carrilet NA Ajuntament de Palafrugell 17006782 NA NA NA NA yes Q111283756 NA NA
367352591 367352591 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
367693485 367693485 NA NA NA NA NA NA pitch NA NA NA NA NA soccer concrete NA NA NA NA NA
367714709 367714709 Institut Baix Empordà NA NA NA NA school NA NA NA Generalitat de Catalunya 17002557 NA NA NA NA yes Q11926287 NA NA
367729357 367729357 Escola Sant Jordi NA NA NA NA school NA Escola Sant Jordi NA NA 17002521 NA NA NA NA NA Q111594947 NA NA
368163468 368163468 Escola Torres Jonama NA NA NA NA school NA Escola Torres Jonama NA Generalitat de Catalunya 17002481 NA NA NA NA yes Q11910302 ca:CEIP Torres Jonama NA
816953410 816953410 Escola l’Olivar Vell Esclanyà NA NA NA school NA Escola l’Olivar Vell NA NA 17004876 NA NA NA NA NA Q111283738 NA NA
1015010006 1015010006 Escola Pi Verd Palafrugell 12 17200 Carrer de Viçens Roure i Armadà school NA Escola Pi Verd NA NA 17008523 christian NA NA https://agora.xtec.cat/escpiverd/ NA Q111283815 NA NA
5465679 5465679 Institut Frederic Martí i Carreras NA NA NA NA school NA NA Q11923061 Generalitat de Catalunya 17002545 NA NA NA NA yes Q111253680 NA multipolygon
Codi R
bm <- read_osm(escoles_punts)

tm_shape(bm) + 
  tm_rgb() + 
  tm_shape(escoles_pol) + 
  tm_borders(col = modthemes::dubois_blue,
             lwd = 2) + 
  tm_shape(escoles_mpol) + 
  tm_borders(col = modthemes::dubois_blue,
             lwd = 2)

Veiem que ens surten alguns objectes sense codi de referència, però no ens hauria de preocupar massa. Són objectes com patis o pistes poliesportives que formen part de les relacions (és a dir, col·leccions d’objectes) de les escoles. Ara toca baixar-nos les dades del Departament d’Educació. Ho fem amb les llibreries httr i jsonlite que ens permeten crear una URL on hi hagi les dades de tots els centres que ens interessen, baixar-nos la informació i organitzar-la en forma de taula.

Codi R
# crear vector de codis únics
refs <- unique(c(escoles_pol$ref, escoles_mpol$ref))
refs <- refs[!is.na(refs)]
# crear una variable character amb tots els codis separats per codis
reftext <- sapply(refs, \(x) paste0("'",str_pad(x, width=8, pad = 0),"'")) |> 
  paste(collapse = ", ")

# generar una url de l'API de dades obertes de la Generalitat que ens
baseurl <- "https://analisi.transparenciacatalunya.cat/resource/kvmv-ahh4.json?$query="


query = paste0("SELECT * WHERE codi_centre IN (", reftext, ") AND curs='2022/2023'")
query <- str_replace_all(query," ","%20")

# descarregar les dades i passar-les a format taula
escoles_gene <- GET(paste0(baseurl,query)) |> 
  content(as = "text") |> 
  fromJSON()

knitr::kable(escoles_gene, style = "pipe")
curs any codi_centre denominaci_completa codi_naturalesa nom_naturalesa codi_titularitat nom_titularitat adre_a codi_postal tel_fon fax codi_delegaci nom_delegaci codi_comarca nom_comarca codi_municipi codi_municipi_6 nom_municipi codi_districte_municipal codi_localitat nom_localitat zona_educativa coordenades_utm_x coordenades_utm_y coordenades_geo_x coordenades_geo_y e_mail_centre url einf2c epri einf1c eso batx cfpm aa03 cfps pfi
2022/2023 2022 17002481 Escola Torres Jonama 1 Públic 01 Departament d’Ensenyament c. Escoles, 10 17200 972610882 972610652 0117 Girona 10 Baix Empordà 17117 171175 Palafrugell 00 06 Palafrugell Baix Empordà 513844 4640216 3.166934 41.913774 b7002481@xtec.cat http://www.xtec.cat/ceiptorresjonama-palafrugell/ EINF2C EPRI NA NA NA NA NA NA NA
2022/2023 2022 17002491 Escola Josep Barceló i Matas 1 Públic 01 Departament d’Ensenyament c. Pals, 75 17200 972300924 972300924 0117 Girona 10 Baix Empordà 17117 171175 Palafrugell 00 06 Palafrugell Baix Empordà 513374 4640994 3.16129 41.920784 b7002491@xtec.cat http://agora.xtec.cat/ceipbarceloimatas/ EINF2C EPRI NA NA NA NA NA NA NA
2022/2023 2022 17002511 Vedruna Palafrugell 2 Privat 22 Fundacions c. Sant Sebastià, 85 17200 972300739 972300303 0117 Girona 10 Baix Empordà 17117 171175 Palafrugell 00 06 Palafrugell Baix Empordà 514063 4640552 3.169588 41.916794 b7002511@xtec.cat http://WWW.vedrunapalafrugell.org EINF2C EPRI EINF1C NA NA NA NA NA NA
2022/2023 2022 17002521 Sant Jordi 2 Privat 26 Societats Mercantils c. Tarongeta, 65 17200 972302898 972304238 0117 Girona 10 Baix Empordà 17117 171175 Palafrugell 00 06 Palafrugell Baix Empordà 513935 4640611 3.168046 41.91733 b7002521@xtec.cat http://www.escolasantjordi.cat EINF2C EPRI NA ESO NA NA NA NA NA
2022/2023 2022 17002545 Institut Frederic Martí i Carreras 1 Públic 01 Departament d’Ensenyament c. Frederic Martí Carreras, 13 17200 972301079 972611336 0117 Girona 10 Baix Empordà 17117 171175 Palafrugell 00 06 Palafrugell Baix Empordà 513680 4639998 3.164958 41.911812 b7002545@xtec.cat http://agora.xtec.cat/iesfredericmarti/ NA NA NA ESO BATX NA NA NA NA
2022/2023 2022 17002557 Institut Baix Empordà 1 Públic 01 Departament d’Ensenyament av. de les Corts Catalanes, s/n 17200 972300323 972611874 0117 Girona 10 Baix Empordà 17117 171175 Palafrugell 00 06 Palafrugell Baix Empordà 513786 4639842 3.166224 41.910404 b7002557@xtec.cat http://www.insbaixemporda.cat NA NA NA ESO BATX CFPM AA03 CFPS PFI
2022/2023 2022 17004876 Escola l’Olivar Vell 1 Públic 01 Departament d’Ensenyament Veïnat Colomina, s/n 17255 972611990 972611990 0117 Girona 10 Baix Empordà 17013 170139 Begur 00 02 Esclanyà Baix Empordà 514364 4642168 3.173253 41.931346 b7004876@xtec.cat https://agora.xtec.cat/ceipolivarvell/ EINF2C EPRI NA NA NA NA NA NA NA
2022/2023 2022 17006782 Escola Carrilet 1 Públic 01 Departament d’Ensenyament pl. Narcisa Oliver i Deulofeu, s/n 17200 972306765 972306770 0117 Girona 10 Baix Empordà 17117 171175 Palafrugell 00 06 Palafrugell Baix Empordà 512884 4639998 3.155351 41.911822 b7006782@xtec.cat http://agora.xtec.cat/escolacarrilet/ EINF2C EPRI NA NA NA NA NA NA NA
2022/2023 2022 17008523 Escola Pi Verd 1 Públic 01 Departament d’Ensenyament c. Vicenç Roure i Armadà, 12 17200 972610457 NA 0117 Girona 10 Baix Empordà 17117 171175 Palafrugell 00 06 Palafrugell Baix Empordà 514349 4640814 3.173042 41.919148 b7008523@xtec.cat http://agora.xtec.cat/escpiverd/ EINF2C EPRI NA NA NA NA NA NA NA

Tenim un munt de variables, moltes de les quals ens interessen. Algunes les podem incorporar tal i com van i d’altres voldran una mica de feina. Comencem per l’adreça. Veiem que hi ha quatre camps vinculats amb l’adreça: addr.city, addr.housenumber (número d’edifici), addr.postcode (codi postal) i addr.street (carrer). D’altra banda, podem agafar directament la web, el correu electrònic i com el nom del titular. La titularitat també es pot agafar directament, però cal traduir-ho a l’anglès. També cal afegir els prefixos internacionals als camps de telèfon i fax.

Codi R
escoles_gene_osm <- escoles_gene |> 
  select(-c(curs, codi_titularitat, codi_naturalesa, 
            codi_delegaci, nom_delegaci, codi_comarca,
            codi_municipi, codi_municipi_6, 
            codi_localitat, codi_districte_municipal, 
            nom_comarca, zona_educativa,
            coordenades_utm_x, coordenades_utm_y,
            coordenades_geo_x, coordenades_geo_y)) |> # eliminar columnes que no calen
  rename("operator" = "nom_titularitat",
         "name" = "denominaci_completa",
         "ref" = "codi_centre",
         "contact:phone" = "tel_fon",
         "contact:fax" = "fax",
         "contact:email" = "e_mail_centre",
         "website" = "url",
         "addr:city" = "nom_municipi",
         "addr:place" = "nom_localitat",
         "addr:postcode" = "codi_postal",
         "source:date" = "any") |> # canviar noms de columnes que podem adaptar "tal qual"
  mutate("contact:fax" = paste0("+34",`contact:fax`),
         "contact:phone" = paste0("+34", `contact:phone`),
         "addr:street" = str_extract(adre_a, "^[^\\,]+"),
         "addr:housenumber" = str_extract(adre_a, "[^\\, ]+$"),
         "operator:type" = ifelse(nom_naturalesa == "Públic", "public", "private"))
knitr::kable(escoles_gene_osm, style = "pipe")
source:date ref name nom_naturalesa operator adre_a addr:postcode contact:phone contact:fax addr:city addr:place contact:email website einf2c epri einf1c eso batx cfpm aa03 cfps pfi addr:street addr:housenumber operator:type
2022 17002481 Escola Torres Jonama Públic Departament d’Ensenyament c. Escoles, 10 17200 +34972610882 +34972610652 Palafrugell Palafrugell b7002481@xtec.cat http://www.xtec.cat/ceiptorresjonama-palafrugell/ EINF2C EPRI NA NA NA NA NA NA NA c. Escoles 10 public
2022 17002491 Escola Josep Barceló i Matas Públic Departament d’Ensenyament c. Pals, 75 17200 +34972300924 +34972300924 Palafrugell Palafrugell b7002491@xtec.cat http://agora.xtec.cat/ceipbarceloimatas/ EINF2C EPRI NA NA NA NA NA NA NA c. Pals 75 public
2022 17002511 Vedruna Palafrugell Privat Fundacions c. Sant Sebastià, 85 17200 +34972300739 +34972300303 Palafrugell Palafrugell b7002511@xtec.cat http://WWW.vedrunapalafrugell.org EINF2C EPRI EINF1C NA NA NA NA NA NA c. Sant Sebastià 85 private
2022 17002521 Sant Jordi Privat Societats Mercantils c. Tarongeta, 65 17200 +34972302898 +34972304238 Palafrugell Palafrugell b7002521@xtec.cat http://www.escolasantjordi.cat EINF2C EPRI NA ESO NA NA NA NA NA c. Tarongeta 65 private
2022 17002545 Institut Frederic Martí i Carreras Públic Departament d’Ensenyament c. Frederic Martí Carreras, 13 17200 +34972301079 +34972611336 Palafrugell Palafrugell b7002545@xtec.cat http://agora.xtec.cat/iesfredericmarti/ NA NA NA ESO BATX NA NA NA NA c. Frederic Martí Carreras 13 public
2022 17002557 Institut Baix Empordà Públic Departament d’Ensenyament av. de les Corts Catalanes, s/n 17200 +34972300323 +34972611874 Palafrugell Palafrugell b7002557@xtec.cat http://www.insbaixemporda.cat NA NA NA ESO BATX CFPM AA03 CFPS PFI av. de les Corts Catalanes s/n public
2022 17004876 Escola l’Olivar Vell Públic Departament d’Ensenyament Veïnat Colomina, s/n 17255 +34972611990 +34972611990 Begur Esclanyà b7004876@xtec.cat https://agora.xtec.cat/ceipolivarvell/ EINF2C EPRI NA NA NA NA NA NA NA Veïnat Colomina s/n public
2022 17006782 Escola Carrilet Públic Departament d’Ensenyament pl. Narcisa Oliver i Deulofeu, s/n 17200 +34972306765 +34972306770 Palafrugell Palafrugell b7006782@xtec.cat http://agora.xtec.cat/escolacarrilet/ EINF2C EPRI NA NA NA NA NA NA NA pl. Narcisa Oliver i Deulofeu s/n public
2022 17008523 Escola Pi Verd Públic Departament d’Ensenyament c. Vicenç Roure i Armadà, 12 17200 +34972610457 +34NA Palafrugell Palafrugell b7008523@xtec.cat http://agora.xtec.cat/escpiverd/ EINF2C EPRI NA NA NA NA NA NA NA c. Vicenç Roure i Armadà 12 public

Veureu per això, que he deixat unes quantes columnes sense tractar, que tenen a veure amb quins cicles imparteixen. A partir d’això, cal generar tres variables més. isced:level, que estandarditza els nivells d’educació a nivell mundial (podeu veure’n totes les equivalències aquí), min_age (edat mínima), max_age (edat màxima), school el tipus d’escola i amenity on distingim entre escoles bressol, escoles de música elementals, d’idiomes o escoles de qualsevol altre tipus. Primer de tot, copiem la taula d’equivalències de la wiki d’OpenStreetMap.

Codi R
eqs <- "https://wiki.openstreetmap.org/wiki/Import_schools_in_Catalunya" |> 
  read_html() |> 
  html_nodes(xpath = '/html/body/div[3]/div[3]/div[5]/div[1]/table[2]') |> 
  html_table()
eqs <- eqs[[1]] |> 
  mutate(Cycle = str_split(Cycle, ", ")) |> 
  unnest(cols = Cycle) |> 
  mutate(Cycle = str_to_lower(Cycle))
knitr::kable(eqs, style = "pipe")
Cycle ISCED level min_age max_age
einf1c 0 0 3
einf2c 1 3 6
epri 1 6 12
eso 2 12 16
batx 3 16 18
aa01 2 NA NA
cfpm 3 16 NA
cfam 3 16 NA
tegm 3 16 NA
pa01 3 16 NA
ppas 3 16 NA
aa03 3 16 NA
cfps 5 18 NA
cfas 5 18 NA
esdi 5 18 NA
dans 5 18 NA
muss 5 18 NA
tegs 5 18 NA
pa02 5 18 NA
adr 5 18 NA
crbc 5 18 NA
pfi 2 16 21
dane 1; 2 NA NA
muse 1; 2 NA NA
danp 2; 3 12 18
musp 2; 3 12 18
estr NA NA
idi 16 NA
adults 1; 2; 3 18 NA
ee 1; 2 3 NA

Ara ja podem generar les columnes que falten.

Codi R
escoles_gene_isced <- escoles_gene |> 
  select("codi_centre", "epri", "einf1c", "einf2c", "eso", "batx", "cfpm", "aa03", "cfps", "pfi") |> 
  pivot_longer(-codi_centre,
               names_to = "level_name",
               values_to = "junk") |> 
  filter(!is.na(junk)) |> 
  select(-junk) |> 
  left_join(eqs, by = c("level_name" = "Cycle")) |> 
  mutate("school" = case_when(level_name %in% c("einf1c", "einf2c") ~ NA_character_,
                              level_name == "epri" ~ "primary",
                              level_name %in% c("eso", "batx") ~ "secondary",
                              level_name %in% c("aa01", "cfpm", "ppas", 
                                                "aa03", "cfps", "pfi", "pa01",
                                                "cfam", "pa02", "cfas",
                                                "esdi", "adr", "crbc",
                                                "dans", "musp", "muss",
                                                "tegm", "tegs") ~ "professional",
                              level_name == "ee" ~ "special_education_needs",
                              TRUE ~ NA_character_),
         "amenity" = case_when(level_name %in% c("einf1c", "einf2c") ~ "kindergarten",
                               level_name == "muse" ~ "music_school",
                               level_name == "dane" ~ NA_character_,
                               level_name == "idi" ~ "language_school",
                               TRUE ~ "school")) |> 
  arrange(`ISCED level`) |> 
  group_by(codi_centre) |> 
  summarise("isced:level" = paste(unique(`ISCED level`), collapse = "; "),
            "min_age" = min(min_age),
            "max_age" = ifelse(length(c(max_age)[is.na(c(max_age))]) > 0, NA_integer_,max(max_age)),
            "amenity" = paste(unique(`amenity`), collapse = "; "),
            "school" = paste(unique(school)[!is.na(c(unique(school)))], collapse = "; "))
knitr::kable(escoles_gene_isced, style = "pipe")
codi_centre isced:level min_age max_age amenity school
17002481 1 3 12 school; kindergarten primary
17002491 1 3 12 school; kindergarten primary
17002511 0; 1 0 12 kindergarten; school primary
17002521 1; 2 3 16 school; kindergarten primary; secondary
17002545 2; 3 12 18 school secondary
17002557 2; 3; 5 12 NA school secondary; professional
17004876 1 3 12 school; kindergarten primary
17006782 1 3 12 school; kindergarten primary
17008523 1 3 12 school; kindergarten primary

Ara només queda generar una taula única i ja tenim totes les dades preparades per a importar-les a OpenStreetMap amb JOSM o qualsevol altra eina.

Codi R
escoles_gene_osm <- escoles_gene_osm |> 
  select(-c("epri", "einf1c", "einf2c", "eso", "batx", "cfpm", "aa03", "cfps", "pfi", "nom_naturalesa", "adre_a")) |> 
  left_join(escoles_gene_isced, by = c("ref" = "codi_centre"))
knitr::kable(escoles_gene_osm, style = "pipe")
source:date ref name operator addr:postcode contact:phone contact:fax addr:city addr:place contact:email website addr:street addr:housenumber operator:type isced:level min_age max_age amenity school
2022 17002481 Escola Torres Jonama Departament d’Ensenyament 17200 +34972610882 +34972610652 Palafrugell Palafrugell b7002481@xtec.cat http://www.xtec.cat/ceiptorresjonama-palafrugell/ c. Escoles 10 public 1 3 12 school; kindergarten primary
2022 17002491 Escola Josep Barceló i Matas Departament d’Ensenyament 17200 +34972300924 +34972300924 Palafrugell Palafrugell b7002491@xtec.cat http://agora.xtec.cat/ceipbarceloimatas/ c. Pals 75 public 1 3 12 school; kindergarten primary
2022 17002511 Vedruna Palafrugell Fundacions 17200 +34972300739 +34972300303 Palafrugell Palafrugell b7002511@xtec.cat http://WWW.vedrunapalafrugell.org c. Sant Sebastià 85 private 0; 1 0 12 kindergarten; school primary
2022 17002521 Sant Jordi Societats Mercantils 17200 +34972302898 +34972304238 Palafrugell Palafrugell b7002521@xtec.cat http://www.escolasantjordi.cat c. Tarongeta 65 private 1; 2 3 16 school; kindergarten primary; secondary
2022 17002545 Institut Frederic Martí i Carreras Departament d’Ensenyament 17200 +34972301079 +34972611336 Palafrugell Palafrugell b7002545@xtec.cat http://agora.xtec.cat/iesfredericmarti/ c. Frederic Martí Carreras 13 public 2; 3 12 18 school secondary
2022 17002557 Institut Baix Empordà Departament d’Ensenyament 17200 +34972300323 +34972611874 Palafrugell Palafrugell b7002557@xtec.cat http://www.insbaixemporda.cat av. de les Corts Catalanes s/n public 2; 3; 5 12 NA school secondary; professional
2022 17004876 Escola l’Olivar Vell Departament d’Ensenyament 17255 +34972611990 +34972611990 Begur Esclanyà b7004876@xtec.cat https://agora.xtec.cat/ceipolivarvell/ Veïnat Colomina s/n public 1 3 12 school; kindergarten primary
2022 17006782 Escola Carrilet Departament d’Ensenyament 17200 +34972306765 +34972306770 Palafrugell Palafrugell b7006782@xtec.cat http://agora.xtec.cat/escolacarrilet/ pl. Narcisa Oliver i Deulofeu s/n public 1 3 12 school; kindergarten primary
2022 17008523 Escola Pi Verd Departament d’Ensenyament 17200 +34972610457 +34NA Palafrugell Palafrugell b7008523@xtec.cat http://agora.xtec.cat/escpiverd/ c. Vicenç Roure i Armadà 12 public 1 3 12 school; kindergarten primary

Trobareu el codi per això i per altres coses d’OpenStreetMap al meu GitHub