block by mbostock 2522624ada2c1f9e0fafb75cca09442b

U.S. Population Density

Full Screen

Source: American Community Survey, 2014 5-Year Estimate

index.html

<!DOCTYPE html>
<img src="topo.svg" width="960" height="680">

legend.svg

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="960" height="600" viewBox="0 0 960 600" fill="none">
  <g transform="translate(540,640)" font-size="10" font-family="sans-serif" text-anchor="middle">
    <rect height="8" x="0" width="6" fill="#fff7ec"></rect>
    <rect height="8" x="6" width="13" fill="#fee8c8"></rect>
    <rect height="8" x="19" width="23" fill="#fdd49e"></rect>
    <rect height="8" x="42" width="42" fill="#fdbb84"></rect>
    <rect height="8" x="84" width="49" fill="#fc8d59"></rect>
    <rect height="8" x="133" width="56" fill="#ef6548"></rect>
    <rect height="8" x="189" width="78" fill="#d7301f"></rect>
    <rect height="8" x="267" width="110" fill="#b30000"></rect>
    <rect height="8" x="377" width="23" fill="#7f0000"></rect>
    <text x="0" y="-6" fill="#000" text-anchor="start" font-weight="bold">Population per square mile</text>
    <g transform="translate(6,0)">
      <line stroke="#000" y2="13" x1="0.5" x2="0.5"></line>
      <text fill="#000" y="16" x="0.5" dy="0.71em">1</text>
    </g>
    <g transform="translate(19,0)">
      <line stroke="#000" y2="13" x1="0.5" x2="0.5"></line>
      <text fill="#000" y="16" x="0.5" dy="0.71em">10</text>
    </g>
    <g transform="translate(42,0)">
      <line stroke="#000" y2="13" x1="0.5" x2="0.5"></line>
      <text fill="#000" y="16" x="0.5" dy="0.71em">50</text>
    </g>
    <g transform="translate(84,0)">
      <line stroke="#000" y2="13" x1="0.5" x2="0.5"></line>
      <text fill="#000" y="16" x="0.5" dy="0.71em">200</text>
    </g>
    <g transform="translate(133,0)">
      <line stroke="#000" y2="13" x1="0.5" x2="0.5"></line>
      <text fill="#000" y="16" x="0.5" dy="0.71em">500</text>
    </g>
    <g transform="translate(189,0)">
      <line stroke="#000" y2="13" x1="0.5" x2="0.5"></line>
      <text fill="#000" y="16" x="0.5" dy="0.71em">1,000</text>
    </g>
    <g transform="translate(267,0)">
      <line stroke="#000" y2="13" x1="0.5" x2="0.5"></line>
      <text fill="#000" y="16" x="0.5" dy="0.71em">2,000</text>
    </g>
    <g transform="translate(377,0)">
      <line stroke="#000" y2="13" x1="0.5" x2="0.5"></line>
      <text fill="#000" y="16" x="0.5" dy="0.71em">4,000</text>
    </g>
  </g>
</svg>

package.json

{
  "private": true,
  "license": "gpl-3.0",
  "author": {
    "name": "Mike Bostock",
    "url": "https://bost.ocks.org/mike"
  },
  "scripts": {
    "prepublish": "bash prepublish"
  },
  "devDependencies": {
    "d3-scale": "^1.0.4",
    "d3-scale-chromatic": "^1.1.0",
    "d3-geo-projection": "^1.2.1",
    "ndjson-cli": "^0.3.0",
    "shapefile": "^0.5.9",
    "topojson-server": "^2.0.0",
    "topojson-client": "^2.1.0",
    "topojson-simplify": "^2.0.0"
  }
}

prepublish

#!/bin/bash

# U.S. Albers
PROJECTION='d3.geoAlbersUsa().scale(1280).translate([480, 300])'

# The state FIPS codes.
STATES="01 02 04 05 06 08 09 10 11 12 13 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 44 45 46 47 48 49 50 51 53 54 55 56"

# The ACS 5-Year Estimate vintage.
YEAR=2014

# The display size.
WIDTH=960
HEIGHT=680

# Download the census tract boundaries.
# Extract the shapefile (.shp) and dBASE (.dbf).
# Download the census tract population estimates.
for STATE in ${STATES}; do
  if [ ! -f cb_${YEAR}_${STATE}_tract_500k.shp ]; then
    curl -o cb_${YEAR}_${STATE}_tract_500k.zip \
      "http://www2.census.gov/geo/tiger/GENZ${YEAR}/shp/cb_${YEAR}_${STATE}_tract_500k.zip"
    unzip -o \
      cb_${YEAR}_${STATE}_tract_500k.zip \
      cb_${YEAR}_${STATE}_tract_500k.shp \
      cb_${YEAR}_${STATE}_tract_500k.dbf
  fi
  if [ ! -f cb_${YEAR}_${STATE}_tract_B01003.json ]; then
    curl -o cb_${YEAR}_${STATE}_tract_B01003.json \
      "http://api.census.gov/data/${YEAR}/acs5?get=B01003_001E&for=tract:*&in=state:${STATE}&key=${CENSUS_KEY}"
  fi
done

# Construct TopoJSON.
if [ ! -f topo.json ]; then
  geo2topo -n \
    tracts=<(for STATE in ${STATES}; do \
        ndjson-join 'd.id' \
          <(shp2json -n cb_${YEAR}_${STATE}_tract_500k.shp \
            | geoproject -n "${PROJECTION}" \
            | ndjson-map 'd.id = d.properties.GEOID, d') \
          <(ndjson-cat cb_${YEAR}_${STATE}_tract_B01003.json \
            | ndjson-split 'd.slice(1)' \
            | ndjson-map '{id: d[1] + d[2] + d[3], B01003: +d[0]}') \
          | ndjson-map -r d3=d3-array 'd[0].properties = {density: d3.bisect([1, 10, 50, 200, 500, 1000, 2000, 4000], (d[1].B01003 / d[0].properties.ALAND || 0) * 2589975.2356)}, d[0]'; \
      done) \
    | topomerge -k 'd.id.slice(0, 5)' counties=tracts \
    | topomerge -k 'd.id.slice(0, 2)' states=counties \
    | topomerge --mesh -f 'a !== b' counties=counties \
    | topomerge --mesh -f 'a !== b' states=states \
    | topomerge -k 'd.properties.density' tracts=tracts \
    | toposimplify -p 1 -f \
    | topoquantize 1e5 \
    > topo.json
fi

# Convert to SVG (while dropping the last line).
cat \
  <(topo2geo -n < topo.json tracts=- \
    | ndjson-map -r d3=d3-scale-chromatic '(d.properties.title = d.id, d.properties.fill = d3.schemeOrRd[9][d.id], d)') \
  <(topo2geo -n < topo.json counties=- \
    | ndjson-map '(d.properties.stroke = "black", d.properties.strokeWidth = 0.5, d.properties.strokeOpacity = 0.3, d)') \
  <(topo2geo -n < topo.json states=- \
    | ndjson-map '(d.properties.stroke = "black", d.properties.strokeOpacity = 0.3, d)') \
  | geo2svg --stroke=none -n -p 1 -w ${WIDTH} -h ${HEIGHT} \
  | sed '$d' \
  > topo.svg

# Insert the legend.
tail -n +4 \
  < legend.svg \
  >> topo.svg