Getting Data

Author

Josef Fruehwald

Published

March 9, 2023

ky <- counties(state = "KY")
lex <- ky |> filter(NAME == "Fayette")

New for today

# install.packages(tidygeocoder)
library(tidygeocoder)
# install.packages("osmdata")
library(osmdata)
#remotes::install_github("riatelab/osrm")
library(osrm)

Other packages & resources:

lex_addr <- read_sf("source.geojson")
ggplot()+
  geom_sf(data = lex) + 
  geom_sf(data =lex_addr, size = 0.01, alpha = 0.05) +
  labs(title = "A map of all addresses in Lexington")+
  theme_void()

Tidy Geocoder

Info:

https://jessecambon.github.io/tidygeocoder/

tibble(
  UK_landmarks = c(
    "Patterson Office Tower, Lexington, KY",
    "William T Young Library, Lexington, KY",
    "Otis A. Singletary Center for the Arts, Lexington, KY",
    "Rupp Arena, Lexington, Kentucky",
    "Kroger Field, Lexington, Kentucky",
    "Memorial Hall, Lexington, Kentucky"
  )
) |> 
  geocode(UK_landmarks) ->
  uky_places
uky_places
# A tibble: 6 × 3
  UK_landmarks                                            lat  long
  <chr>                                                 <dbl> <dbl>
1 Patterson Office Tower, Lexington, KY                  38.0 -84.5
2 William T Young Library, Lexington, KY                 38.0 -84.5
3 Otis A. Singletary Center for the Arts, Lexington, KY  NA    NA  
4 Rupp Arena, Lexington, Kentucky                        38.0 -84.5
5 Kroger Field, Lexington, Kentucky                      38.0 -84.5
6 Memorial Hall, Lexington, Kentucky                     38.0 -84.5
uky_places |> 
  rowwise() |>  
  mutate(geometry = list(st_point(c(long, lat)))) |> 
  st_as_sf()->
  uk_points

st_crs(uk_points) <- 4326
mapview(uk_points)
Warning in validateCoords(lng, lat, funcName): Data contains 1 rows with either
missing or invalid lat/lon values and will be ignored

Official Sources

Lexington Data Hub

Shape files are downloadable, or:

  • View Full Details ->

  • View API Resources ->

  • Copy the GeoJSON link

lex_bike <- read_sf("https://services1.arcgis.com/Mg7DLdfYcSWIaDnu/arcgis/rest/services/Bicycle_Network/FeatureServer/0/query?outFields=*&where=1%3D1&f=geojson")
ggplot()+
  geom_sf(data = lex)+
  geom_sf(data = lex_bike)

lex_councils <- read_sf("https://services1.arcgis.com/Mg7DLdfYcSWIaDnu/arcgis/rest/services/Council_District_2012/FeatureServer/0/query?outFields=*&where=1%3D1&f=geojson")
ggplot()+
  geom_sf(data = lex_councils, aes(fill = factor(DISTRICT)))

lex_bike |> 
  st_intersection(lex_councils) ->
  lex_bike_in_council
Warning: attribute variables are assumed to be spatially constant throughout all
geometries
lex_bike_in_council |> 
  ggplot()+
    geom_sf(data = lex)+
    geom_sf(aes(color = factor(DISTRICT)))

lex_bike |> 
  st_intersection(lex_councils) |> 
  group_by(DISTRICT) |> 
  summarise() |> 
  mutate(len = st_length(geometry)) |> 
  st_drop_geometry() |> 
  arrange(desc(len))
Warning: attribute variables are assumed to be spatially constant throughout all
geometries
# A tibble: 12 × 2
   DISTRICT    len
      <int>    [m]
 1       12 45602.
 2        1 44526.
 3        3 44427.
 4        5 42098.
 5        2 40433.
 6        6 38747.
 7       10 38496.
 8        7 38252.
 9        9 37219.
10        8 31512.
11        4 29464.
12       11 27430.

OSM data

[1] "4wd_only"  "abandoned" "abutters"  "access"    "addr"      "addr:city"
[1] "agrarian"  "alcohol"   "anime"     "antiques"  "appliance" "art"      
opq(bbox = "lexington, kentucky") |> 
  add_osm_feature(key = "parking") |> 
  osmdata_sf() -> lex_parking
lex_parking$osm_polygons |> 
  mapview()
lex_parking$osm_polygons |> 
  st_intersection(lex_councils) |> 
  group_by(DISTRICT) |> 
  summarise() |> 
  mutate(area = st_area(geometry)) |> 
  st_drop_geometry() |> 
  arrange(desc(area))
