Data

List of schools and libraries from OpenStreetMap. Includes all schools (no easy way to filter for just primary schools).

# load useful libraries
if (!require("osmdata")) install.packages("osmdata")
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("sf")) install.packages("sf")
if (!require("leaflet")) install.packages("leaflet")
if (!require("revgeo")) install.packages("revgeo")
if (!require("DT")) install.packages("DT")

# Query openstreemap (overpass api) ----------------------------------------------------

# set area value for map e.g. "Glasgow UK"
area <- "Herefordshire UK" 

# query libraries
library_query <- getbb(area) %>%
  opq() %>%
  add_osm_feature("amenity", "library")
# query schools
school_query <- getbb(area) %>%
  opq() %>%
  add_osm_feature("amenity", "school")

# merge schools and libraries in to single object
libraries <- c(osmdata_sf(library_query), osmdata_sf(school_query)) 
# return unqiue objects (in case featues mapped at points and polygons)
libraries <- unique_osmdata(libraries)

# get centroids of polygons because want to display as points
lib_centroids <- st_sf(st_centroid(libraries$osm_polygon))

# get points so can merge with centroid
lib_point <- libraries$osm_points
# merge centroid points and points
all_points <- bind_rows(data.frame(lib_point), data.frame(lib_centroids))
# add geometry to this new merged dataset
all_points$geometry <- c(lib_point$geometry, lib_centroids$geometry)
# convert to 'sf' object
all_points <- st_as_sf(all_points)
# add object back to osmdata object
libraries$osm_points <- all_points

# filter only schools and libraries (appears to 'empty' things)
libraries$osm_points <- filter(libraries$osm_points, amenity %in% c("school", "library"))

Map

Click points to see name and address (if available)

# Map -----------------------------------------------------------------------------------

# Colour for icons
libs <- mutate(libs, colour = ifelse(amenity == "school","blue","green"))
# Make icons
icons <- awesomeIcons(
  icon = "ios-close",
  iconColor = "black",
  library = "ion",
  markerColor = libs$colour
)

# make web 'slippy' map 
m <- leaflet(libs) %>%
  addTiles() %>%
  addAwesomeMarkers(data = libs, popup = paste(libs$name, libs$street, libs$city, sep = "<br/>"), icon = icons)
m

Nearest library

Distance to library (as the crow flies).

all_lib <- filter(libs, amenity == "library")
all_schools <- filter(libs, amenity == "school")

all_schools$nearest <- st_nearest_feature(all_schools, all_lib)
all_lib$nearest <- as.integer(row.names(all_lib))

df <- as_tibble(select(
all_schools, name,
street,
city,
nearest
))

df_lib <- as_tibble(
  select(
  all_lib, name,
  street,
  city,
  nearest))

df <- right_join(df, df_lib, by = c("nearest" = "nearest"))

df$distance <- st_distance(df$geometry.x, df$geometry.y, by_element = TRUE) / 1000
units(df$distance) = NULL
df$distance <- round(df$distance, 1)

table_df <- as_tibble(transmute(df,
                             "School" = name.x,
                             "School Address" = paste(df$street.x, df$city.x, sep = ", "),
                             "Nearest Library" = name.y,
                             "Library Address" = paste(df$street.y, df$city.y, sep = ", "),
                             "Distance in km" = distance))

datatable(table_df)

