Add US Census Bureau layers
This commit is contained in:
parent
77ff710b0d
commit
0b88a77b15
38
layers/census-bureau/README.md
Normal file
38
layers/census-bureau/README.md
Normal 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
|
47
layers/census-bureau/cleanup_data.py
Normal file
47
layers/census-bureau/cleanup_data.py
Normal 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)
|
17
layers/census-bureau/get_data.sh
Executable file
17
layers/census-bureau/get_data.sh
Executable 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?
|
63
layers/census-bureau/index.js
Normal file
63
layers/census-bureau/index.js
Normal 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;
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue