This variation of my California population density map uses geo2svg to generate a static choropleth from the command line!
Last active
March 8, 2024 10:40
-
-
Save mbostock/fb6c1e5ff700f9713a9dc2f0fd392c35 to your computer and use it in GitHub Desktop.
geo2svg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: gpl-3.0 | |
height: 1100 | |
border: no |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.DS_Store | |
node_modules | |
cb_* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<img src="topo.svg" width="960" height="1100"> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"private": true, | |
"license": "gpl-3.0", | |
"author": { | |
"name": "Mike Bostock", | |
"url": "https://bost.ocks.org/mike" | |
}, | |
"scripts": { | |
"prepublish": "bash prepublish" | |
}, | |
"devDependencies": { | |
"d3-array": "^1.0.1", | |
"d3-geo-projection": "^1.2.1", | |
"d3-scale-chromatic": "^1.1.0", | |
"ndjson-cli": "^0.3.0", | |
"shapefile": "^0.5.8", | |
"topojson": "^2.0.0", | |
"topojson-client": "^2.1.0", | |
"topojson-simplify": "^2.0.0" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# EPSG:3310 California Albers | |
PROJECTION='d3.geoAlbers().parallels([34, 40.5]).rotate([120, 0])' | |
# The state FIPS code. | |
STATE=06 | |
# The ACS 5-Year Estimate vintage. | |
YEAR=2014 | |
# The display size. | |
WIDTH=960 | |
HEIGHT=1100 | |
# Download the census block group boundaries. | |
# Extract the shapefile (.shp) and dBASE (.dbf). | |
if [ ! -f cb_${YEAR}_${STATE}_bg_500k.shp ]; then | |
curl -o cb_${YEAR}_${STATE}_bg_500k.zip \ | |
"http://www2.census.gov/geo/tiger/GENZ${YEAR}/shp/cb_${YEAR}_${STATE}_bg_500k.zip" | |
unzip -o \ | |
cb_${YEAR}_${STATE}_bg_500k.zip \ | |
cb_${YEAR}_${STATE}_bg_500k.shp \ | |
cb_${YEAR}_${STATE}_bg_500k.dbf | |
fi | |
# Download the list of counties. | |
if [ ! -f cb_${YEAR}_${STATE}_counties.json ]; then | |
curl -o cb_${YEAR}_${STATE}_counties.json \ | |
"http://api.census.gov/data/${YEAR}/acs5?get=NAME&for=county:*&in=state:${STATE}&key=${CENSUS_KEY}" | |
fi | |
# Download the census block group population estimates for each county. | |
if [ ! -f cb_${YEAR}_${STATE}_bg_B01003.ndjson ]; then | |
for COUNTY in $(ndjson-cat cb_${YEAR}_${STATE}_counties.json \ | |
| ndjson-split \ | |
| tail -n +2 \ | |
| ndjson-map 'd[2]' \ | |
| cut -c 2-4); do | |
echo ${COUNTY} | |
if [ ! -f cb_${YEAR}_${STATE}_${COUNTY}_bg_B01003.json ]; then | |
curl -o cb_${YEAR}_${STATE}_${COUNTY}_bg_B01003.json \ | |
"http://api.census.gov/data/${YEAR}/acs5?get=B01003_001E&for=block+group:*&in=state:${STATE}+county:${COUNTY}&key=${CENSUS_KEY}" | |
fi | |
ndjson-cat cb_${YEAR}_${STATE}_${COUNTY}_bg_B01003.json \ | |
| ndjson-split \ | |
| tail -n +2 \ | |
>> cb_${YEAR}_${STATE}_bg_B01003.ndjson | |
done | |
fi | |
# 1. Convert to GeoJSON. | |
# 2. Project. | |
# 3. Join with the census data. | |
# 4. Compute the population density. | |
# 5. Simplify. | |
# 6. Compute the county borders. | |
geo2topo -n \ | |
blockgroups=<(ndjson-join 'd.id' \ | |
<(shp2json cb_${YEAR}_${STATE}_bg_500k.shp \ | |
| geoproject "${PROJECTION}.fitExtent([[10, 10], [${WIDTH} - 10, ${HEIGHT} - 10]], d)" \ | |
| ndjson-split 'd.features' \ | |
| ndjson-map 'd.id = d.properties.GEOID.slice(2), d') \ | |
<(cat cb_${YEAR}_${STATE}_bg_B01003.ndjson \ | |
| ndjson-map '{id: d[2] + d[3] + d[4], 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]') \ | |
| topomerge -k 'd.id.slice(0, 3)' counties=blockgroups \ | |
| topomerge --mesh -f 'a !== b' counties=counties \ | |
| topomerge -k 'd.properties.density' blockgroups=blockgroups \ | |
| toposimplify -p 1 -f \ | |
> topo.json | |
# Convert to SVG (while dropping the last line). | |
cat \ | |
<(topo2geo -n \ | |
< topo.json blockgroups=- \ | |
| 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.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 | |
rm topo.json |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Problems occur when running
npm install
. Node complains in the following way:I can supply a debug.log if you're interested. If one follows the tutorial and installs the dependencies globally, the prepublish script works just fine.