[ Launch: once more with feeling ] 6025562 by gelicia
-
-
Save gelicia/6025562 to your computer and use it in GitHub Desktop.
once more with feeling
This file contains 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
{"description":"once more with feeling","endpoint":"","display":"svg","public":true,"require":[{"name":"underscore","url":"http://underscorejs.org/underscore-min.js"}],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"map.geojson":{"default":true,"vim":false,"emacs":false,"fontSize":12},"newyork.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"thumbnail":"http://i.imgur.com/2SZsiLN.png"} |
This file contains 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
/*Occasionally there is a race condition where the map loads before | |
the bar chart, so the map-to-barchart highlighting doesn't work. | |
Hit space on this side to fix it. | |
It happens very rarely. In real life I would fix it with | |
jquery deferred but underscore defer works well enough for now. | |
This is also full of magic numbers, more external styling and | |
config variables would fix that. | |
*/ | |
var map = tributary.newyork; | |
var svg = d3.select('svg'); | |
var data = []; | |
var bounds = {l : 768, h: 366}; | |
var mapG = svg.append('g').attr("id", "mapG"); | |
var path = d3.geo.path().projection( | |
d3.geo.mercator().center([ -74.1, 40.7]). | |
scale(34348).translate([bounds.l / 2, bounds.h / 2])); | |
var mapPath = mapG.selectAll('path.shapes') | |
.data(map.features) | |
.enter().append('path') | |
.attr({ | |
'class': 'shape', | |
'd': path, | |
'id': function(d){return "p"+ d.properties.Precinct;} | |
}) | |
.style('fill', '#BBBBF8') | |
.style('stroke', "black"); | |
d3.json('http://data.cityofnewyork.us/resource/2j99-6h29.json', | |
function(error, json) { | |
//standardize the precinct to be just a number or undefined | |
json = json.map(function(d){ | |
if (isNaN(d.police_precinct.substring(9, d.police_precinct.length))){ | |
d.police_precinct = undefined; | |
} | |
else { | |
d.police_precinct = Number(d.police_precinct.substring(9, d.police_precinct.length)); | |
} | |
return d; | |
}); | |
//group the set to be by precinct, totaling the number of reports and averaging the | |
//number of days a report goes unresolved | |
for (var i = 0; i < json.length; i++) { | |
var graffEntry = json[i]; | |
if (graffEntry.police_precinct !== undefined){ | |
var entry = _.find(data, function(d){ return d.precinct == graffEntry.police_precinct;}); | |
if (entry === undefined){ //create | |
var thisPre = {}; | |
thisPre.precinct = graffEntry.police_precinct; | |
thisPre.avgResolveDays = 0; | |
thisPre.numUnresolved = 0; | |
thisPre.numTotal = 0; | |
data.push(thisPre); | |
entry = data[data.length-1]; | |
} | |
entry.numTotal = entry.numTotal + 1; | |
var resolved = graffEntry.status == 'Closed' ? true : false; | |
//closed_date seems to be filled for closed entries, otherwise don't trust status | |
//just trust closed_date | |
if(resolved){ | |
// difference in days | |
var dateDiff = (graffEntry.closed_date - graffEntry.created_date)/60/60/24; | |
if (entry.avgResolveDays === 0) { entry.avgResolveDays = dateDiff;} | |
else { | |
entry.avgResolveDays = (entry.avgResolveDays + dateDiff)/2; | |
} | |
} | |
else { | |
entry.numUnresolved = entry.numUnresolved + 1; | |
} | |
} | |
} | |
//display the bars sorted by desc avgResolveDays | |
data = data.sort(function(a, b) { | |
return a.avgResolveDays < b.avgResolveDays ? 1 : -1; | |
}); | |
var graphGrp = svg.append('g') | |
.attr('transform', 'translate(36, 360)'); | |
var barWidth = 8; | |
var valMax = d3.max(data, function(d){return d.avgResolveDays}); | |
var heightScale = d3.scale.linear().domain([0, valMax]) | |
.range([0, 200]); | |
graphGrp.append('text') | |
.attr({ | |
x: 213, | |
y: 50, | |
'font-size': 14 | |
}) | |
.text('Average Days To Resolve a Report'); | |
graphGrp.selectAll('rect') | |
.data(data) | |
.enter() | |
.append('rect') | |
.attr({ | |
'id': function(d){return 'b'+d.precinct;}, | |
x: function(d,i){return (i*(barWidth + 2));}, | |
y: function(d){return 30 - heightScale(d.avgResolveDays);}, | |
height: function(d){return heightScale(d.avgResolveDays);}, | |
width: barWidth, | |
fill: '#FFC78A' | |
}) | |
.on('mouseover', function(d){ | |
d3.select(this) | |
.style('fill', '#FF9A2C'); | |
d3.select('#p' + d.precinct) | |
.style('fill', '#6C6CED'); | |
}) | |
.on('mouseout', function(d){ | |
d3.select(this) | |
.style('fill', '#FFC78A'); | |
d3.select('#p' + d.precinct) | |
.style('fill', '#BBBBF8'); | |
}) | |
.on('click', function(d){ | |
var entry = _.find(data, function(dIn){ return dIn.precinct == d.precinct;}); | |
clickPrec(entry); | |
}); | |
//fixes a race condition where the map draws before the bars | |
//then the map to bar highlighting doesn't work | |
_.defer(function(){ | |
mapPath | |
.on('mouseover', function(d){ | |
d3.select(this) | |
.style('fill', '#6C6CED'); | |
d3.select('#b' + d.properties.Precinct) | |
.style('fill', '#FF9A2C'); | |
}) | |
.on('mouseout', function(d){ | |
d3.select(this) | |
.style('fill', '#BBBBF8'); | |
d3.select('#b' + d.properties.Precinct) | |
.style('fill', '#FFC78A'); | |
}) | |
.on('click', function(d){ | |
var entry = _.find(data, function(dIn){ return dIn.precinct == d.properties.Precinct;}); | |
clickPrec(entry); | |
}); | |
}); | |
}); | |
//swaps out an informational box | |
function clickPrec(entry){ | |
d3.select('g.clkInfo').remove(); | |
var infoTxt = svg.append('g') | |
.classed('clkInfo', true) | |
.attr('transform', 'translate(50, 50)').append('text'); | |
if(entry !== undefined){ | |
infoTxt.append('tspan') | |
.classed('headline', true) | |
.text('Police Precinct ' + entry.precinct); | |
infoTxt.append('tspan') | |
.attr({ | |
x : 0, | |
dy : '1.2em' | |
}) | |
.text(Math.round(entry.avgResolveDays) + " average days to resolve a report."); | |
infoTxt.append('tspan') | |
.attr({ | |
x : 0, | |
dy : '1.2em' | |
}) | |
.text(entry.numTotal + " reports (" + entry.numUnresolved + " unresolved)"); | |
} | |
else { | |
infoTxt.text('No information available for this precinct.'); | |
} | |
} |
This file contains 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
.headline { | |
font-weight: bold | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment