Tutorial Notebook: on Github | open in Colab
Reference map data for the Bias Bounties @ Scale challenge (Humane Intelligence / Reliabl). The challenge measures whether open map data (Overture Maps) systematically under-covers climate-vulnerable, rural, and tribal communities in the US, scored as a coverage-gap score per Census tract.
This product holds the Overture extracts and the authoritative reference layers they are scored against, clipped to four study regions and packaged as cloud-native GeoParquet.
📥 Getting the data
No download needed. Every snippet in this README reads straight from the bucket, no account, no credentials; that is the suggested way to work with it.
Jump to: Access (read remotely)
Need the whole package on disk? Use
aws s3 sync, not the browser. It resumes if the connection drops and re-running it only fetches what changed. Zips per region exist as a fallback for anyone who cannot install the CLI, but a multi-GB browser download that fails partway does not resume.
Each region covers well over the challenge's 5-tract minimum (591 to 6,010 tracts).
Every region boundary is the dissolve of its own Census tracts (eastern-ok since
2026-08-12, the other three since 2026-08-26), so every member tract lies fully inside its
region and every reference layer covers the whole of every scored tract. Membership is frozen
in boundaries/<region>-tract-geoids.csv (1,593 / 591 / 1,192 / 6,010). The authoritative
scored tract list for every region is its <region>-sample-submission.csv (one row per scored
tract), which matches strata/<region>/<region>-census-tracts.parquet exactly. Two rules keep
those lists clean: a tract belongs to exactly one region, decided by state FIPS (two
Oklahoma tracts on the Texas border, 40013795900 and 40085094200, are eastern-ok only),
and tracts with no scorable reference data are dropped from the list (7 in
south-central-tx, all 99xx water tracts; none elsewhere). Scored rows: 1,192 / 1,593 / 591 / 6,003.
One membership note: maricopa-az is 1,592 Arizona tracts plus one New Mexico tract,
35023970000 (Hidalgo County, Tract 9700, the bootheel), which overlaps the original AOI ring
where it meets the state line. It is a member on the same terms as every other tract; the
region is "Maricopa County and surrounding", not Arizona.
Region-major. Every file name is self-describing (<region>-<source>-<layer>.parquet), so a
file pulled out of its folder still identifies itself.
The strata are national, one row per 2020 census tract, 85,396 rows, keyed on GEOID.
strata/national/ is the source of truth; strata/<region>/ holds the same tables subset to a
region, so the two cannot drift. Every table below ships as .parquet and .csv.
national-strata-tract-table joins every layer into one 232-column table so you can stratify
without a dozen joins. It carries each source's headline columns; the per-source tables keep the
full detail (per-year components, per-raster min/max/stdev). Column names are prefixed by source
(svi_, cvi_, usdm_, usfs_, mtbs_, …) so provenance reads off the name.
Coverage is not uniform and is never filled with zero. Each source carries a *_covered flag
and explicit nulls where it does not reach. Several layers are CONUS-only (CarbonPlan, USFS, CDC
EPHT, CDC WONDER, SPI/PMDI); NCHS and CVI have never covered Puerto Rico; USDM and MTBS are the
only fully national hazard layers.
bbox column for
cloud-native range reads. Written with geoparquet-io.OGC:CRS84 (lon/lat, equivalent to EPSG:4326) on every layer.<region>-census-tracts.parquet still carries frac_inside_aoi
(each tract's share of area inside the region, EPSG:5070); it is 1.0 for every tract and is
kept so the invariant is visible in the data.GEOID) and the point layers (geometry becomes lon / lat columns, which is lossless for a
point and needs no geospatial library). Polygon and line layers, and the Overture layers with
nested columns (categories, names, sources, addresses), are parquet-only, a CSV of
those would either be enormous WKT or would quietly drop structure.<region>-coverage-gap.csv, Reliabl's scoring) publish every
component with a _defined flag. transport_gap, building_gap and poi_gap each have a
transport_defined / / true/false column beside them. A
component is undefined when the tract has no reference of that kind to compare against (no
named highway, no Microsoft footprint, no critical facility and no establishment); it is then
written as with . , so a with means "nothing to compare", not "fully
mapped", and the composite reproduces from the CSV in every row. Tracts with all three
undefined are dropped from the CSV and the sample submission.2026-08-19.0 (pinned; all Overture layers use it. The first
issue of this product was cut from 2026-06-17.0; Overture removes each release 60 days after
publication, so the 2026-08-26 re-issue moved every region to the current release).
The Overture attributes are shipped as released: every column and value is Overture's own,
and nothing was added, renamed, or trimmed. The one thing that changed is the bbox column,
which was regenerated by the repartition (the same values written in GeoParquet-spec covering
order, xmin, ymin, xmax, ymax, instead of Overture's native xmin, xmax, ymin, ymax) so
the extracts carry the same bbox convention as every other layer in this product.Strata vintages differ by source, deliberately. Each table carries its own vintage column, so this list is never the only record of it.
Tract vintage is 2020 throughout (as published in TIGER 2025), so every table joins to every
other on GEOID. Sources published on older tract geography were crosswalked, population-weighted.
No credentials, no signup. One line:
Two routes to the same bytes
Everything here is reachable directly from the bucket (
s3://us-west-2.opendata.source.coop/…) or through the Source Cooperative data proxy (https://data.source.coop/…). Both are public, no credentials either way. The proxy is S3-compatible, so it works withs3://clients too when you pass it as the endpoint. The snippets below use the bucket URI because it's the shortest form every library shown accepts. Support matrix at the end of this section.
The files are cloud-native, so you don't have to download them to query them. Pull a window out
of the 3 GB buildings layer in about two seconds. bbox= pushes the filter down to the row groups:
That returns 20,066 footprints out of 4.4M, without downloading the file.
Tabular layers (no geometry) are the same call with pandas:
Same call. The strata are national tract tables, so read the whole thing and filter on GEOID:
To map any of it, join to the tract polygons, which ship once:
Pull just the columns you need with columns=; at 232 columns that is the difference between
a few MB and the whole file:
Open every connection the same way. httpfs does the reading, spatial gives you the ST_*
functions, and the two SETs are what make s3:// work against this bucket:
s3_url_style='path' is required because the bucket name contains dots. Without it DuckDB puts the
bucket in the hostname, where Amazon's wildcard certificate can't cover it, and TLS fails.
The geometry column is already a GEOMETRY (DuckDB reads GeoParquet natively), so ST_* functions
take it directly. Don't wrap it in ST_GeomFromWKB().
Same bbox trick as above. Filter on bbox to prune row groups, then ST_Intersects to be exact
(the bbox prune is what makes this fast; ST_Intersects alone is roughly 6x slower):
Use all four comparisons. Filtering on
bbox.xmin/bbox.yminalone is a corner-in-box test, not an overlap test, and silently drops features that straddle the edge of your window.
Axis order. Every layer here is lon/lat (OGC:CRS84), as GeoParquet requires. DuckDB's
spatial extension follows the EPSG authority axis order when you name EPSG:4326, which is
lat/lon, so the two obvious ways to measure a road in metres both fail without an error:
ST_Transform(geometry, 'EPSG:4326', 'EPSG:5070') returns POINT (inf inf) for every feature.
Pass always_xy := true:
ST_Length_Spheroid(geometry) (and ST_Distance_Spheroid) returns NaN, because those
functions take lat/lon input. Flip first: ST_Length_Spheroid(ST_FlipCoordinates(geometry)).
Neither failure raises. sum() over NaN is NaN and inf propagates, so a whole run can
finish "successfully" with nothing usable in it. Test one segment whose length you know before
running anything over a layer. Verified on DuckDB 1.5.4 with the core spatial extension.
GEOID is text, not a number. Maricopa is state FIPS 04 (one tract is 35); an integer read drops the leading
zero and every join silently fails for that region. Read it as a string everywhere:
The parquet files already store GEOID as a string; the CSVs are where this bites.
DuckDB reads it straight from the URL too:
The
/vsicurl/prefix matters. On a barehttps://URL, GeoPandas probes the URL withurllibfirst to check for range support, the proxy rejects that User-Agent, and you get a 403 before GDAL ever sees it./vsicurl/hands the URL straight to GDAL, so plaingpd.read_file()works with no credentials and no environment variables.pyogrio.read_dataframe()on the bare URL works too, for the same reason.
Globbing is another reason to use s3://: it needs a LIST, which plain HTTPS cannot do.
The suggested way to work with this data is remotely, with the tooling above: every snippet in
this README reads straight from the bucket, and none of them needs a local copy. If you do need
the entire package on disk, use aws s3 sync rather than downloading files from the site one at
a time in the browser. It needs no account, resumes if the connection drops, and re-running it
only fetches what has changed, so a re-issued file is a one-line update instead of a fresh
download.
Sizes per region, reference/ only: Maricopa about 1.0 GB, Northern CA 0.45 GB, Eastern OK
0.9 GB, South Texas 3.9 GB. The strata tables (parquet + csv) add about 1.7 GB, and the boundaries file
is small.
Step by step
Install the aws CLI if you do not have it (aws --version tells you). Any one of these:
No aws configure step. The bucket is public and --no-sign-request below tells the CLI not
to look for credentials.
Open a terminal in the project folder you are using for the challenge. The files land in the
directory you run the command from (./), so cd there first.
Run the line for the region you want. Point the CLI at the bucket directly, no --endpoint-url.
Or everything at once, into a folder tree that mirrors the bucket:
One layer across all regions also works, because the self-describing names make --include
match at any depth:
Check the byte counts, not just the file names. A parallel download can exit cleanly and still leave truncated files behind (one tester ended up with five short files, including a 5.6 MB copy of a 299.5 MB buildings layer, and nothing reported an error). Compare local sizes to the bucket listing:
Any file that is smaller locally is incomplete. Re-running the same aws s3 sync line fixes
it: sync compares size and timestamp and re-fetches only the files that differ.
Zip archives. Two archives are also on the bucket for anyone who cannot install the CLI,
under bulk-downloads/ (posted 2026-08-27, after the re-issued data above): reference.zip (all four regions of reference/, 6.39 GB) and
strata.zip (all of strata/, 1.68 GB). Each has this README at the top level.
Browser downloads of multi-GB files do not resume, so if one fails partway the archive is
corrupt and has to be fetched again: check the byte count against the size shown in the file
browser before unzipping. Prefer aws s3 sync where you can.
Three ways to address the same bytes. The snippets in this README use the first, because it's the shortest form every client accepts.
The proxy speaks the S3 API, so it is not HTTPS-only: point any S3 client at
https://data.source.coop as its endpoint and the org name (humane-intelligence) becomes the
bucket. It's also the only way to compare the two routes apples-to-apples, since it holds the
client stack fixed and changes only the server.
anon=True is required. Without it fsspec looks for credentials it doesn't need and raises
NoCredentialsError. The pyarrow spelling is the same idea:
DuckDB gets there with SET s3_endpoint='data.source.coop'; (keep s3_url_style='path'), and the
aws CLI with --endpoint-url https://data.source.coop --no-sign-request.
Note it's the endpoint, not the path. Writing s3://data.source.coop/… as a plain URI won't
work: the client resolves data.source.coop as a bucket name on real AWS, so the request never
reaches the proxy at all.
The https:// URI as a path doesn't work in Python either. gpd.read_parquet("https://...")
raises ArrowInvalid: Unrecognized filesystem type in URI (pyarrow has no https driver);
pd.read_parquet("https://...") and gpd.read_file("https://...") return 403, because those
paths probe the URL with Python's default urllib User-Agent and the proxy rejects it. Neither is
anything you did wrong: use one of the two s3:// forms above for parquet, and the /vsicurl/
prefix (or pyogrio.read_dataframe()) for the GeoJSON.
Every cell in that table is checked by scripts/readme_addresses.py
if you want to re-run it on your own machine (uv run scripts/readme_addresses.py, no credentials
needed).
The Overture layers do not have flat attributes, and this is the first thing that trips people
up. names and categories are structs; sources is a list of structs.
In DuckDB, reach into structs with dot access. names.common is a MAP, so it takes a key, not an
index:
sources is a list, so index it (sources[1], 1-based) or unnest it. Unnesting tells you which
upstream dataset actually supplied each feature, which is close to the heart of this challenge: a
region built mostly from ML-derived footprints is a different coverage story from one built on
OpenStreetMap.
confidence is sparse: only some upstream datasets populate it (Microsoft ML on a minority of
its rows, Google Open Buildings on all of theirs, OpenStreetMap never). Treat NULL as "not
reported", not as "low confidence".
In GeoPandas the same structs arrive as plain dicts, and lists of structs as arrays of dicts.
The .str accessor indexes both, despite the name, and it chains:
With pandas you can ask for Arrow-backed columns instead and get real typed accessors
(dtype_backend is a pandas argument; gpd.read_parquet does not accept it):
Clicking any .parquet file in the file browser opens a table preview of that file. It works on
one file at a time (it range-reads row groups, so even multi-GB files preview fine) and does
not overlay layers or draw a map.
buildings / roads / rail layers: ODbL; places and base, so pois / infrastructure:
CDLA Permissive 2.0). Attribute © Overture Maps Foundation and its sources (incl.
OpenStreetMap contributors).| Overture | pois | points | Places of interest (theme=places), full categories taxonomy retained. |
| Microsoft | buildings | polygons | Microsoft GlobalML US Building Footprints (Feb 2026 refresh), the reference baseline for the building coverage gap. |
| Census | acs-housing | tract polygons | ACS 5-Year table B25001 total housing units per tract, joined to TIGER tract geometry. |
| Census | tiger-roads | lines | TIGER/Line roads (reference baseline for the road gap). The road gap compares named-highway classes only: TIGER S1100 + S1200 (primary and secondary roads) against Overture motorway / trunk / primary / secondary. Those class definitions differ between the two sources, so the road component measures Overture's coverage of the highway network, and its values are not comparable across regions (a rural region with few highways scores differently from a metro one for reasons that have nothing to do with mapping effort). Tracts with no TIGER highway at all have no road component (transport_defined = false): 253 of 1,192 in eastern-ok, 869 of 1,593 in maricopa-az, 218 of 591 in northern-ca, 1,704 of 6,003 in south-central-tx (denominators are the scored tract lists). The all-roads comparison is available via roads-unfiltered (the difference is mostly Overture service roads: driveways, parking aisles, alleys). |
| Census | cbp | tract polygons | County Business Patterns establishment counts, apportioned ZIP→tract via the HUD USPS crosswalk. Ships both weightings: cbp_estab_bus (business-address share; also the default cbp_estab) and cbp_estab_res (residential share). |
| HIFLD | hospitals / fire-stations / ems-stations / schools | points | Emergency facilities, four separate layers. Sourced from the USGS National Map "structures" service (the maintained successor to HIFLD Open); ems-stations is USGS "Ambulance Services". |
building_definedpoi_defined0_defined = falsecoverage_gap_score is the mean of the defined
components only0_defined = falsepoi_gap is per facility type. Its HIFLD half matches Overture places to each HIFLD layer
on categories.primary: fire stations = fire_department; EMS = ambulance_and_ems_services;
schools = elementary_school, middle_school, high_school, school, private_school,
public_school. For each type, 1 - min(1, overture / hifld) per tract, undefined where the
tract has no HIFLD facility of that type; poi_gap_hifld is the mean over the defined types.
Hospitals are excluded: Overture's hospital category is about 12x HIFLD's hospital count
everywhere, so that term never binds. EMS is close to 1:1 and rarely binds either; fire
stations carry the component. The CBP half (all Overture places against CBP establishments)
is unchanged, and poi_gap is the mean of the two halves. The per-type values ship as
poi_gap_fire, poi_gap_ems, poi_gap_schools, poi_gap_cbp, each with its own
poi_defined_* flag.strata/national/national-census-tracts.parquet; join any strata table to it on GEOID to map
it. At region scale the same columns ride on <region>-census-tracts.parquet directly.| CDC WONDER heat-wave days |
| 1981-2010 |
| NOAA GHCN |
| 2015-2023 |