Add US Census Bureau layers

This commit is contained in:
Chandler Swift 2023-07-25 21:34:19 -05:00
parent 77ff710b0d
commit 0b88a77b15
Signed by: chandlerswift
GPG key ID: A851D929D52FB93F
5 changed files with 168 additions and 1 deletions

View file

@ -0,0 +1,38 @@
from the US Census Bureau:
https://www.census.gov/geographies/mapping-files/time-series/geo/cartographic-boundary.html
more description here:
https://www.census.gov/programs-surveys/geography/technical-documentation/naming-convention/cartographic-boundary-file.html
Including the following:
> # File Naming Convention
> ## 2013 to Present Files
>
> The cartographic boundary files are named cb_yyyy_ss_<entity>_rr.zip where:
>
> * yyyy = 4 digit year
> * ss = state FIPS code or 'us' for a national level file
> * entity = the entity name
> * rr = resolution level
> * 500k = 1:500,000
> * 5m = 1:5,000,000
> * 20m = 1:20,000,000
I prefer the KML options when available since OpenLayers doesn't [citation
needed?] have built-in support for shapefiles (.shp)? That said, we also do
transform KML to GeoJSON to be able to edit more easily (and it's sometimes good
for a smaller file size).
For more information, see e.g.:
https://indicatrix.org/post/shapefiles-in-openlayers/
Census Bureau data appears to be using a different (US-centric, possibly?)
projection; this may require more work to be accurate going forward.
https://gis.stackexchange.com/a/310949
https://epsg.io/4269

View file

@ -0,0 +1,47 @@
#!/usr/bin/python3
import sys
import json
with open(sys.argv[1]) as f:
data = json.load(f)
# {
# "type": "FeatureCollection",
# "name": "cb_2022_us_county_20m",
# "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
# "features": [
# {
# "type": "Feature",
# "properties": {
# "Name": "<at><openparen>Autauga<closeparen>",
# "Description": "<center><table><tr><th colspan='2' align='center'><em>Attributes</em></th></tr><tr bgcolor=\"#E3E3F3\"> <th>STATEFP</th> <td>01</td> </tr><tr bgcolor=\"\"> <th>COUNTYFP</th> <td>001</td> </tr><tr bgcolor=\"#E3E3F3\"> <th>COUNTYNS</th> <td>00161526</td> </tr><tr bgcolor=\"\"> <th>AFFGEOID</th> <td>0500000US01001</td> </tr><tr bgcolor=\"#E3E3F3\"> <th>GEOID</th> <td>01001</td> </tr><tr bgcolor=\"\"> <th>NAME</th> <td>Autauga</td> </tr><tr bgcolor=\"#E3E3F3\"> <th>NAMELSAD</th> <td>Autauga County</td> </tr><tr bgcolor=\"\"> <th>STUSPS</th> <td>AL</td> </tr><tr bgcolor=\"#E3E3F3\"> <th>STATE_NAME</th> <td>Alabama</td> </tr><tr bgcolor=\"\"> <th>LSAD</th> <td>06</td> </tr><tr bgcolor=\"#E3E3F3\"> <th>ALAND</th> <td>1539631461</td> </tr><tr bgcolor=\"\"> <th>AWATER</th> <td>25677536</td> </tr></table></center>"
# },
# "geometry": {
# "type": "Polygon",
# "coordinates": [
# [
# [
# -86.917595,
# 32.664169,
# 0.0
# ],
# ...
# ]
# ]
# }
# },
# [...]
# ]
# }
# len("<at><openparen>") == 15
# len("<closeparen>") == 12
# "<at><openparen>Autauga<closeparen>"[15:-12] == "Autauga"
for feature in data['features']:
# del feature['properties']['Description']
feature['properties']['Name'] = feature['properties']['Name'][15:-12]
with open(sys.argv[1], 'w') as f:
json.dump(data, f)

View file

@ -0,0 +1,17 @@
#!/bin/sh
for resolution in 20m 5m; do
curl --silent --remote-name https://www2.census.gov/geo/tiger/GENZ2022/shp/cb_2022_us_county_${resolution}.zip
unzip cb_2022_us_county_${resolution}.zip
ogr2ogr -f GeoJSON us-counties-${resolution}.geojson cb_2022_us_county_${resolution}.shp
sed -i '/^"crs":/d' us-counties-${resolution}.geojson # TODO: handle this projection properly
rm cb_2022_us_county_${resolution}.*
# python cleanup_data.py us-counties-${resolution}.geojson # Only needed for KML files
done
curl --silent --remote-name https://www2.census.gov/geo/tiger/GENZ2022/shp/cb_2022_us_unsd_500k.zip
unzip cb_2022_us_unsd_500k.zip
ogr2ogr -f GeoJSON us-school-districts.geojson cb_2022_us_unsd_500k.shp
sed -i '/^"crs":/d' us-school-districts.geojson # TODO: handle this projection properly
rm cb_2022_us_unsd_500k.*
# TODO: some kind of cleanup to save space?

View file

@ -0,0 +1,63 @@
import GeoJSON from 'ol/format/GeoJSON.js';
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import counties20m from './us-counties-20m.geojson?url';
import counties5m from './us-counties-5m.geojson?url';
import schoolDistricts from './us-school-districts.geojson?url';
import { Fill, Stroke, Style, Text } from 'ol/style.js';
function style(feature){
return new Style({
text: new Text({
text: feature.get('NAME'),
}),
fill: new Fill({
color: 'rgba(255,255,255,0.4)',
}),
stroke: new Stroke({
color: '#3399CC',
width: 1.25,
}),
});
}
const layers = {
name: "US Census Bureau Data",
layers: [
{
name: "All Counties (2022; low-res)",
layer: new VectorLayer({
source: new VectorSource({
url: counties20m,
format: new GeoJSON(),
}),
style: style,
}),
},
{
name: "All Counties (2022; medium-res)",
layer: new VectorLayer({
source: new VectorSource({
url: counties5m,
format: new GeoJSON(),
}),
style: style,
}),
},
{
name: "School Districts (2022; unreasonably large)",
layer: new VectorLayer({
source: new VectorSource({
url: schoolDistricts,
format: new GeoJSON(),
// TODO: this probably uses projection 'EPSG:4326'
}),
style: style,
}),
},
],
};
export default layers;

View file

@ -7,6 +7,7 @@ import amtrakLayer from './amtrak/layer.js';
import arenasLayer from './nhl-arenas/layer.js'; import arenasLayer from './nhl-arenas/layer.js';
import bikepackingLayer from './bikepacking/layer.js'; import bikepackingLayer from './bikepacking/layer.js';
import chains from './chains/index.js'; import chains from './chains/index.js';
import census_bureau from './census-bureau/index.js';
const layerCategories = [ const layerCategories = [
{ // Base maps { // Base maps
@ -70,7 +71,8 @@ const layerCategories = [
}, },
] ]
}, },
chains chains,
census_bureau,
]; ];
export default layerCategories; export default layerCategories;