US Federal Judicial Districts
Sources:
| .DS_Store | |
| node_modules | |
| us-judicial-districts.zip | |
| build |
Sources:
| <!doctype html> | |
| <meta charset="utf-8"> | |
| <style type="text/css" media="screen"> | |
| body { | |
| margin: 0; | |
| } | |
| .district { | |
| stroke: #fff; | |
| stroke-width: 1; | |
| fill-opacity: 0.6; | |
| } | |
| .district:hover { | |
| fill-opacity: 0.8; | |
| } | |
| .county { | |
| fill: none; | |
| stroke: #333; | |
| stroke-width: 0.5; | |
| stroke-opacity: 0.6; | |
| } | |
| .label { | |
| font-family: Helvetica; | |
| font-size: 11px; | |
| font-weight: bold; | |
| fill-opacity: 1; | |
| text-anchor: middle; | |
| stroke: none; | |
| pointer-events: none; | |
| } | |
| </style> | |
| <body> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <script src="http://d3js.org/topojson.v1.min.js"></script> | |
| <script type="text/javascript" charset="utf-8"> | |
| var width = 960, | |
| height = 600 | |
| var path = d3.geo.path() | |
| var color = d3.scale.category20() | |
| var svg = d3.select("body").append('svg') | |
| .attr('width', width) | |
| .attr('height', height) | |
| d3.json('us.json', function(error, us) { | |
| if(error) return console.error("Boom goes the dynamite: " + error) | |
| var dem = 0, rep = 0 | |
| us.objects.districts.geometries.forEach(function(d) { | |
| d.properties.judges.forEach(function(j) { | |
| if(j.ppa === 'Democratic') dem++ | |
| if(j.ppa === 'Republican') rep++ | |
| }) | |
| }) | |
| console.log(dem + " Democrat appointments", rep + " Republican appointments"); | |
| svg.append('path') | |
| .datum(topojson.mesh(us, us.objects.counties)) | |
| .attr('class', 'county') | |
| .attr('d', path) | |
| districts = svg.selectAll('.district') | |
| .data(topojson.feature(us, us.objects.districts).features) | |
| .enter().append('path') | |
| .attr('class', 'district') | |
| .attr('d', path) | |
| .style('fill', function(d, i) { return color(i) }) | |
| .on('click', function(district) { | |
| var d = 0, r = 0 | |
| var names = district.properties.judges.map(function(j) { | |
| if(j.ppa === 'Democratic') d++ | |
| if(j.ppa === 'Republican') r++ | |
| return j.ppa + ": " + j.name | |
| }).join("\n") | |
| console.log("D: " + d, "R: " + r, "\n\n" + names); | |
| }) | |
| var labels = svg.append('g') | |
| districts.each(function(d) { | |
| var center = path.centroid(d) | |
| labels.append('text') | |
| .attr('class', 'label') | |
| .attr('dx', function(d) { return center[0] }) | |
| .attr('dy', function(d) { return center[1] }) | |
| .text(d.properties.jdcode) | |
| }) | |
| }) | |
| </script> | |
| </body> |
| all: us.json | |
| clean: | |
| rm -rf -- us.json \ | |
| build/*-ungrouped.* \ | |
| build/*.json \ | |
| build/judicial-districts.shp \ | |
| build/judicial-districts.sbn \ | |
| build/judicial-districts.sbx \ | |
| build/judicial-districts.shx \ | |
| build/judicial-districts.prj \ | |
| build/judicial-districts.dbf | |
| .PHONY: all clean | |
| build/judicial-districts.shp: | |
| rm -rf $(basename $@) | |
| mkdir -p $(basename $@) | |
| tar -xzm -C build -f ./build/judicial-districts.tar.gz | |
| for file in $(basename $@)/*; do chmod 644 $$file; mv $$file $(basename $@).$${file##*.}; done | |
| rmdir $(basename $@) | |
| build/counties.json: build/judicial-districts.shp | |
| node_modules/.bin/topojson \ | |
| -o $@ \ | |
| --no-pre-quantization \ | |
| --post-quantization=1e6 \ | |
| --simplify=7e-7 \ | |
| -p jdcode=+JDCODE,state=State,name=JD_NAME \ | |
| --id-property=+FIPS \ | |
| -- counties=build/judicial-districts.shp | |
| build/districts.json: build/counties.json | |
| rm $(basename $@)-unreconciled.json | |
| node_modules/.bin/topojson-merge \ | |
| -o $(basename $@)-unreconciled.json \ | |
| --in-object=counties \ | |
| --out-object=districts \ | |
| --key='d.properties.jdcode' \ | |
| -- $< | |
| ./reconcile-judges < $(basename $@)-unreconciled.json > $@ | |
| us.json: build/districts.json | |
| node_modules/.bin/topojson-merge \ | |
| -o $@ \ | |
| --in-object=districts \ | |
| --out-object=nation \ | |
| -- $< |
| { | |
| "name": "anonymous", | |
| "version": "0.0.1", | |
| "private": true, | |
| "dependencies": { | |
| "fast-csv": "0.2.4", | |
| "topojson": ">=1.6.2 <2" | |
| } | |
| } |
| #!/usr/bin/env node | |
| // Because no one bothered to standardize on court names or give them an ID and | |
| // assign judges to one, we're left with the cesspool you see below | |
| // | |
| var fs = require('fs'), | |
| csv = require('fast-csv') | |
| var topo = JSON.parse(fs.readFileSync('build/districts-unreconciled.json')) | |
| var judges = [], | |
| states = [], | |
| names = [], | |
| locations = ['Northern', 'Southern', 'Middle', 'Western', 'Eastern'] | |
| // Only keep active US District Court judges | |
| function terminated(record) { | |
| var termination = record['Date of Termination'], | |
| death = record['Death year'], | |
| courtType = record['Court Type'], | |
| retired = record['Retirement from Active Service'] | |
| if(termination === '' && courtType === 'USDC' && retired === '') { | |
| judges.push(record) | |
| } | |
| } | |
| function reconcile() { | |
| topo.objects.districts.geometries.forEach(function(geo) { | |
| geo.properties.judges = [] | |
| if(geo.properties.name === null) return; | |
| var parts = geo.properties.name.split(' '), | |
| geostate = null, | |
| geolocation = null | |
| if(parts.length > 1) { | |
| geolocation = parts.pop() | |
| geostate = parts.join(' ') | |
| } else { | |
| geostate = parts[0] | |
| } | |
| judges.forEach(function(judge) { | |
| var cname = judge['Court Name'], | |
| info = { | |
| name: judge['Judge First Name'] + " " + judge['Judge Last Name'], | |
| ppa: judge['Party Affiliation of President'] | |
| // race: judge['Race or Ethnicity'], | |
| // gender: judge['Gender'], | |
| // date: judge['Commission Date'] | |
| } | |
| if(cname.indexOf(geostate) !== -1 && (geolocation && cname.indexOf(geolocation) !== -1)) { | |
| geo.properties.judges.push(info) | |
| } else if(!geolocation && cname.indexOf(geostate) != -1) { | |
| geo.properties.judges.push(info) | |
| } | |
| }) | |
| }) | |
| console.log(JSON.stringify(topo)); | |
| } | |
| csv.fromPath('build/states.csv', { headers: true }) | |
| .on('record', function(state) { states.push(state) }) | |
| .on('end', function() { | |
| csv.fromPath('build/judges.csv', { headers: true }) | |
| .on('record', terminated) | |
| .on('end', reconcile) | |
| }) |