NA
LS0tCnRpdGxlOiAiTGlicmFyaWVzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKIyBEYXRhCkxpc3Qgb2Ygc2Nob29scyBhbmQgbGlicmFyaWVzIGZyb20gT3BlblN0cmVldE1hcC4gSW5jbHVkZXMgYWxsIHNjaG9vbHMgKG5vIGVhc3kgd2F5IHRvIGZpbHRlciBmb3IganVzdCBwcmltYXJ5IHNjaG9vbHMpLgpgYGB7ciBxdWVyeSwgbWVzc2FnZT1GLHdhcm5pbmc9Rn0KIyBsb2FkIHVzZWZ1bCBsaWJyYXJpZXMKaWYgKCFyZXF1aXJlKCJvc21kYXRhIikpIGluc3RhbGwucGFja2FnZXMoIm9zbWRhdGEiKQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQppZiAoIXJlcXVpcmUoInNmIikpIGluc3RhbGwucGFja2FnZXMoInNmIikKaWYgKCFyZXF1aXJlKCJsZWFmbGV0IikpIGluc3RhbGwucGFja2FnZXMoImxlYWZsZXQiKQppZiAoIXJlcXVpcmUoInJldmdlbyIpKSBpbnN0YWxsLnBhY2thZ2VzKCJyZXZnZW8iKQppZiAoIXJlcXVpcmUoIkRUIikpIGluc3RhbGwucGFja2FnZXMoIkRUIikKCiMgUXVlcnkgb3BlbnN0cmVlbWFwIChvdmVycGFzcyBhcGkpIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBzZXQgYXJlYSB2YWx1ZSBmb3IgbWFwIGUuZy4gIkdsYXNnb3cgVUsiCmFyZWEgPC0gIkhlcmVmb3Jkc2hpcmUgVUsiIAoKIyBxdWVyeSBsaWJyYXJpZXMKbGlicmFyeV9xdWVyeSA8LSBnZXRiYihhcmVhKSAlPiUKICBvcHEoKSAlPiUKICBhZGRfb3NtX2ZlYXR1cmUoImFtZW5pdHkiLCAibGlicmFyeSIpCiMgcXVlcnkgc2Nob29scwpzY2hvb2xfcXVlcnkgPC0gZ2V0YmIoYXJlYSkgJT4lCiAgb3BxKCkgJT4lCiAgYWRkX29zbV9mZWF0dXJlKCJhbWVuaXR5IiwgInNjaG9vbCIpCgojIG1lcmdlIHNjaG9vbHMgYW5kIGxpYnJhcmllcyBpbiB0byBzaW5nbGUgb2JqZWN0CmxpYnJhcmllcyA8LSBjKG9zbWRhdGFfc2YobGlicmFyeV9xdWVyeSksIG9zbWRhdGFfc2Yoc2Nob29sX3F1ZXJ5KSkgCiMgcmV0dXJuIHVucWl1ZSBvYmplY3RzIChpbiBjYXNlIGZlYXR1ZXMgbWFwcGVkIGF0IHBvaW50cyBhbmQgcG9seWdvbnMpCmxpYnJhcmllcyA8LSB1bmlxdWVfb3NtZGF0YShsaWJyYXJpZXMpCgojIGdldCBjZW50cm9pZHMgb2YgcG9seWdvbnMgYmVjYXVzZSB3YW50IHRvIGRpc3BsYXkgYXMgcG9pbnRzCmxpYl9jZW50cm9pZHMgPC0gc3Rfc2Yoc3RfY2VudHJvaWQobGlicmFyaWVzJG9zbV9wb2x5Z29uKSkKCiMgZ2V0IHBvaW50cyBzbyBjYW4gbWVyZ2Ugd2l0aCBjZW50cm9pZApsaWJfcG9pbnQgPC0gbGlicmFyaWVzJG9zbV9wb2ludHMKIyBtZXJnZSBjZW50cm9pZCBwb2ludHMgYW5kIHBvaW50cwphbGxfcG9pbnRzIDwtIGJpbmRfcm93cyhkYXRhLmZyYW1lKGxpYl9wb2ludCksIGRhdGEuZnJhbWUobGliX2NlbnRyb2lkcykpCiMgYWRkIGdlb21ldHJ5IHRvIHRoaXMgbmV3IG1lcmdlZCBkYXRhc2V0CmFsbF9wb2ludHMkZ2VvbWV0cnkgPC0gYyhsaWJfcG9pbnQkZ2VvbWV0cnksIGxpYl9jZW50cm9pZHMkZ2VvbWV0cnkpCiMgY29udmVydCB0byAnc2YnIG9iamVjdAphbGxfcG9pbnRzIDwtIHN0X2FzX3NmKGFsbF9wb2ludHMpCiMgYWRkIG9iamVjdCBiYWNrIHRvIG9zbWRhdGEgb2JqZWN0CmxpYnJhcmllcyRvc21fcG9pbnRzIDwtIGFsbF9wb2ludHMKCiMgZmlsdGVyIG9ubHkgc2Nob29scyBhbmQgbGlicmFyaWVzIChhcHBlYXJzIHRvICdlbXB0eScgdGhpbmdzKQpsaWJyYXJpZXMkb3NtX3BvaW50cyA8LSBmaWx0ZXIobGlicmFyaWVzJG9zbV9wb2ludHMsIGFtZW5pdHkgJWluJSBjKCJzY2hvb2wiLCAibGlicmFyeSIpKQpgYGAKCgpgYGB7ciBnZW9jb2RpbmcsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KIyBHZW9jb2RpbmcgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIGNvbnZlcnQgdG8gZGF0YWZyYW1lIHdpdGggbGF0IC8gbG9uCnBvaW50c19sYXRfbG9uIDwtIHVubGlzdChzdF9nZW9tZXRyeShsaWJyYXJpZXMkb3NtX3BvaW50cykpICU+JQogIG1hdHJpeChuY29sID0gMiwgYnlyb3cgPSBUUlVFKSAlPiUKICBhc190aWJibGUoKSAlPiUKICBzZXROYW1lcyhjKCJsb25naXR1ZGUiLCAibGF0aXR1ZGUiKSkKCiMgcmV2ZXJzZSBnZW9jb2RlIHRvIGdldCBhZGRyZXNzIGluZm8gd2hlcmUgcG9zc2libGUKZ2VvY29kZSA8LSByZXZnZW8ocG9pbnRzX2xhdF9sb24kbG9uZ2l0dWRlLCBwb2ludHNfbGF0X2xvbiRsYXRpdHVkZSwgb3V0cHV0ID0gImZyYW1lIikKCiMgbWVyZ2UgZ2VvY29kZSB0YWJsZSBiYWNrIGludG8gb2JqZWN0OgpsaWJfcG9pbnQgPC0gbGlicmFyaWVzJG9zbV9wb2ludHMKdnYgPC0gY2JpbmQoZGF0YS5mcmFtZShsaWJfcG9pbnQpLCBkYXRhLmZyYW1lKGdlb2NvZGUpKQp2diA8LSBzdF9zZih2dikKbGlicmFyaWVzJG9zbV9wb2ludHMgPC0gdnYKbGlicyA8LSBzdF9zZihsaWJyYXJpZXMkb3NtX3BvaW50cykKCmBgYAoKIyMgTWFwCgpDbGljayBwb2ludHMgdG8gc2VlIG5hbWUgYW5kIGFkZHJlc3MgKGlmIGF2YWlsYWJsZSkKCmBgYHtyIG1hcCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9CiMgTWFwIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIENvbG91ciBmb3IgaWNvbnMKbGlicyA8LSBtdXRhdGUobGlicywgY29sb3VyID0gaWZlbHNlKGFtZW5pdHkgPT0gInNjaG9vbCIsImJsdWUiLCJncmVlbiIpKQojIE1ha2UgaWNvbnMKaWNvbnMgPC0gYXdlc29tZUljb25zKAogIGljb24gPSAiaW9zLWNsb3NlIiwKICBpY29uQ29sb3IgPSAiYmxhY2siLAogIGxpYnJhcnkgPSAiaW9uIiwKICBtYXJrZXJDb2xvciA9IGxpYnMkY29sb3VyCikKCiMgbWFrZSB3ZWIgJ3NsaXBweScgbWFwIAptIDwtIGxlYWZsZXQobGlicykgJT4lCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRBd2Vzb21lTWFya2VycyhkYXRhID0gbGlicywgcG9wdXAgPSBwYXN0ZShsaWJzJG5hbWUsIGxpYnMkc3RyZWV0LCBsaWJzJGNpdHksIHNlcCA9ICI8YnIvPiIpLCBpY29uID0gaWNvbnMpCm0KYGBgCgojIyBOZWFyZXN0IGxpYnJhcnkKCkRpc3RhbmNlIHRvIGxpYnJhcnkgKGFzIHRoZSBjcm93IGZsaWVzKS4KCmBgYHtyLCBtZXNzYWdlPUYsd2FybmluZz1GfQphbGxfbGliIDwtIGZpbHRlcihsaWJzLCBhbWVuaXR5ID09ICJsaWJyYXJ5IikKYWxsX3NjaG9vbHMgPC0gZmlsdGVyKGxpYnMsIGFtZW5pdHkgPT0gInNjaG9vbCIpCgphbGxfc2Nob29scyRuZWFyZXN0IDwtIHN0X25lYXJlc3RfZmVhdHVyZShhbGxfc2Nob29scywgYWxsX2xpYikKYWxsX2xpYiRuZWFyZXN0IDwtIGFzLmludGVnZXIocm93Lm5hbWVzKGFsbF9saWIpKQoKZGYgPC0gYXNfdGliYmxlKHNlbGVjdCgKYWxsX3NjaG9vbHMsIG5hbWUsCnN0cmVldCwKY2l0eSwKbmVhcmVzdAopKQoKZGZfbGliIDwtIGFzX3RpYmJsZSgKICBzZWxlY3QoCiAgYWxsX2xpYiwgbmFtZSwKICBzdHJlZXQsCiAgY2l0eSwKICBuZWFyZXN0KSkKCmRmIDwtIHJpZ2h0X2pvaW4oZGYsIGRmX2xpYiwgYnkgPSBjKCJuZWFyZXN0IiA9ICJuZWFyZXN0IikpCgpkZiRkaXN0YW5jZSA8LSBzdF9kaXN0YW5jZShkZiRnZW9tZXRyeS54LCBkZiRnZW9tZXRyeS55LCBieV9lbGVtZW50ID0gVFJVRSkgLyAxMDAwCnVuaXRzKGRmJGRpc3RhbmNlKSA9IE5VTEwKZGYkZGlzdGFuY2UgPC0gcm91bmQoZGYkZGlzdGFuY2UsIDEpCgp0YWJsZV9kZiA8LSBhc190aWJibGUodHJhbnNtdXRlKGRmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTY2hvb2wiID0gbmFtZS54LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTY2hvb2wgQWRkcmVzcyIgPSBwYXN0ZShkZiRzdHJlZXQueCwgZGYkY2l0eS54LCBzZXAgPSAiLCAiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTmVhcmVzdCBMaWJyYXJ5IiA9IG5hbWUueSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGlicmFyeSBBZGRyZXNzIiA9IHBhc3RlKGRmJHN0cmVldC55LCBkZiRjaXR5LnksIHNlcCA9ICIsICIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEaXN0YW5jZSBpbiBrbSIgPSBkaXN0YW5jZSkpCgpkYXRhdGFibGUodGFibGVfZGYpCgpgYGAKCg==