Warning: attribute variables are assumed to be spatially constant throughout all
geometries
# A tibble: 12 × 2
   DISTRICT    area
      <int>   [m^2]
 1        3 364701.
 2       12  97132.
 3        2  50098.
 4        4  37441.
 5        9  36548.
 6        1  29790.
 7        7  26475.
 8       11  26271.
 9        8  15536.
10        5  12143.
11       10   8699.
12        6   8235.

Route Data

tribble(
  ~name, ~addr,
  "POT", "120 Patterson Dr, Lexington, KY 40506",
  "Kroger", "704 Euclid Ave, Lexington, KY 40502"
) |> 
  geocode(addr) |> 
  rowwise() |> 
  mutate(geom = list(st_point(c(long, lat)))) |> 
  st_as_sf() ->
  kroger_trip

st_crs(kroger_trip) <- 4326
kroger_route <-osrmRoute(
  kroger_trip$geom[1], 
  kroger_trip$geom[2], 
  osrm.profile = "foot")
kroger_route
Simple feature collection with 1 feature and 4 fields
Geometry type: LINESTRING
Dimension:     XY
Bounding box:  xmin: -84.50409 ymin: 38.03038 xmax: -84.49229 ymax: 38.03877
Geodetic CRS:  WGS 84
        src dst duration distance                       geometry
src_dst src dst 22.64833   1.6961 LINESTRING (-84.50409 38.03...
mapview(kroger_route)

Isochrones

osrmIsochrone(
  loc = kroger_trip$geom[2], 
  breaks = seq(0,60, by = 5), 
  osrm.profile = "foot"
)->
  kroger_walks
mapview(kroger_walks, zcol = "isomax")

Mashup

opq(bbox = "Lexington, KY") |> 
  add_osm_feature(key = "shop", value = "supermarket") |> 
  osmdata_sf()->
  osm_markets
osm_markets$osm_points |> 
  st_filter(osm_markets$osm_polygons, .predicate = st_intersects)->
  market_overlap_points
osm_markets$osm_points |> 
  anti_join(market_overlap_points |> st_drop_geometry()) ->
  lex_market_points
osm_markets$osm_polygons |> 
  st_centroid() |> 
  bind_rows(lex_market_points) ->
  all_lex_market
Warning in st_centroid.sf(osm_markets$osm_polygons): st_centroid assumes
attributes are constant over geometries of x
mapview(all_lex_market, label = "name")
all_lex_market |> 
  st_join(lex_councils, join = st_covered_by) |> 
  count(DISTRICT) |> 
  arrange(n)
Simple feature collection with 12 features and 2 fields
Geometry type: GEOMETRY
Dimension:     XY
Bounding box:  xmin: -84.59149 ymin: 37.86554 xmax: -84.41769 ymax: 38.18635
Geodetic CRS:  WGS 84
First 10 features:
   DISTRICT n                       geometry
1         5 1      POINT (-84.47888 37.9968)
2         7 1     POINT (-84.44418 38.00359)
3         2 2 MULTIPOINT ((-84.52705 38.0...
4         8 2 MULTIPOINT ((-84.47953 37.9...
5         1 3 MULTIPOINT ((-84.48315 38.0...
6         3 3 MULTIPOINT ((-84.51595 38.0...
7        10 3 MULTIPOINT ((-84.55931 38.0...
8         4 4 MULTIPOINT ((-84.49641 37.9...
9         6 4 MULTIPOINT ((-84.46126 38.0...
10        9 4 MULTIPOINT ((-84.55002 37.9...
all_lex_market |> 
  st_join(lex_councils, join = st_covered_by) |> 
  select(DISTRICT, name) ->
  market_by_district 

mapview(market_by_district, zcol = "DISTRICT", label = "name")
all_lex_market |> 
  st_filter(
    st_buffer(lex_bike, 100),
    .predicate = st_intersects
  ) -> 
  lex_market_bike
lex_market_bike |> 
  select(name) |> 
  mapview(label = "name")
lex |> 
  st_transform(st_crs(lex_bike)) -> 
  lex_reproj
all_lex_market |> 
  st_filter(
    lex_reproj,
    .predicate = st_covered_by
  ) ->
  in_lex_markets
in_lex_markets |> 
  st_filter(
    st_buffer(lex_bike, 100),
    .predicate = st_intersects
  ) -> lex_market_bike

in_lex_markets |> 
  anti_join(lex_market_bike |>st_drop_geometry()) ->
  lex_nobike
ggplot()+
  geom_sf(data = lex_reproj) +
  geom_sf(data = lex_bike, color = "darkgreen", linewidth = 0.2)+
  geom_sf(data = lex_market_bike, aes(color = "bikable"))+
  geom_sf(data = lex_nobike, aes(color = "not bikable"))+
  khroma::scale_color_bright(name = "supermarkets")+
  theme_void()