We utilized only Javascript and SVG to produce this data analysis / visualization report.
This report is prepared by
For this assignment the authors opted to spend time and search for Public Safety Open Data available online. We found several good resources at the state level for several states and also for cities at a more local level. In particular, New York City maintains an easy-to-use open data website at (https://nycopendata.socrata.com/)
The data for this exercise/report came from here and looks like:
[
{
"Incident Type": "Fire-Brush",
"Borough": "Staten Island"
},
{
"Incident Type": "Law Enforcement-Suspicious Package",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-1st Alarm",
"Borough": "Manhattan"
},
{
"Incident Type": "Structural-Other",
"Borough": "Bronx"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Queens"
},
{
"Incident Type": "Utility-Other",
"Borough": "Queens"
},
{
"Incident Type": "Utility-Gas High Pressure",
"Borough": "Brooklyn"
},
{
"Incident Type": "Fire-1st Alarm",
"Borough": "Brooklyn"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Staten Island"
},
{
"Incident Type": "Fire-3rd Alarm",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Steam Main",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Steam Main",
"Borough": "Manhattan"
},
{
"Incident Type": "Structural-Collapse",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Brooklyn"
},
{
"Incident Type": "Law Enforcement-Other",
"Borough": "Brooklyn"
},
{
"Incident Type": "Utility-Network Condition",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Water Service Line",
"Borough": "Queens"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Bronx"
},
{
"Incident Type": "Utility-Water Service Line",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Water Main",
"Borough": "Bronx"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Queens"
},
{
"Incident Type": "Law Enforcement-Other",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Gas Service Line",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Steam Main",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-Sensitive Location",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Queens"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Brooklyn"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Bronx"
},
{
"Incident Type": "Fire-Residential",
"Borough": "Queens"
},
{
"Incident Type": "Transportation-Other",
"Borough": "Staten Island"
},
{
"Incident Type": "Fire-Collapse",
"Borough": "Bronx"
},
{
"Incident Type": "Fire-10-77 (Residential High Rise Fire)",
"Borough": "Bronx"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Brooklyn"
},
{
"Incident Type": "Fire-4th Alarm",
"Borough": "Queens"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Bronx"
},
{
"Incident Type": "Utility-Water Main",
"Borough": "Queens"
},
{
"Incident Type": "Fire-2nd Alarm",
"Borough": "Manhattan"
},
{
"Incident Type": "Structural-Scaffold",
"Borough": "Brooklyn"
},
{
"Incident Type": "Marine-Freight Wet Goods",
"Borough": "Staten Island"
},
{
"Incident Type": "Structural-Parapet",
"Borough": "Queens"
},
{
"Incident Type": "Structural-Parapet",
"Borough": "Queens"
},
{
"Incident Type": "Utility-Water Service Line",
"Borough": "Brooklyn"
},
{
"Incident Type": "Fire-4th Alarm",
"Borough": "Staten Island"
},
{
"Incident Type": "Administration-Meeting",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Other",
"Borough": "Brooklyn"
},
{
"Incident Type": "Rescue-Confined Space",
"Borough": "Bronx"
},
{
"Incident Type": "HazMat-Fuel",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-1st Alarm",
"Borough": "Queens"
},
{
"Incident Type": "Structural-Other",
"Borough": "Brooklyn"
},
{
"Incident Type": "Utility-Power Outage",
"Borough": "Brooklyn"
},
{
"Incident Type": "HazMat-Fuel",
"Borough": "Brooklyn"
},
{
"Incident Type": "Fire-Other",
"Borough": "Bronx"
},
{
"Incident Type": "Fire-School",
"Borough": "Brooklyn"
},
{
"Incident Type": "HazMat-High Carbon Monoxide",
"Borough": "Brooklyn"
},
{
"Incident Type": "Structural-Scaffold",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-10-77 (Residential High Rise Fire)",
"Borough": "Manhattan"
},
{
"Incident Type": "HazMat-Fuel",
"Borough": "Bronx"
},
{
"Incident Type": "Law Enforcement-Suspicious Package",
"Borough": "Brooklyn"
},
{
"Incident Type": "Fire-Manhole",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-3rd Alarm",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-3rd Alarm",
"Borough": "Staten Island"
},
{
"Incident Type": "Structural-Partial Collapse",
"Borough": "Brooklyn"
},
{
"Incident Type": "Fire-Other",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Other",
"Borough": "Brooklyn"
},
{
"Incident Type": "Utility-Water Main",
"Borough": "Manhattan"
},
{
"Incident Type": "Utility-Other",
"Borough": "Bronx"
},
{
"Incident Type": "Law Enforcement-Suspicious Package",
"Borough": "Manhattan"
},
{
"Incident Type": "Fire-4th Alarm",
"Borough": "Brooklyn"
},
{
"Incident Type": "Utility-Gas Main Rupture",
"Borough": "Brooklyn"
},
{
"Inciden
<rect x="0"
y="345.5571635311143"
height="54.44283646888567"
width="80"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(0 345.5571635311143)">
Staten Island
</text>
<rect x="90"
y="20"
height="380"
width="80"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(90 20)">
Manhattan
</text>
<rect x="180"
y="277.9160636758321"
height="122.08393632416788"
width="80"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(180 277.9160636758321)">
Bronx
</text>
<rect x="270"
y="221.8234442836469"
height="178.1765557163531"
width="80"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(270 221.8234442836469)">
Queens
</text>
<rect x="360"
y="142.63386396526772"
height="257.3661360347323"
width="80"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(360 142.63386396526772)">
Brooklyn
</text>
<rect x="450"
y="396.15050651230104"
height="3.849493487698987"
width="80"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(450 396.15050651230104)">
Citywide
</text>
<rect x="540"
y="399.4500723589002"
height="0.5499276410998553"
width="80"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(540 399.4500723589002)">
</text><rect x="${d.x}"
y="${d.y}"
height="${d.height}"
width="${d.width}"
style="fill:${d.color};
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(${d.x} ${d.y})">
${d.label}
</text>var groups = _.groupBy(data, 'Borough')
var counts = _.map(groups, function(value, key) {
return {'name': key, 'count': _.pluck(value, 'Incident Type').length}
})
// Produce a bottom-aligned bar chart with margins
function computeX(d, i) {
return i * 90
}
function computeHeight(d, i) {
var value = _.max(_.pluck(counts, 'count'))
return (d.count/(value/380))
}
function computeWidth(d, i) {
return 80
}
function computeY(d, i) {
return 400 - computeHeight(d, i)
}
function computeColor(d, i) {
return 'red'
}
function computeLabel(d, i) {
return d.name
}
var viz = _.map(counts, function(d, i) {
return {
x: computeX(d, i),
y: computeY(d, i),
height: computeHeight(d, i),
width: computeWidth(d, i),
color: computeColor(d, i),
label: computeLabel(d, i)
}
})
var result = _.map(viz, function(d) {
// invoke the compiled template function on each viz data
return template({d: d})
})
return result.join('\n')<rect x="0"
y="210"
height="190"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(0 210)">
Law Enforcement-Suspicious Package
</text>
<rect x="60"
y="164.62686567164178"
height="235.37313432835822"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(60 164.62686567164178)">
Fire-1st Alarm
</text>
<rect x="120"
y="71.04477611940297"
height="328.95522388059703"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(120 71.04477611940297)">
Fire-2nd Alarm
</text>
<rect x="180"
y="295.07462686567163"
height="104.92537313432837"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(180 295.07462686567163)">
Utility-Other
</text>
<rect x="240"
y="229.8507462686567"
height="170.1492537313433"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(240 229.8507462686567)">
Fire-3rd Alarm
</text>
<rect x="300"
y="297.910447761194"
height="102.08955223880598"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(300 297.910447761194)">
Structural-Collapse
</text>
<rect x="360"
y="300.74626865671644"
height="99.25373134328359"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(360 300.74626865671644)">
Utility-Water Service Line
</text>
<rect x="420"
y="20"
height="380"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(420 20)">
Utility-Water Main
</text>
<rect x="480"
y="306.4179104477612"
height="93.58208955223881"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(480 306.4179104477612)">
Structural-Scaffold
</text>
<rect x="540"
y="246.86567164179104"
height="153.13432835820896"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(540 246.86567164179104)">
Utility-Power Outage
</text>
<rect x="600"
y="252.53731343283582"
height="147.46268656716418"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(600 252.53731343283582)">
HazMat-High Carbon Monoxide
</text>
<rect x="660"
y="306.4179104477612"
height="93.58208955223881"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(660 306.4179104477612)">
Structural-Stability Problem
</text>
<rect x="720"
y="25.67164179104475"
height="374.32835820895525"
width="50"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(720 25.67164179104475)">
LawEnforcement-Suspicious Package
</text><rect x="${d.x}"
y="${d.y}"
height="${d.height}"
width="${d.width}"
style="fill:${d.color};
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(${d.x} ${d.y})">
${d.label}
</text>var groups = _.groupBy(data, 'Incident Type')
// Using _.map and _.filter enables easy composition of unsorted output for viz purposes
var counts = _.map(groups, function(value, key) {
return {'name': key, 'count': _.pluck(value, 'Incident Type').length}
})
console.log(counts)
var filtered_counts = _.filter(counts, function(d) {
return d.count > 30
})
console.log(filtered_counts)
// Produce a bottom-aligned bar chart with margins
function computeX(d, i) {
return i * 60
}
function computeHeight(d, i) {
var value = _.max(_.pluck(counts, 'count'))
return (d.count/(value/380))
}
function computeWidth(d, i) {
return 50
}
function computeY(d, i) {
return 400 - computeHeight(d, i)
}
function computeColor(d, i) {
return 'red'
}
function computeLabel(d, i) {
return d.name
}
var viz = _.map(filtered_counts, function(d, i) {
return {
x: computeX(d, i),
y: computeY(d, i),
height: computeHeight(d, i),
width: computeWidth(d, i),
color: computeColor(d, i),
label: computeLabel(d, i)
}
})
console.log(viz)
var result = _.map(viz, function(d) {
// invoke the compiled template function on each viz data
return template({d: d})
})
return result.join('\n')<rect x="0"
y="20"
height="380"
width="90"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(0 20)">
Manhattan
</text>
<rect x="100"
y="72.41379310344826"
height="327.58620689655174"
width="90"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(100 72.41379310344826)">
Brooklyn
</text>
<rect x="200"
y="190.3448275862069"
height="209.6551724137931"
width="90"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(200 190.3448275862069)">
Queens
</text>
<rect x="300"
y="334.48275862068965"
height="65.51724137931035"
width="90"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(300 334.48275862068965)">
Bronx
</text>
<rect x="400"
y="295.17241379310343"
height="104.82758620689656"
width="90"
style="fill:red;
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(400 295.17241379310343)">
Staten Island
</text><rect x="${d.x}"
y="${d.y}"
height="${d.height}"
width="${d.width}"
style="fill:${d.color};
stroke-width:3;
stroke:rgb(0,0,0)" />
<text transform="translate(${d.x} ${d.y})">
${d.label}
</text>var flist = _.filter(data, function(f) {
return f['Incident Type'] == "Fire-1st Alarm"
})
var groups = _.groupBy(flist, 'Borough')
// Using _.map and _.filter enables easy composition of unsorted output for viz purposes
var counts = _.map(groups, function(value, key) {
return {'name': key, 'count': _.pluck(value, 'Incident Type').length}
})
console.log(counts)
// Produce a bottom-aligned bar chart with margins
function computeX(d, i) {
return i * 100
}
function computeHeight(d, i) {
var value = _.max(_.pluck(counts, 'count'))
return (d.count/(value/380))
}
function computeWidth(d, i) {
return 90
}
function computeY(d, i) {
return 400 - computeHeight(d, i)
}
function computeColor(d, i) {
return 'red'
}
function computeLabel(d, i) {
return d.name
}
var viz = _.map(counts, function(d, i) {
return {
x: computeX(d, i),
y: computeY(d, i),
height: computeHeight(d, i),
width: computeWidth(d, i),
color: computeColor(d, i),
label: computeLabel(d, i)
}
})
console.log(viz)
var result = _.map(viz, function(d) {
// invoke the compiled template function on each viz data
return template({d: d})
})
return result.join('\n')