← Back to map

Methodology & sources

How this map was built, what every variable means, and what its limits are.

Data sources

Geography

All five New York City boroughs at the 2020 census tract level — 2,325 tracts in total. (The ACS file carries 2,327; two have no polygon in DCP's shoreline-clipped set and are dropped.) A tract is a small statistical area that typically contains 1,200–8,000 people. Tract boundaries are stable enough to compare across years but small enough to surface meaningful neighborhood-scale differences.

The "Borough" and "NTA" (Neighborhood Tabulation Area) labels in the detail panel come from NYC DCP's official 2020 designations. Tracts that fall in parks, cemeteries, airports, or industrial areas may show small or zero population.

Neighborhoods (NTAs)

The default view aggregates tracts into NYC DCP's 262 Neighborhood Tabulation Areas: 197 residential NTAs plus 65 that DCP classifies as parks, cemeteries, airports, industrial or correctional areas. Each tract belongs to exactly one NTA.

Change, October 2026: earlier versions of this map averaged the tract medians, weighted by households or units. That approximation was off by a median of about $1,900 on NTA household income and by as much as $28,000 (Old Astoria-Hallets Point showed $112,417; City Planning's figure is $84,443). The worst rent gap was $413 (Midtown-Times Square) and the worst home-value gap $302,000 (Hunts Point showed $635,400; City Planning has $333,332). Tribeca showed $229,813, a figure the brackets cannot support; its median is above $200,000 and can't be pinned down further. The non-residential NTAs were also included in the color scales. Both are fixed.

How values are calculated

Every variable in the map either comes directly from an ACS estimate (medians and totals) or is computed as a share, using the denominator the Census Bureau publishes alongside that table. For example:

Full variable list

FieldSource table / formula
Total populationB01003_001
Population densityB01003_001 ÷ tract land area (sq mi)
Median ageB01002_001
Share under 18Σ B01001 male+female under-18 cells ÷ B01003_001
Share 65 and overΣ B01001 male+female 65+ cells ÷ B01003_001
White, Black, Asian (non-Hispanic), HispanicB03002_003 / 004 / 006 / 012 ÷ B03002_001
Median household incomeB19013_001 (tracts); interpolated from B19001 (NTAs)
Household income bandsSums of B19001 cells ÷ B19001_001
Poverty rateB17001_002 ÷ B17001_001
Receiving SNAPB22010_002 ÷ B22010_001
Households / avg household sizeB11016_001 / B25010_001
Owner-occupied homesB25003_002 ÷ B25003_001
Median gross rent / home valueB25064_001 / B25077_001 (tracts); interpolated from B25063 / B25075 (NTAs)
Median rent burdenB25071_001, median gross rent as % of household income (tracts); interpolated from B25070 (NTAs)
Bachelor's+ / HS onlyΣ B15003_022–025 / Σ B15003_017–018 ÷ B15003_001
Foreign-bornB05002_013 ÷ B05002_001
Not a U.S. citizenB05002_021 ÷ B05002_001
Non-English at home(C16001_001 − C16001_002) ÷ C16001_001
In labor force (16+)B23025_002 ÷ B23025_001
Commute mode sharesB08301_010 / 019 / 021 ÷ B08301_001
Veterans (18+)B21001_002 ÷ B21001_001
Unemployment rateB23025_005 ÷ B23025_003 (BLS-standard: unemployed ÷ civilian labor force, not ÷ total labor force)
No home internetB28002_013 ÷ B28002_001 (no subscription and no other internet access at the residence; households with free access but no subscription are in B28002_012 and are not counted here)
Households with no vehicle / 2+ vehiclesB08201_002 / Σ B08201_004-006 ÷ B08201_001
Average vehicles per householdΣ (bucket midpoint × bucket count) ÷ B08201_001 (4+ bucket treated as 4.5)
Homeowners / renters without a vehicleB25044_003 ÷ B25044_002 / B25044_010 ÷ B25044_009
K-12 students in public / private school (by residence)Σ B14002 K-12 public (or private) male + female cells ÷ total K-12 students. Tracks where the students live.
Public-school K-12 enrolled (by school location)Σ DOE Demographic Snapshot enrollment by school (latest year), aggregated to the tract containing each school's address. Tracks where the schools are.
Major-felony rate(Σ NYPD complaints with KY_CD ∈ {101, 104, 105, 106, 107, 109, 110}) ÷ population × 1,000
Violent-crime rate(Σ NYPD complaints with KY_CD ∈ {101, 104, 105, 106}) ÷ population × 1,000
Property-crime rate(Σ NYPD complaints with KY_CD ∈ {107, 109, 110}) ÷ population × 1,000

Election details

Vote shares are reported as the candidate's share of major-candidate votes — not of all ballots cast. For the presidential races and the 2021 mayoral race, this means D ÷ (D + R), so the values are directly comparable across years even when third-party candidates differ. For 2025 mayoral, the denominator is Mamdani + Cuomo + Sliwa (the three major candidates); minor candidates are not counted in the denominator.

Each candidate's vote total includes all of their ballot lines, because cross-endorsed lines are votes for the same person. Biden 2020 and Harris 2024: Democratic + Working Families. Trump 2020 and 2024: Republican + Conservative. Adams 2021: Democratic. Sliwa 2021: Republican + Independent (the Conservative line that year went to Bill Pepitone, who is not counted). Mamdani 2025: Democratic + Working Families. Cuomo 2025: Fight and Deliver. Sliwa 2025: Republican + Protect Animals.

NYC redrew Election District boundaries after the 2020 redistricting cycle, so 2020/2021 results use the pre-redistricting ED geometry (5,697 EDs with polygons) and 2024/2025 results use the post-redistricting geometry (4,069 EDs). Both are aggregated to the same 2020 census tract boundaries. Because EDs are typically smaller than tracts (about 2.5 EDs per tract for 2020–21 and 1.75 for 2024–25), the centroid-based join is reliable.

Votes cast in EDs that have no polygon in the archive, or whose centroid falls outside every tract, are dropped. Against the certified citywide totals, the tract sums capture 99.9% of major-candidate votes for the 2020 presidential and 2021 mayoral races, 99.3% for the 2025 mayoral race and 98.7% for the 2024 presidential race; the 2024 gap is EDs in the Board of Elections file that are missing from the post-redistricting polygon set.

Tracts with fewer than 25 total major-candidate votes for a given election are suppressed (shown as "no data") for that election, because vote shares from tiny samples are noisy.

Rent-stabilized units — how the unit count is derived

NYC's official rent-stabilization registry, maintained by the state's Division of Housing and Community Renewal (DHCR), does not publish unit counts per building. The annual Rent Guidelines Board lists released by NYC RGB are PDFs of building addresses only — no unit data.

The numbers on this map come from a workaround that exploits NYC's tax system. The Department of Finance charges every rent-stabilized building an annual per-unit "Rent Stabilization Fee" on its property tax bill ($20 per unit since July 1, 2019; $10 before that). The fee line item appears on the property's annual DOF Statement of Account PDF. Divide that fee by the per-unit rate and you've reverse-engineered the registered unit count for that building. The JustFix.nyc team's nyc-doffer project scrapes every NYC tax lot's Statement of Account PDFs annually, extracts the fee, and publishes per-BBL unit counts back to 2018. That's what's aggregated to tracts here.

What the unit counts actually mean and don't mean:

Crime rate details

NYPD's "seven major felonies" (sometimes called Index 7) are the historical FBI Part I categories the department reports for CompStat. We split them into the two standard buckets:

Each complaint is filed to the date the incident was reported to police (RPT_DT), not the date it allegedly occurred — that's the field NYPD uses for its own performance reporting, and the only one that's reliably populated.

Station houses. NYPD places complaints it cannot geocode, and nearly every rape complaint (to protect victims), at the station house of the precinct where they happened: in the first half of 2026, 1,003 of 1,065 rape complaints sat within 130 meters of their precinct's station house. These complaints have no known street location, so the map leaves them out: any complaint within 140 meters of its own precinct's station house is not counted (station addresses from each precinct's NYPD page, geocoded with NYC Planning's GeoSearch, plus the 40th Precinct's former building at 257 Alexander Avenue, where NYPD still places its records). That is 4,408 of the 118,463 complaints in the July 2025–June 2026 window, 3,075 of them violent, so in practice the violent-crime rate counts very few rapes. No complaint is assigned to a place by its precinct alone. Left in place, they would pile into the one tract holding the station house (some carried as many as 95 extra violent felonies a year). The 140-meter radius comes from 2024 arrests: in 75 of 76 precincts, the largest stack of arrests spanning many offense types sits within 140 meters of the geocoded station house.

Records on a boundary. NYPD places each complaint at an intersection or the middle of a street segment, and most tract and neighborhood boundaries run down street centerlines. A complaint within 10 meters of a tract boundary is shared equally among the tracts that meet there (44,518 of the 114,055 street-located complaints), so counts can be fractional.

Complaints are placed on the tract map by point-in-polygon on the NYPD-reported latitude/longitude. The denominator is total population from the same ACS table used elsewhere on this page (B01003_001), so the rate is per 1,000 residents, not per 1,000 daytime population or per 1,000 visitors. Tracts with fewer than 200 residents (103 tracts: parks, cemeteries, airports, transit yards, industrial areas) are shown as "no data" on the rate maps because the denominator is too small to be meaningful — a single felony in a 12-person tract would produce an 83-per-1,000 rate. Tracts inside NTAs that DCP classifies as non-residential (65 of the 262) also get no rate. Tracts and NTAs whose rate exceeds 100 per 1,000 residents keep their rate but carry a daytime-population caveat in the detail panel, since such rates almost always reflect crimes against commuters and visitors.

The "rolling 12 months" window spans the most recent 365 days for which combined data are available. Because the Historic dataset is updated quarterly and the YTD dataset daily, this can shift forward each time the build script is re-run.

Margins of error and reliability

ACS is a sample, not a count. Every cell estimate comes with a margin of error (MOE) at 90% confidence. For tracts with small populations or small subgroups, the MOE can be a substantial fraction of the estimate itself — sometimes larger than the estimate. We surface this in three places:

MOEs for derived shares are propagated using the Census Bureau's standard formulas from the ACS General Handbook (chapter 8, "Calculating Measures of Error for Derived Estimates"): moe(p) = √[moe(x)² − p² · moe(y)²] / y for proportions where the numerator is a subset of the denominator (with a fall-back to the independent-ratio formula when the radicand is negative). Sum-of-cells MOEs use √Σmoe². Tract medians use the published MOE directly; interpolated NTA medians carry no ±.

The undocumented-population proxy

The U.S. Census Bureau does not ask about immigration status, so there is no direct tract-level count of undocumented residents. Every published "undocumented by tract" figure is a model output, not a measurement. The closest publicly available variable that gets at this population without modeling assumptions is B05002_021 — "Foreign-born, not a U.S. citizen." We surface it as "Not a U.S. citizen."

This variable over-counts the undocumented population because it also includes:

Calibrating it to undocumented requires a multiplier. Nationally, Pew Research Center estimates 14 million unauthorized immigrants in 2023, 27% of the foreign-born population. For New York City, the Center for Migration Studies estimates 535,000 undocumented residents in 2023, 15% of the city's 3.1 million foreign-born and roughly two-fifths of its non-citizens (CMS counts 820,400 legal non-citizens alongside the 535,000 undocumented). The share varies by country of origin: CMS finds Mexico is the largest source of undocumented New Yorkers, China second and the Dominican Republic fourth, so the multiplier runs higher where those groups concentrate and lower where non-citizens are mostly green-card holders or visa holders. A tract with 1,000 "Not a U.S. citizen" residents probably contains something like 400 undocumented residents, with wide neighborhood-level variation.

This map does not multiply by that factor — we show the raw proxy and ask the reader to understand it as such. CMS publishes more authoritative estimates at sub-city geographies (Community District level); when this map grows a Community District aggregation, those will be layered in directly.

What is not yet here

Color scales

The map offers two binning options for every variable:

Each thematic group uses a different single-hue palette to make the active variable immediately recognizable.

Two variables. Each variable is split into thirds (low, middle, high) across the areas that have both values, and the 3×3 palette colors each area by its pair of thirds. The legend labels the two cut points on each axis and lists how many areas fall in each third; ties can make the thirds uneven. The correlation shown is Pearson's r across the same areas, each counted once regardless of population. The preset explanations were checked against the neighborhood data; the places they name sit in the cells described at the neighborhood level, and the direction of each relationship holds at the tract level, where most are weaker.

Summary statistics. The lowest, middle, average and highest values in the sidebar describe the areas on the map, each counted once. They are not citywide figures: the average of 197 neighborhood poverty rates is not the city's poverty rate.

Known limits

The American Community Survey is a sample, not a census. At the tract level — especially for small subgroups in low-population tracts — margins of error can be large. Treat single-tract values as estimates with uncertainty, not as exact counts.

Reproducing this map

The Python build script (build.py) fetches all ACS variables from Census Reporter (caching the raw responses in cache/; pass --refresh to re-download), joins them to NYC DCP tract geometry, computes the derived shares, aggregates tracts to NTAs and writes tracts.geojson, ntas.geojson and variables.json into the docs/ folder. The page is plain HTML/JS — Leaflet for the map, d3 for color scales, no build step. Source is available on GitHub.

← Back to map