---
title: "Get started with closecity"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Get started with closecity}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
# Examples run when a key is present (on the docs site), and are shown but not run
# otherwise (on CRAN, and locally without a key). The displayed client uses a
# placeholder; the real one is built here from an environment variable.
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = nzchar(Sys.getenv("CLOSECITY_KEY"))
)
library(closecity)
close <- closecity::close_client(api_key = Sys.getenv("CLOSECITY_KEY"))
```

`closecity` reads the Close API: travel times from every US census block to nearby
places, on foot, by bike, and by public transit. This vignette is a short tour.
The tutorials go further. The full list of query methods is on the
[`CloseClient`](../reference/CloseClient.html) reference page, and the wider API is
documented at [docs.close.city](https://docs.close.city).

## Key terms

A few terms come up throughout:

- **Census block.** The smallest area the Census Bureau publishes. Each one has a
  15-digit id, its **GEOID**. Block GEOIDs come from the census. Look them up with
  the `tigris` or `tidycensus` packages, the Census Bureau geocoder/API, or read
  them straight off Close's block routes (`$blocks_query()`, `$place_blocks()`).
- **Destination type.** A category of place, such as grocery stores or libraries.
  Every type has a numeric id.
- **Mode.** How someone travels: walk, bike, or transit.
- **Isochrone** or **catchment**: the area you can reach starting from a point
  within a time limit, by a selected travel mode.

## Travel times

Times to nearby places are **capped at 30 minutes** for each mode, and recorded in
**whole minutes**. A missing time means the place is not reachable within the cap,
not that it is zero. Isochrones are the exception: they are available for any
budget up to an hour.

## Build a client

You make every request through a client object.

```r
library(closecity)
close <- closecity::close_client(api_key = "ck_live_your_key")   # use your own key here
```

The catalog and lookup routes are free, so `close_client()` with no key also works
for those.

```{r}
close$modes()
```

## Look things up instead of guessing

Two free calls save you from memorising codes. Both come back as data frames, so
you filter and index them the usual way: read the numeric id for a category from
the catalog, and turn a city name into a GEOID and a centre point.

```{r}
amenity_types <- close$destination_types()
supermarket_type <- amenity_types[amenity_types$label == "grocery_stores", ]$dest_type_id

providence_ri <- close$places(q = "Providence")[1, ]
providence_ri[, c("name", "state", "geoid")]
```

The catalog's `name` column is the readable label ("Grocery stores"); the
underscored `label` is the internal key you match on. A place lookup carries a
`state`, so you can tell Providence, RI from the one in Utah. When you have a point
rather than a block, `$point_summary(lat = , lon = )` reads the same travel times
for a `lat`/`lon` starting point instead of a GEOID.

## Make a call and map it

Routes with geometry return an [sf](https://r-spatial.github.io/sf/) object.
`close_map()` draws it on an interactive basemap in one line: bright, hoverable
points here, with the city boundary behind them and the view zoomed to fit.

```{r}
supermarkets <- close$place_pois(geoid = providence_ri$geoid, type = supermarket_type)
city_boundary <- close$place_boundary(geoid = providence_ri$geoid)
closecity::close_map(
  x = supermarkets,
  color = "#e8590c",
  boundary = city_boundary,
  label = "name"
)
```

## Choose an output

Every route returns tabular data by default: an sf object for inherently spatial
data, a data frame otherwise. The `output` setting changes the shape: `"tabular"`
never downloads boundaries, and `"raw"` gives the underlying reply with its
metering and cursor fields. Set it on the client, or pass `output =` to one call.

A block summary, with the readable category names merged on and sorted by time:

```{r}
walk_times <- close$block_summary(geoid = "440070008001068", mode = "walk")
walk_times <- merge(
  walk_times,
  amenity_types[, c("dest_type_id", "name")],
  by = "dest_type_id"
)
walk_times[order(walk_times$travel_time), c("name", "travel_time")]
```

...and the same call as the raw reply, whose `results` you can inspect yourself:

```{r}
raw <- close$block_summary(geoid = "440070008001068", mode = "walk", output = "raw")
str(raw$results, max.level = 2, list.len = 3)
```

## The client methods

Every data-getting method lives on the client. Follow any name to its arguments and
return value on the [`CloseClient`](../reference/CloseClient.html) reference page.

Catalog and lookups (free, no key):

- [`$modes()`](../reference/CloseClient.html#method-CloseClient-modes): the travel modes, walk, bike, and transit.
- [`$destination_types()`](../reference/CloseClient.html#method-CloseClient-destination_types): the catalog of amenity categories and their numeric ids.
- [`$places()`](../reference/CloseClient.html#method-CloseClient-places): a city name to its GEOID and centre point.
- [`$place_boundary()`](../reference/CloseClient.html#method-CloseClient-place_boundary): the boundary polygon of a census place.
- [`$vintage()`](../reference/CloseClient.html#method-CloseClient-vintage): the data vintage.
- [`$last_updated()`](../reference/CloseClient.html#method-CloseClient-last_updated): when the data was last refreshed.
- [`$isochrone_meta()`](../reference/CloseClient.html#method-CloseClient-isochrone_meta): isochrone modes, directions, and assumptions.
- [`$health()`](../reference/CloseClient.html#method-CloseClient-health): a service health check.

Travel times from a block or a point:

- [`$block_summary()`](../reference/CloseClient.html#method-CloseClient-block_summary): walk/bike/transit time from a block to each amenity type.
- [`$point_summary()`](../reference/CloseClient.html#method-CloseClient-point_summary): the same, from a `lat`/`lon` point.
- [`$block_pois()`](../reference/CloseClient.html#method-CloseClient-block_pois): the individual POIs reachable from a block, each with its travel time.
- [`$point_pois()`](../reference/CloseClient.html#method-CloseClient-point_pois): the same, from a `lat`/`lon` point.

Points of interest:

- [`$pois_search()`](../reference/CloseClient.html#method-CloseClient-pois_search): search POIs by radius or bounding box.
- [`$poi()`](../reference/CloseClient.html#method-CloseClient-poi): the details of one POI.
- [`$poi_catchment()`](../reference/CloseClient.html#method-CloseClient-poi_catchment): the blocks that can walk to a POI (its catchment).

Whole areas:

- [`$blocks_query()`](../reference/CloseClient.html#method-CloseClient-blocks_query): per-block travel times for a polygon, or a centre and radius.
- [`$place_blocks()`](../reference/CloseClient.html#method-CloseClient-place_blocks): per-block travel times for every block in a place.
- [`$place_pois()`](../reference/CloseClient.html#method-CloseClient-place_pois): every POI within a place's boundary.
- [`$isochrone()`](../reference/CloseClient.html#method-CloseClient-isochrone): travel-time contours from a block or a point.

## Handle errors

Failed requests raise a classed condition. Catch the base `close_api_error`, or a
specific one.

```{r}
tryCatch(
  close$block_summary(geoid = "000000000000000"),
  close_api_error = function(e) message(sprintf("%s (%d)", e$slug, e$status))
)
```
