shadow-cljs
build tool)xforms
library)npm install citysdk
citysdk
FunctionCitySDK exports a single function, which takes two arguments:
census
function and
applied to the responseBrief overview of each argument parameter that can be passed into CitySDK
Parameter | Type | Description | Geocodes | Stats | GeoJSON | GeoJSON with Stats |
---|---|---|---|---|---|---|
vintage |
int /str |
The reference year (typically release year) of the data | ✔ | ✔ | ✔ | ✔ |
geoHierarchy |
object |
The geographic scope and hierarchical path to the data | ✔ | ✔ | ✔ | ✔ |
sourcePath |
array |
Refers to the Census product of interest | ✔ | ✔ | ||
values |
array |
For statistics, values request counts/estimates via variable IDs |
✔ | ✔ | ||
geoResolution |
str |
Resolution of GeoJSON ("20m" , "5m" , and "500k" available) |
✔ | ✔ | ||
predicates |
object |
Used as a filter available on some values |
✔* |
✔* |
||
statsKey |
str |
You may request a key for Census' statistics API here | ✔** |
✔** |
*
: optional **
: optional for < 500 requests daily
With the exception of “microdata” statistics (not yet available via
Census’ API), all Census data is aggregated to geographic areas of
different sizes. As such, all of Census’ API’s require a set of/unique
geographic identifier(s) to return any data (AKA:
FIPS). Given
that these identifiers are not common knowledge, the CitySDK provides a
way for the user to identify their geographic scope of interest using a
geographic coordinate (lat
+ lng
).
Under the hood, this functionality calls the TigerWeb Web Mapping
Service
with the lat
& lng
provided and pipes the resulting FIPS codes into
your options argument with the appropriate
GEOIDs for
identifying your geographic area of interest.
For a list of geographies currently available for geocoding with this feature, see the Geographies Available by Vintage section below.
There are two ways to scope your geography using this functionality:
RETURN TYPE: JSON
You may pass a {"lat" : <float>, "lng" : <float>}
object as the first
and only value for the geoHierarchy
key:
const census = require("citysdk")
census(
{
vintage: 2015, // required
geoHierarchy: {
// required
county: {
lat: 28.2639,
lng: -80.7214
}
}
},
(err, res) => console.log(res)
)
// result -> {"vintage":"2015","geoHierarchy":{"state":"12","county":"009"}}
Notice how the function prepends an additional geographic component
("state" : "12"
) to the options object. In order to fully qualify the
geographic area (GEOID) associated with the county, the state is needed.
In this example the fully qualified GEOID would be 12009
with the
first two digits (12
) qualifying the state and 009
qualifying the
county within that state. This appropriate geographic hierarchy creation
is handled by the function for you.
RETURN TYPE: JSON
const census = require("citysdk")
census(
{
vintage: "2015", // required
geoHierarchy: {
// required
state: {
lat: 28.2639,
lng: -80.7214
},
county: "*" // <- syntax = "<descendant>" : "*"
}
},
(err, res) => console.log(res)
)
// result -> {"vintage":"2015","geoHierarchy":{"state":"12","county":"*"}}
All Census-defined geographic areas are composed of Census “Blocks”. Some of these composed areas - themselves - compose into higher-order areas. These nested relationships between certain geographic areas allows the Census data user to request all descendants of a particular type.
geoHierarchy
object to an
ordered set, so this part of your request object must be in
descending hierarchical order from parent -> descendant. E.g. -
in the above - an object that contained
{"county" : "*", "state" : {"lat" <lat> "lng" <lng>}}
will not
work.geoHierarchy
object ("county" : "*"
). It is important to use the
"*"
expression signifying that you want all of the specified
level of
descendants
within the geography for which you supply a coordinate. No other
expression will work.This parameter set will call the Census Statistics API and reformat the results with a couple highly requested features:
There are two ways to request Census statistics using citysdk
:
values
of estimates and other statistical values
(required)predicates
(optional)For both of these options, a sourcePath
needs to be supplied. This is
the fully qualified path to the product. For more information about how
to find the sourcePath
to your product of interest, go to the
Developers’ Microsite and - in any
of the examples of making a call - take the path between <vintage>/
and the ?get
. For example, for American Community Survey
1-year
you’ll the first example (2017) shows:
https://api.census.gov/data/2017/acs/acs1?get=NAME,group(B01001)&for=us:1
└─┬─┘└───┬────┘
vintage sourcePath
The corresponding sourcePath
for this endpoint is ["acs", "acs1"]
"values"
by ID:RETURN TYPE: JSON
census(
{
vintage: 2015, // required
geoHierarchy: {
// required
county: {
lat: 28.2639,
lng: -80.7214
}
},
sourcePath: ["cbp"], // required
values: ["ESTAB"] // required
},
(err, res) => console.log(res)
)
// result -> [{"ESTAB":13648,"state":"12","county":"009"}]
Here, we added the parameters for sourcePath
(the path to the survey
and/or source of the statistics) and values
(the identifiers of the
statistics we’re interested in). By including these parameters within
your argument object, you trigger the census
function to get
statistics. This “deploy on parameter set” strategy is how the census
function determines your intent.
You’re probably thinking: “How am I supposed to know what codes to use
inside those parameters?” - or - “Where did that "cbp"
& "ESTAB"
stuff come from?” The data sets covered by the CitySDK are vast. As
such, this is the steepest part of the learning curve. But, don’t worry,
there are a number of different resources available to assist you in
your quest:
"values"
by ID (with key):RETURN TYPE: JSON
census(
{
vintage: 2015, // required
geoHierarchy: {
// required
county: {
lat: 28.2639,
lng: -80.7214
}
},
sourcePath: ["cbp"], // required
values: ["ESTAB"], // required
statsKey: "<your key here>" // required for > 500 calls per day
},
(err, res) => console.log(res)
)
// result -> [{"ESTAB":13648,"state":"12","county":"009"}]
predicates
:RETURN TYPE: JSON
predicates
Predicates are used to create a sub-selection of statistical values based on a given range or categorical qualifyer.
census(
{
vintage: "2017",
geoHierarchy: {
state: "51",
county: "*"
},
sourcePath: ["acs", "acs1"],
values: ["NAME"],
predicates: {
B01001_001E: "0:100000" // number range separated by `:`
},
statsKey: "<your key here>"
},
(err, res) => console.log(res)
)
/* result:
[
{
"NAME":"Augusta County, Virginia",
"B01001_001E" : 75144,
"state":"51",
"county":"015"
},
{
"NAME":"Bedford County, Virginia",
"B01001_001E" : 77974,
"state":"51",
"county":"019"
},
...
]
*/
If you’d like to use “timeseries” data, you may do so for statistics
only. Mapping timeseries data is currently unsupported. Note that many
timeseries products rely heavily on the "predicates"
option:
'timeseries"
data:RETURN TYPE: JSON
census(
{
vintage: "timeseries", // required
geoHierarchy: {
// required
us: "*"
},
sourcePath: ["asm", "industry"], // required
values: ["EMP", "NAICS_TTL", "GEO_TTL"],
predicates: { time: "2016", NAICS: "31-33" }
},
(err, res) => console.log(res)
)
/* result:
[{"EMP": 11112764,
"NAICS_TTL": "Manufacturing",
"GEO_TTL": "United States",
"time": "2016",
"NAICS": "31-33",
"us":"1"}]
*/
For some sources (e.g., the American Community Survey), most of the
values
can also be used as predicates
, but are optional. In others,
(e.g., International Trade), predicates
are a key part of the
statistical query. In either case, at least one value within values
must be supplied.
You can also use the CitySDK to retrieve Cartographic Boundary files,
which have been translated into GeoJSON. The only additional parameter
you’ll need to know is a simple declaration of geoResolution
of which
there are three options:
Resolution | Map Scale | Benefits | Costs |
---|---|---|---|
500k | 1:500,000 | Greatest variety of summary levels & Most detailed | largest file sizes |
5m | 1:5,000,000 | Balance between size and detectable area size | lowest variety of available area types |
20m | 1:20,000,000 | Smallest file sizes | lowest level of detail |
See the full available Cartographic GeoJSON in the Geographies Available by Vintage section
fs
RETURN TYPE: JSON STRING
const fs = require("fs")
census(
{
vintage: 2017,
geoHierarchy: {
"metropolitan statistical area/micropolitan statistical area": "*"
},
geoResolution: "500k" // required
},
(err, res) => {
fs.writeFile("./directory/filename.json", JSON.stringify(res), () => console.log("done"))
}
)
This would convert the returned geojson to a string, which allows it to be saved via Node.js’ fileSystem API.
census(
{
vintage: "2017",
geoHierarchy: {
state: "51",
county: "*"
},
geoResolution: "500k" // required
},
(err, res) => console.log(res)
)
It’s important to note that - when querying for these GeoJSON files - you may retrieve a larger area than your request argument specifies. The reason for this is that the files are (currently) stored at two geographic levels: National and by State. Thus, the query above will attempt to resolve, at the state level, all counties, but because counties are stored at the national level in vintage 2017, all the counties in the US will be returned by this query.
If you wish to get back only those geographies you specify, you may do
so by using the last and perhaps most useful feature included in the
v2.0 release: Getting GeoJSON with statistics included within the
"FeatureCollection"
properties
object!
RETURN TYPE: JSON
There are a number of reasons you might want to merge your statistics into their GeoJSON/geographic boundaries, all of which are relevant when seeking to map Census data:
values
)A more dynamic example of using stats merged with GeoJSON on the fly
with citysdk
can be found here:
Type in a county name and see the unweighted sample count of the population (ACS) for all the Block Groups within that County.
Use Chrome for best results (mapbox-gl geocoder caveat)
census({
vintage: "2017",
geoHierarchy: {
county: "*"
},
sourcePath: ["acs", "acs5"],
values: ["B19083_001E"], // GINI index
statsKey: "<your key here>",
geoResolution: "500k"
})
In this example, we use citysdk
to create the payload and then save it
via Nodes
fs.writeFileSync
and then serve it via a
Mapbox-GL map.
census({
vintage: "2017",
geoHierarchy: {
"zip-code-tabulation-area": "*"
},
sourcePath: ["acs", "acs5"],
values: ["B19083_001E"], // GINI index
statsKey: "<your key here>",
geoResolution: "500k"
})
This is a very large request, in fact, one of the largest you could
possibly make in a single citysdk
function call. It is so large, in
fact that it currently only works on Node and only if you increase your
node --max-old-space-size=4096
. With large merges (such as all
counties or zctas), it is recommended not to try to use citysdk
dynamically, but - rather - to munge your data before hand with
citysdk
and then serve it statically to your mapping library, as was
done here:
// Call the WMS only
{
"vintage": 2014,
"geoHierarchy": { "state": { "lat": 28.2639, "lng": -80.7214 }, "county": '*' }
}
// Getting the stats for a single county filtering out any county with population under 100,000
{
"vintage": 2016,
"geoHierarchy": { "county": { "lat": 28.2639, "lng": -80.7214 } },
"sourcePath": [ "acs", "acs5" ],
"values": [ "B01001_001E" ]
"predicates": { "B00001_001E": "0:100000" },
}
// strings are valid as vintages as well
{
"vintage": "2015",
"geoHierarchy": { "county": { "lat": 28.2639, "lng": -80.7214 } },
"sourcePath": [ "cbp" ],
"values": [ "ESTAB" ]
}
// Just geojson for all the counties within a state located by a given coordinate
{
"vintage": 2014,
"geoHierarchy": { "state": { "lat": 28.2639, "lng": -80.7214 }, "county": "*" },
"geoResolution": "500k"
}
// For large request expect to have to increase `node --max-old-space-size=4096`
{
"vintage": 2016,
"sourcePath": [ "acs", "acs5" ],
"values": [ "B25001_001E" ],
"geoHierarchy": { "zip-code-tabulation-area": "*" },
"geoResolution": "500k"
}
The Census Bureau publishes both high and low accuracy geographic area files to accommodate the widest possible variety of user needs (within feasibility). Cartography Files are simplified representations of selected geographic areas from the Census Bureau’s Master Address File/Topologically Integrated Geographic Encoding and Referencing (MAF/TIGER) system. These boundary files are specifically designed for small scale thematic mapping (i.e., for visualizations).
For a while now, we have published our cartography files in the
.shp
format. More recently, we expanded our portfolio of available formats to
.kml
. It
is with this release that we follow suit with the community at large to
release these boundaries in .json
(GeoJSON) format.
The most comprehensive set of geographies and vintages can be found
within the 500k
set.
Some vintages - 103
through
110
"congressional district"
The following
tables represent the availability of various geographic summary levels
through the remaining vintages:Geographic Area Type | 1990 | 2000 | 2010 | 2012 | 2013 - 2015 | 2016 - 2019 |
---|---|---|---|---|---|---|
"alaska native regional corporation" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"american indian-area/alaska native area/hawaiian home land" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"block group" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"combined new england city and town area" |
✔ | ✔ | ||||
"combined statistical area" |
✔ | ✔ | ✔ | |||
"congressional district" |
✔ | ✔ | ✔ | ✔ | ||
"consolidated cities" |
✔ | ✔ | ✔ | ✔ | ||
"county" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"county subdivision" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"division" |
✔ | ✔ | ✔ | ✔ | ||
"metropolitan statistical area/micropolitan statistical area" |
✔ | ✔ | ✔ | |||
"new england city and town area" |
✔ | ✔ | ✔ | |||
"place" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"public use microdata area" |
✔ | ✔ | ||||
"region" |
✔ | ✔ | ✔ | ✔ | ||
"school district (elementary)" |
✔ | ✔ | ✔ | |||
"school district (secondary)" |
✔ | ✔ | ✔ | |||
"school district (unified") |
✔ | ✔ | ✔ | |||
"state" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"state legislative district (lower chamber)" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"state legislative district (upper chamber)" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"tract" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"urban area" |
✔ | ✔ | ✔ | ✔ | ✔ | |
"us" |
✔ | ✔ | ✔ | |||
"zip code tabulation area" |
✔ | ✔ | ✔ |
If you’re new to Census data and need some help figuring out which of the many products Census curates for public use, don’t hesitate to reach out to these contacts for help: