Getting started

A short tour of the client. The tutorials go further.

Words you will see

A few terms come up throughout:

  • Census block. The smallest area the Census Bureau publishes. Each one has a 15-digit id, its GEOID.

  • 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. The area reachable from a point within a time limit, as a polygon.

  • Catchment. The reverse: every block that can reach a given place.

Build a client

You make every request through a client.

from closecity import Client

close = Client("ck_live_your_key")   # use your own key here

The catalog and lookup routes are free, so Client() with no key works for those. They come back as data frames:

close.modes()
mode_id mode description
0 1 walk Walking
1 2 bike Biking
2 3 transit Public transit

Look things up instead of guessing

Read the numeric id for a category from the catalog, and turn a city name into a GEOID and a centre point. Both are plain data frames, so you filter and index them the usual way.

types = close.destination_types()
grocery = types.loc[types["label"] == "grocery_stores", "dest_type_id"].iloc[0]

matches = close.places("Providence")
providence = matches.iloc[0]
providence["geoid"]
'4459000'

Make a call and map it

Routes with geometry return a GeoDataFrame, so you can map the result straight away.

groceries = close.pois_search(lat = providence["lat"], lon = providence["lon"],
                              radius_m = 1500, type = grocery)
groceries.plot(color = "#202a5b")
<Axes: >
_images/f69eef77c1241604edcf950411011e56d54868b4ecc59d14f2cd8531e29235cf.png

Choose an output

Every route returns tabular data by default. The output setting controls the shape:

  • "spatial" (the default) returns a GeoDataFrame where geometry applies, and a plain DataFrame otherwise.

  • "tabular" returns a plain DataFrame for every route and never downloads block boundaries. Reach for it when you only want the numbers.

  • "raw" returns the underlying reply, with the parsed body on .data and the token counts alongside.

Set it on the client, or pass output= to a single call.

close.output = "raw"
summary = close.block_summary("440070008001068", mode = "walk")
summary.results
[{'dest_type_id': 1, 'mode': 'walk', 'travel_time': 10.0},
 {'dest_type_id': 5, 'mode': 'walk', 'travel_time': 26.0},
 {'dest_type_id': 6, 'mode': 'walk', 'travel_time': 22.0},
 {'dest_type_id': 7, 'mode': 'walk', 'travel_time': 10.0},
 {'dest_type_id': 27, 'mode': 'walk', 'travel_time': 3.0},
 {'dest_type_id': 28, 'mode': 'walk', 'travel_time': 3.0},
 {'dest_type_id': 29, 'mode': 'walk', 'travel_time': 9.0},
 {'dest_type_id': 30, 'mode': 'walk', 'travel_time': 6.0},
 {'dest_type_id': 31, 'mode': 'walk', 'travel_time': 3.0},
 {'dest_type_id': 32, 'mode': 'walk', 'travel_time': 15.0},
 {'dest_type_id': 33, 'mode': 'walk', 'travel_time': 18.0},
 {'dest_type_id': 34, 'mode': 'walk', 'travel_time': 9.0},
 {'dest_type_id': 35, 'mode': 'walk', 'travel_time': 13.0},
 {'dest_type_id': 38, 'mode': 'walk', 'travel_time': 17.0},
 {'dest_type_id': 40, 'mode': 'walk', 'travel_time': 8.0},
 {'dest_type_id': 41, 'mode': 'walk', 'travel_time': 9.0},
 {'dest_type_id': 43, 'mode': 'walk', 'travel_time': 3.0},
 {'dest_type_id': 60, 'mode': 'walk', 'travel_time': 2.0},
 {'dest_type_id': 63, 'mode': 'walk', 'travel_time': 3.0},
 {'dest_type_id': 64, 'mode': 'walk', 'travel_time': 4.0},
 {'dest_type_id': 65, 'mode': 'walk', 'travel_time': 7.0},
 {'dest_type_id': 66, 'mode': 'walk', 'travel_time': 13.0},
 {'dest_type_id': 67, 'mode': 'walk', 'travel_time': 3.0},
 {'dest_type_id': 126, 'mode': 'walk', 'travel_time': 10.0},
 {'dest_type_id': 159, 'mode': 'walk', 'travel_time': 14.0},
 {'dest_type_id': 160, 'mode': 'walk', 'travel_time': 24.0},
 {'dest_type_id': 200, 'mode': 'walk', 'travel_time': 2.0},
 {'dest_type_id': 204, 'mode': 'walk', 'travel_time': 2.0},
 {'dest_type_id': 205, 'mode': 'walk', 'travel_time': 2.0},
 {'dest_type_id': 206, 'mode': 'walk', 'travel_time': 4.0},
 {'dest_type_id': 207, 'mode': 'walk', 'travel_time': 7.0},
 {'dest_type_id': 208, 'mode': 'walk', 'travel_time': 3.0},
 {'dest_type_id': 209, 'mode': 'walk', 'travel_time': 9.0}]

In the frame modes, the token counts and other reply metadata ride on df.attrs.

Errors

Problem responses become typed exceptions.

from closecity import CloseAPIError

try:
    close.block_summary("000000000000000")
except CloseAPIError as err:
    print(err.status, err.slug)
404 block-not-found