Methodology & sources
Last updated: 2026-05-04
This map compares two ways of measuring density in New York City:
- Residential density — how many people live in a place, per acre. Computed at the 2020 Census block level (the smallest geography the Census Bureau publishes population for).
- Built environment — the physical mass of buildings, by roof height. Each polygon is one building footprint; its 3D height is the measured roof height in feet.
Tall buildings are not the same as crowded neighborhoods. Midtown towers are full of office workers during the day, but at night they are nearly empty. Brownstone Brooklyn looks short and quiet from a satellite, but plenty of people sleep there.
Residential layer
Geographies
NYC Department of City Planning, 2020 Census Blocks (shoreline-clipped), dataset wmsu-5muw on NYC Open Data. 37,588 blocks across the five boroughs.
Source: data.cityofnewyork.us/City-Government/2020-Census-Blocks/wmsu-5muw
Population counts
U.S. Census Bureau, 2020 Decennial Census, P.L. 94-171 redistricting file, Table P1 (total population), joined to the blocks on the 15-digit GEOID20.
API endpoint used:
https://api.census.gov/data/2020/dec/pl?get=P1_001N,GEO_ID&for=block:*&in=state:36+county:005,047,061,081,085
Density calculation
Density is computed as persons_per_acre = total_population / land_area_acres. Land area comes from the shape_area field on each block, which is in square feet (NY State Plane Long Island foot units). One acre = 43,560 ft².
Filters
- Blocks with zero population are excluded — these are mostly parks, rail yards, water, industrial sites and cemeteries. Including them as flat polygons would clutter the map without adding information. 6,896 blocks dropped (~18%).
- Blocks smaller than 0.1 acres are excluded — these are typically measurement-noise polygons (single-lot remnants left by the shoreline-clipping process) where dividing population by tiny area produces unreliable extreme values. 3 blocks dropped.
- 30,689 populated blocks are shown.
Height multiplier
Persons-per-acre values are too small to read in 3D without amplification — a block with 100 persons/acre would be a polygon 100 feet tall, invisible against towers in the same view. The height multiplier control on the map (default ×8) scales the extruded height so blocks read as visual mass, not literal feet. The multiplier is exposed as a control because it's an arbitrary visual choice, not a measurement. Color encodes the underlying density value; height is for readability.
Color ramp (residential)
| Persons/acre | Color |
|---|---|
| 0 | #fde725 yellow |
| 50 | #5ec962 green |
| 150 | #21918c teal |
| 300 | #3b528b blue |
| 600 | #440154 purple |
Linear interpolation between breakpoints. Viridis ramp, color-blind safe.
Built environment layer
Source
NYC Office of Technology and Innovation, Building Footprints, dataset 5zhs-2jue on NYC Open Data. Only buildings with a recorded roof height (height_roof > 0) are kept: 1,082,139 footprints. Each footprint is extruded to its roof height in feet, with no multiplier.
How it's loaded
The footprints are drawn as a MapLibre GL fill-extrusion layer on the same camera used for the residential layer. Both layers load when the page opens, and the toggle only swaps which one is visible. Toggling between views does not change the camera, so you can compare the same vantage point.
Tile pipeline
Data was tiled with tippecanoe into PMTiles archives, served as static files. The browser reads only the byte ranges for tiles in view, so neither the 3.6 MB residential file nor the 69 MB buildings file is downloaded in full.
Limitations
- Daytime population is not shown. The residential layer reflects nighttime/where-people-sleep population. Midtown's daytime population is roughly ten times its residential population. A daytime layer is on the to-do list (LEHD LODES workplace data).
- Block-level population is averaged. A single Census block may include both a 30-story apartment building and a vacant lot — the density value averages across the block.
- Roof height is not floor count. A 200-ft warehouse and a 200-ft 20-story apartment building look the same in the Built view. Floor counts and residential unit counts (from MapPLUTO) could be added later.
- Building footprints are the city's best LiDAR-derived snapshot, not real-time. Some recent demolitions or new construction may not be reflected.
- The basemap is © CARTO © OpenStreetMap contributors, served via raster tiles.
Reproducing
The full pipeline is two Python scripts and two tippecanoe commands:
python3 scripts/build_population.py
python3 scripts/build_buildings.py
tippecanoe -zg --drop-densest-as-needed -l blocks -o data/pop_blocks.pmtiles data/blocks_pop.ndjson
tippecanoe -zg --no-feature-limit --no-tile-size-limit --simplification=8 -l buildings -o data/buildings.pmtiles data/buildings.ndjson