--- title: "Looking for a home" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Looking for a home} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = nzchar(Sys.getenv("CLOSECITY_KEY")) ) library(closecity) library(sf) close <- closecity::close_client(api_key = Sys.getenv("CLOSECITY_KEY")) ``` Say you are moving to a new city and want to live near the amenities that are important to you. In this tutorial, we find the blocks that are within a 10-minute walk of a supermarket, a 5-minute walk of a restaurant, and a 20-minute walk of a frequent-transit stop. Then, we narrow those blocks to the overlap of two commutes. The example city is Somerville, Massachusetts. *Running this tutorial uses about 2,600 tokens.* ## Set up Build a client, then read the pieces you need from the free catalog instead of memorising codes. ```r library(closecity) library(sf) close <- closecity::close_client(api_key = "ck_live_your_key") # use your own key here ``` ```{r} # The catalog lists every category with its numeric id. Pull the ids you need. amenity_types <- close$destination_types() ids <- setNames(amenity_types$dest_type_id, amenity_types$label) supermarket_dest_id <- ids[["grocery_stores"]] restaurant_dest_id <- ids[["restaurants"]] freq_transit_stop_dest_id <- ids[["frequent_transit"]] # Turn the city name into a GEOID and pull its boundary for context. city <- close$places(q = "Somerville")[1, ] city_boundary <- close$place_boundary(geoid = city$geoid) ``` ## See what is around Look at the raw ingredients first: every supermarket, restaurant, and frequent-transit stop **within Somerville**, from `$place_pois()`. The city boundary, not a guessed radius, is the edge. Give each category a colour and map them together. ```{r} supermarkets <- close$place_pois(geoid = city$geoid, type = supermarket_dest_id) restaurants <- close$place_pois(geoid = city$geoid, type = restaurant_dest_id) stops <- close$place_pois(geoid = city$geoid, type = freq_transit_stop_dest_id) supermarkets$kind <- "Supermarket" restaurants$kind <- "Restaurant" stops$kind <- "Transit stop" around <- rbind(supermarkets, restaurants, stops) palette <- c(Supermarket = "#058040", Restaurant = "#c6cbe0", `Transit stop` = "#f36e21") closecity::close_map( x = around, color = palette[around$kind], label = "kind", boundary = city_boundary ) ``` ## Find the blocks that qualify Somerville is a census place, so one call by place GEOID pulls the per-block walk times for every block in the city. `$place_blocks()` reads every page and returns one sf row per (block, category); block boundaries come from `tigris`, downloaded once and cached. (To search an arbitrary area instead, use `$blocks_query()` with a centre and radius or a polygon. We do that with a radius in the other tutorials only to keep their token cost low; a place GEOID pulls the whole city.) ```{r} blocks <- close$place_blocks( geoid = city$geoid, mode = "walk", type = c(supermarket_dest_id, restaurant_dest_id, freq_transit_stop_dest_id) ) ``` Reshape to one row per block, with a walk-time column for each amenity, so a block carries all three times at once (and the hover on the map shows them). Then flag the blocks that pass every rule. ```{r} city_blocks <- blocks[!duplicated(blocks$geoid), "geoid"] time_to <- function(type_id) { sub <- blocks[blocks$dest_type_id == type_id, ] setNames(sub$travel_time, sub$geoid)[city_blocks$geoid] } city_blocks$supermarket_min <- time_to(supermarket_dest_id) city_blocks$restaurant_min <- time_to(restaurant_dest_id) city_blocks$transit_min <- time_to(freq_transit_stop_dest_id) city_blocks$qualifies <- (city_blocks$supermarket_min <= 10 & city_blocks$restaurant_min <= 5 & city_blocks$transit_min <= 20) city_blocks$qualifies[is.na(city_blocks$qualifies)] <- FALSE ``` Show every block in the city, highlight the ones that qualify, and hover any block to read its walk time to each amenity. ```{r} closecity::close_map( x = city_blocks, highlight = "qualifies", color = "#f36e21", boundary = city_boundary ) ``` ## Narrow to a shared commute Suppose two of you work in different places. A transit isochrone from each workplace shows how far each commute reaches; drawn together, half-transparent, you can see both at once. ```{r} work_a <- close$isochrone( lon = -71.0865, lat = 42.3625, mode = "transit", direction = "from", minutes = 20, format = "geojson" ) work_b <- close$isochrone( lon = -71.0589, lat = 42.3555, mode = "transit", direction = "from", minutes = 20, format = "geojson" ) closecity::close_map( x = work_a, color = "#058040", opacity = 0.5, background = work_b, background_color = "#f36e21", background_opacity = 0.5 ) ``` Keep the qualifying blocks that also sit inside both commutes. The final map shows those winning blocks, with the shortlist (inside both commutes) highlighted, over the two commute walksheds. ```{r} both_commutes <- sf::st_intersection(sf::st_union(work_a), sf::st_union(work_b)) winners <- city_blocks[city_blocks$qualifies, ] winners$shortlist <- sf::st_intersects(winners, both_commutes, sparse = FALSE)[, 1] closecity::close_map( x = winners, highlight = "shortlist", color = "#1f78b4", boundary = city_boundary, background = list(work_a, work_b), background_color = c("#058040", "#f36e21"), background_fill = FALSE ) ```