← groundworkmethodology

Methodology

groundwork is a viewer for public housing data. Every number on the map and in the panels comes from an open dataset or a hand-written loader script that anyone can run against the same source. This page documents where everything comes from and where it gets fuzzy.

Projects per city

One loader per city under scripts/in the repo. Each pulls from that city's open-data API, maps the local schema onto a shared projects table, and writes it to Postgres. Re-runnable, idempotent on (city_id, external_id).

Rent-burden choropleth + supply-demand gap

Census tract polygons come from the U.S. Census Bureau's TIGERweb service. Population, median income, renter household counts, and rent-burden counts come from the ACS 5-year (2022) via the Census API.

The supply-demand gap is a PostGIS spatial join. For every tract, we count rent-burdened households (ACS) against the total affordable units in any project within 1 km of the tract centroid. The number reported is burdened_households / nearby_affordable_units — higher = worse-served. We exclude tracts with fewer than 100 renter households to keep the ratio meaningful.

"Rent-burdened" here is the ACS standard: a household paying 30% or more of household income on gross rent. "Severely rent-burdened" is the 50%+ subset, which we collect but don't currently surface in the gap ranking.

Stakeholders panel

Council district and community board, where available, come from the city's own dataset. The elected representative for each district is scraped by scripts/load-council.mjs, which pulls from either the city's official roster page or Wikipedia depending on what's reachable and parseable.

This is the most fragile data on the page. NYC carries council district on the project record itself, so the surface area for error is small. Other cities don't, and we don't do a point-in-polygon back-fill yet, so the rep shown can be missing or stale. Treat it as a starting point, not an audit.

Production trends (units per year by income tier)

We compute the "year" of each project as COALESCE(start_date, completion_date), whichever the city's feed provides. Income tier columns (Extremely Low → Middle Income → Other) come straight from each project record where available, summed within each year.

Income tiers are not strictly comparable across cities. Each city defines "Extremely Low" against its own AMI, which floats year to year and HUD region to HUD region. Cross-city comparison is directional, not exact. Chicago's feed has neither a start nor a completion date for its projects, so its trends panel is empty.

Production vs published target

For cities with a real, public housing-production commitment, we chart cumulative units delivered each year against a linear trajectory to the stated goal. The targets come from the agency documents linked below.

"Pace" is the ratio of (units delivered as of the latest data year) to (units the linear trajectory would expect by that year). It is a rough on-track signal, not an audit — cities front-load or back-load production for political and financing reasons that this chart can't see.

  • Housing New York 2.0 · 300,000 units by 2026
    Expanded in November 2017 from the original 200,000-unit goal. Counts both newly constructed and preserved units financed by HPD. HPD reports their own running total; the chart here is computed independently from the public HPD dataset and may differ slightly from HPD's official accounting.
  • Housing Element 6th Cycle — affordable · 46,598 units by 2031
    State-mandated affordable RHNA allocation for the 8-year Housing Element period 2023-2031. Affordable here means very-low, low, and moderate income (≤120% AMI). Total RHNA including market-rate is 82,069.
  • Housing Element 6th Cycle — affordable · 184,721 units by 2029
    State-mandated affordable RHNA allocation for the 6th Cycle Housing Element. Includes very-low, low, and moderate income (≤120% AMI). Total RHNA including market-rate is 456,643. Open-data coverage of completions is partial — the chart is a lower bound, not an audit.
  • Housing Framework for Equity and Growth · 12,000 units by 2025
    Affordable subset of the 36,000-unit overall housing goal announced by Mayor Bowser in 2019. 'Affordable' here is units at or below 80% MFI.

Where the math breaks down

  • Definitions drift."Affordable" is not one thing. It includes units priced for ELI to middle income, all the way to 165% AMI in NYC's case. The chart legend reflects this; the headline numbers ("X units delivered") don't.
  • Dataset lag.Each city refreshes on its own cadence — daily for NYC, monthly for some, sporadic for others. The fetchedAt timestamp on each city's data is shown in the sidebar.
  • Open data is not all data.Federally financed LIHTC projects don't all appear in city pipelines. Where a city's open dataset misses projects, we miss them too.
  • Geocoding quirks.A handful of project lat/lngs are clearly wrong (literal middle-of-the-ocean coordinates from upstream geocoder errors). We don't silently drop them; we just render them where the data says.

Source code

All of it is at github.com/c-tonneslan/groundwork. Every loader, every SQL query, every chart. If you spot something wrong or have a city target source we should add, open an issue.

MIT-licensed. Cite as: Tonneslan, C. (2026). groundwork. github.com/c-tonneslan/groundwork.