Boston Stop and Frisk visualization
Last active
June 9, 2016 00:12
-
-
Save pa-w/ee6da80443276e33af29754afd1caf45 to your computer and use it in GitHub Desktop.
Boston Stop and Frisk: Frisks, Searches and Summons issued by race
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
zip | total | black_total | white_total | hispanic_total | search_total | summons_total | frisked_total | search_black | search_white | search_hispanic | summons_black | summons_white | summons_hispanic | frisked_black | frisked_white | frisked_hispanic | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
02119 | 2560 | 2161 | 229 | 122 | 371 | 79 | 765 | 289 | 35 | 26 | 73 | 5 | 4 | 628 | 72 | 44 | |
02121 | 2003 | 1717 | 136 | 89 | 304 | 25 | 753 | 254 | 21 | 23 | 21 | 3 | 5 | 667 | 34 | 36 | |
02124 | 1937 | 1616 | 198 | 77 | 305 | 20 | 749 | 233 | 50 | 17 | 18 | 1 | 0 | 624 | 83 | 25 | |
1537 | 985 | 202 | 76 | 158 | 8 | 441 | 107 | 32 | 11 | 4 | 3 | 1 | 330 | 71 | 30 | ||
02118 | 1249 | 837 | 316 | 205 | 91 | 5 | 291 | 48 | 34 | 17 | 0 | 4 | 1 | 181 | 82 | 50 | |
02125 | 1145 | 795 | 220 | 78 | 163 | 9 | 391 | 108 | 32 | 14 | 1 | 5 | 0 | 282 | 67 | 26 | |
00000 | 1018 | 797 | 153 | 69 | 108 | 15 | 275 | 77 | 23 | 11 | 4 | 11 | 1 | 217 | 32 | 21 | |
02120 | 993 | 777 | 113 | 107 | 92 | 2 | 214 | 73 | 9 | 9 | 2 | 0 | 0 | 159 | 34 | 33 | |
02130 | 903 | 625 | 210 | 92 | 129 | 20 | 283 | 81 | 39 | 22 | 13 | 7 | 4 | 168 | 95 | 46 | |
02122 | 699 | 473 | 137 | 32 | 55 | 8 | 185 | 37 | 9 | 2 | 7 | 1 | 2 | 128 | 31 | 9 | |
02111 | 688 | 340 | 303 | 51 | 292 | 203 | 273 | 161 | 113 | 26 | 120 | 76 | 20 | 150 | 101 | 23 | |
02128 | 586 | 80 | 440 | 74 | 83 | 14 | 190 | 19 | 54 | 27 | 3 | 10 | 4 | 43 | 123 | 46 | |
02126 | 540 | 469 | 29 | 16 | 51 | 7 | 174 | 44 | 4 | 3 | 7 | 0 | 0 | 158 | 8 | 2 | |
02127 | 522 | 156 | 330 | 38 | 52 | 0 | 115 | 20 | 30 | 4 | 0 | 0 | 0 | 47 | 63 | 9 | |
02116 | 377 | 179 | 179 | 33 | 110 | 40 | 115 | 49 | 59 | 6 | 25 | 14 | 4 | 44 | 66 | 10 | |
02108 | 365 | 109 | 225 | 22 | 122 | 57 | 101 | 46 | 67 | 8 | 28 | 26 | 1 | 43 | 51 | 6 | |
02129 | 150 | 50 | 94 | 6 | 59 | 18 | 61 | 19 | 38 | 1 | 4 | 14 | 1 | 23 | 37 | 1 | |
02115 | 146 | 111 | 29 | 16 | 23 | 1 | 44 | 15 | 4 | 2 | 0 | 1 | 0 | 31 | 11 | 7 | |
02136 | 140 | 92 | 38 | 15 | 12 | 4 | 36 | 5 | 6 | 3 | 0 | 4 | 1 | 24 | 11 | 4 | |
02131 | 135 | 81 | 45 | 20 | 11 | 4 | 35 | 6 | 5 | 4 | 2 | 2 | 2 | 22 | 11 | 12 | |
02114 | 115 | 34 | 79 | 1 | 22 | 6 | 23 | 4 | 17 | 0 | 1 | 5 | 0 | 6 | 16 | 0 | |
02135 | 112 | 41 | 59 | 8 | 18 | 3 | 40 | 7 | 9 | 1 | 1 | 2 | 0 | 16 | 20 | 2 | |
02215 | 84 | 42 | 37 | 3 | 10 | 0 | 21 | 4 | 6 | 1 | 0 | 0 | 0 | 11 | 8 | 2 | |
02132 | 80 | 25 | 51 | 5 | 4 | 1 | 14 | 3 | 1 | 1 | 1 | 0 | 1 | 7 | 7 | 2 | |
02110 | 76 | 19 | 54 | 2 | 30 | 6 | 31 | 9 | 21 | 2 | 1 | 4 | 0 | 9 | 21 | 1 | |
02134 | 54 | 14 | 31 | 2 | 5 | 0 | 25 | 1 | 4 | 0 | 0 | 0 | 0 | 8 | 13 | 2 | |
02109 | 38 | 17 | 20 | 2 | 8 | 4 | 14 | 3 | 5 | 0 | 4 | 0 | 0 | 6 | 8 | 0 | |
02113 | 18 | 4 | 14 | 0 | 5 | 1 | 6 | 0 | 5 | 0 | 0 | 1 | 0 | 1 | 5 | 0 | |
02199 | 16 | 6 | 3 | 0 | 7 | 0 | 9 | 2 | 2 | 0 | 0 | 0 | 0 | 3 | 3 | 0 | |
02210 | 10 | 1 | 8 | 0 | 1 | 0 | 3 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 2 | 0 | |
02203 | 8 | 1 | 6 | 0 | 3 | 0 | 4 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | |
02446 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02026 | 2 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02188 | 2 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | |
0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
01218 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
01810 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | |
02062 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02150 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02169 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02186 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02205 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02351 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02368 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
02467 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 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
<!DOCTYPE html> | |
<html lang="en-us"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Stop and Frisk in Boston</title> | |
<meta charset="utf-8"/> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<script src="//dist.ant-project.com/jquery.min.js"></script> | |
<script src="//dist.ant-project.com/d3.min.js"></script> | |
<script src="//dist.ant-project.com/d3.geo.projection.v0.min.js"></script> | |
<script src="//dist.ant-project.com/queue.min.js"></script> | |
<script src="//dist.ant-project.com/topojson.js"></script> | |
<script src="//dist.ant-project.com/ant.js"></script> | |
<script src="ant.js"></script> | |
<link rel="stylesheet" href="style.css"/> | |
</head> | |
<body> | |
<a data-onload id="download" data-download="data.csv" data-download_id="saf" data-download_processor="process" data-download_parse=".quantifier" data-debug="Start download"></a> | |
<div class="col"> | |
<h2>Stops by Zipcode</h2> | |
<h3>Total</h3> | |
<div id="total" data-chart="lines" class="chart columns"></div> | |
<a class="quantifier" data-control_chart="total" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"cols": ["total"], "comp": "total"}'></a> | |
<h3>Frisks</h3> | |
<div id="total_frisks" data-chart="lines" class="chart columns"></div> | |
<a class="quantifier" data-control_chart="total_frisks" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"cols": ["frisked_total"], "comp": "total"}'></a> | |
<h3>Searches</h3> | |
<div id="total_searches" data-chart="lines" class="chart columns"></div> | |
<a class="quantifier" data-control_chart="total_searches" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"cols": ["search_total"], "comp": "total"}'></a> | |
<h3>Summons Issued</h3> | |
<div id="total_summons" data-chart="lines" class="chart columns"></div> | |
<a class="quantifier" data-control_chart="total_summons" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"cols": ["summons_total"], "comp": "total"}'></a> | |
</div> | |
<div class="col"> | |
<h2>Black, Hispanic and White</h2> | |
<h3>Total</h3> | |
<div id="race_total" data-chart="lines" class="chart columns"></div> | |
<a class="quantifier" data-control_chart="race_total" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"cols": ["black_total", "white_total", "hispanic_total"], "comp": "total"}'></a> | |
<h3>Frisks</h3> | |
<div id="race_frisked" data-chart="lines" class="chart columns"></div> | |
<a class="quantifier" data-control_chart="race_frisked" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"cols": ["frisked_black", "frisked_white", "frisked_hispanic"], "comp": "total"}'></a> | |
<h3>Searches</h3> | |
<div id="race_search" data-chart="lines" class="chart columns"></div> | |
<a class="quantifier" data-control_chart="race_search" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"cols": ["search_black", "search_white", "search_hispanic"], "comp": "total"}'></a> | |
<h3>Summons Issued</h3> | |
<div id="race_summons" data-chart="lines" class="chart columns"></div> | |
<a class="quantifier" data-control_chart="race_summons" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"cols": ["summons_black", "summons_white", "summons_hispanic"], "comp": "total"}'></a> | |
</div> | |
<div class="col"> | |
<h2>Relationships</h2> | |
<h3>Stops vs. frisks</h3> | |
<div id="stops_frisks" data-chart="lines" class="chart scatterplot"></div> | |
<a class="quantifier" data-control_chart="stops_frisks" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"comp": ["total", "total"], "cols": [["total", "frisked_total"], ["black_total", "frisked_black"], ["white_total", "frisked_white"], ["hispanic_total", "frisked_hispanic"]], "scatterplot": true}' data-debug="total_frisks"></a> | |
<h3>Frisks vs. searches</h3> | |
<div id="frisks_searches" data-chart="lines" class="chart scatterplot"></div> | |
<a class="quantifier" data-control_chart="frisks_searches" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"comp": ["total", "frisked_total"], "cols": [["frisked_total", "search_total"], ["frisked_black", "search_black"], ["frisked_white", "search_white"], ["frisked_hispanic", "search_hispanic"]], "scatterplot": true}' data-debug="total_frisks"></a> | |
<h3>Searches vs Summons issued</h3> | |
<div id="searches_summons" data-chart="lines" class="chart scatterplot"></div> | |
<a class="quantifier" data-control_chart="searches_summons" data-quantify="saf" data-quantifier="total" data-quantifier_args='{"comp": ["frisked_total", "search_total"], "cols": [["search_total", "summons_total"], ["search_black", "summons_black"], ["search_white", "summons_white"], ["search_hispanic", "summons_hispanic"]], "scatterplot": true}' data-debug="total_frisks"></a> | |
</div> | |
<div class="col"> | |
<div> | |
<table> | |
<tr><th>Zip:</th><td colspan="3"><span class="zip_text"></span></td></tr> | |
<tr><th></th><th>White</th><th>Black</th><th>Hispanic</th><th>All</th></tr> | |
<tr><th>Stops:</th> | |
<td><span class="white_total_text"></span></td> | |
<td><span class="black_total_text"></span></td> | |
<td><span class="hispanic_total_text"></span></td> | |
<td><span class="total_text"></span></td> | |
</tr> | |
<tr><th>Frisks:</th> | |
<td><span class="frisked_white_text"></span></td> | |
<td><span class="frisked_black_text"></span></td> | |
<td><span class="frisked_hispanic_text"></span></td> | |
<td><span class="frisked_total_text"></span></td> | |
</tr> | |
<tr><th>Searches:</th> | |
<td><span class="search_white_text"></span></td> | |
<td><span class="search_black_text"></span></td> | |
<td><span class="search_hispanic_text"></span></td> | |
<td><span class="search_total_text"></span></td> | |
</tr> | |
<tr><th>Summons:</th> | |
<td><span class="summons_white_text"></span></td> | |
<td><span class="summons_black_text"></span></td> | |
<td><span class="summons_hispanic_text"></span></td> | |
<td><span class="summons_total_text"></span></td> | |
</tr> | |
</table> | |
</div> | |
</div> | |
<script> | |
$(document).ready(function () { | |
var conf = { | |
prequantifiers: { | |
total: function (args) { | |
var comp = args.comp, | |
scale = {}; | |
if (args.scatterplot) { | |
scale.x = d3.scale.pow ().exponent (.15).domain (this.data.saf.extent (function (a) { return parseInt (a.values [args.comp [1]].value); })); | |
comp = args.comp [0]; | |
} | |
var ext = this.data.saf.extent (function (a) { return parseInt (a.values [comp].value);}) | |
scale.y = d3.scale.linear ().domain ([ext [1], ext [0]]) | |
var items = this.data.saf.items (), | |
data = []; | |
for (var i = 0; i < args.cols.length; i++) { | |
data.push ({"values": items, "col": args.cols [i] }); | |
} | |
return { | |
"data": data, | |
"scale": scale | |
} | |
} | |
}, | |
quantifiers: { | |
lines: { | |
total: function (zip, args, a, series ) { | |
/* highlights and updates the labels */ | |
var parse = [ | |
{"control_element": ".zip", "element_remove_class": "highlight"}, | |
{"control_element": ".zip_" + zip.key, "element_add_class": "highlight"}, | |
], ret = { | |
"class": "zip " + series.col + " zip_" + zip.key, | |
"data": {"parse": parse} | |
} | |
var its = zip.values.items (); | |
for (var x in its) { | |
parse.push ({ | |
"control_element": "." + its[x].key + "_text", | |
"element_text": its [x].values.value | |
}); | |
} | |
if (args.scatterplot) { | |
ret ["class"] = series.col [0] + " " + series.col [1] + " zip zip_" + zip.key; | |
ret.y = a.scale.y (parseInt (zip.values [series.col [0]].value)); | |
ret.x = a.scale.x (parseInt (zip.values [series.col [1]].value)); | |
ret.r = (zip.values [series.col [1]].value / 30) + 2; | |
if (ret.x == 0) { | |
ret ["class"] = "hide"; | |
} | |
} else { | |
ret.y = a.scale.y (parseInt (zip.values [series.col].value)); | |
if (parseInt (zip.values [series.col].value) == 0) { | |
} | |
} | |
return ret; | |
} | |
} | |
}, | |
callbacks: { | |
process: function (rows, id) { | |
return new Nestify (rows, ["zip"], ["zip","total","black_total","white_total","hispanic_total","search_total","summons_total","search_black","search_white","search_hispanic","summons_black","summons_white","summons_hispanic", "frisked_total", "frisked_black", "frisked_white", "frisked_hispanic"]).data; | |
} | |
} | |
}; | |
new Ant (conf); | |
}); | |
</script> | |
</body> | |
</html> |
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
COPY ( | |
SELECT distinct | |
split_part("ZIP", '-', 1) as zip, | |
count (*) as total, | |
count (*) filter (WHERE people."RACE" = 'Black') as black_total, | |
count (*) filter (WHERE people."RACE" = 'White') as white_total, | |
count (*) filter (WHERE people."Ethnicity" = 'Hispanic Origin') as hispanic_total, | |
count (*) filter (WHERE stop."SearchPerson" = 'Y') as search_total, | |
count (*) filter (WHERE stop."SummonsIssued" = 'Y') as summons_total, | |
count (*) filter (WHERE stop."Frisked" = 'Y') as frisked_total, | |
count (*) filter (WHERE stop."SearchPerson" = 'Y' AND people."RACE" = 'Black') as search_black, | |
count (*) filter (WHERE stop."SearchPerson" = 'Y' AND people."RACE" = 'White') as search_white, | |
count (*) filter (WHERE stop."SearchPerson" = 'Y' AND people."Ethnicity" = 'Hispanic Origin') as search_hispanic, | |
count (*) filter (WHERE stop."SummonsIssued" = 'Y' AND people."RACE" = 'Black') as summons_black, | |
count (*) filter (WHERE stop."SummonsIssued" = 'Y' AND people."RACE" = 'White') as summons_white, | |
count (*) filter (WHERE stop."SummonsIssued" = 'Y' AND people."Ethnicity" = 'Hispanic Origin') as summons_hispanic, | |
count (*) filter (WHERE stop."Frisked" = 'Y' AND people."RACE" = 'Black') as frisked_black, | |
count (*) filter (WHERE stop."Frisked" = 'Y' AND people."RACE" = 'White') as frisked_white, | |
count (*) filter (WHERE stop."Frisked" = 'Y' AND people."Ethnicity" = 'Hispanic Origin') as frisked_hispanic | |
FROM | |
"FieldContacts_For_Public_2015-Apr_30_2016" as stop LEFT JOIN | |
"FieldContacts_Name_For_Public_2015-Apr_30_2016" people | |
ON stop."FC_NUM" = people."FC_NUM" | |
GROUP BY | |
zip | |
ORDER BY | |
total DESC | |
) TO '/tmp/fios.csv' CSV HEADER; |
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
body { | |
width: 99vw; | |
height: 99vh; | |
margin: 0; | |
padding: 0; | |
color: gray; | |
} | |
h1,h2,h3,h4,h5,h6 { | |
margin: 0; | |
} | |
h2 { font-size: 1.1em; text-align: center; margin-bottom: 1%; } | |
h3 { font-size: 1em; } | |
div.col { | |
float: left; | |
width: 25%; | |
height: 100%; | |
} | |
.chart, .columns path, .chart path { | |
fill: none; | |
} | |
.axis path { | |
display: none; | |
} | |
.axis text { | |
fill: red; | |
font-size: 0.3em; | |
} | |
.axis line { | |
stroke: #777; | |
stroke-dasharray: 1,1; | |
} | |
div.chart { | |
height: 20%; | |
} | |
.chart.columns rect.column { | |
fill: rgba(0,123,123,0.5); | |
fill-opacity: 1 !important; | |
stroke: white; | |
stroke-width: 0.5; | |
} | |
.chart.scatterplot circle { | |
stroke: white; | |
stroke-width: 0.5; | |
} | |
.black_total, .search_black, .frisked_black, .summons_black { | |
fill: rgba(0,123,0,0.5) !important; | |
} | |
.white_total, .search_white, .frisked_white, .summons_white { | |
fill: rgba(0,0,123,0.5) !important; | |
} | |
.hispanic_total, .search_hispanic, .frisked_hispanic, .summons_hispanic { | |
fill: rgba(255,140,0,1) !important; | |
} | |
cirle.total, circle.search_total, circle.frisked_total, circle.summons_total { | |
} | |
circle.hide, rect.hide { | |
display: none !important; | |
} | |
.square { | |
display: none !important; | |
} | |
/* | |
*/ | |
.columns .highlight.background { | |
fill: rgba(255,0,0,0.6) !important; | |
} | |
circle.highlight { | |
stroke: rgba(255,0,0,0.6) !important; | |
stroke-width: 3 !important; | |
} | |
.background, .square, .line, .scatterplot .column { | |
fill: rgba(0,0,0,0) !important; | |
stroke: none !important; | |
} | |
.scatterplot .column, .scatterplot .background { | |
fill: none !important; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment