Skip to content

Instantly share code, notes, and snippets.

@oikonang
Last active March 26, 2017 17:55
Show Gist options
  • Save oikonang/c645e2aa3a4fe313269afc1c39c8a05d to your computer and use it in GitHub Desktop.
Save oikonang/c645e2aa3a4fe313269afc1c39c8a05d to your computer and use it in GitHub Desktop.
Scatterplot with a toggle button using D3.v4
licence: mit

San Francisco crime per District

This scatterplot is a representation of the change in number of crimes in SanFrancisco over the years. It seems that if we check the correlation in number of crimes between two different crime categories, and then swipe throught the years we can observe weather the SFPD is doing a good job or not by checking how closer the points in the scatterplot come to the beginning of the axes(0,0). The size of the points relate to the total number of crimes in 2003 and 2015 respectively.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Scatterplot with a toggle button</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<!-- <link rel="stylesheet" type="text/css" href="styles/barplot.css"> -->
<style rel="stylesheet" type="text/css">
#scatterplot {
padding: 10px;
}
#scatterplot div#area1{
display: block;
}
#scatterplot .axis path,
#scatterplot .axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
#scatterplot text {
font-size: 12px;
fill: #212121;
font-weight: bold;
}
.axisLabel {
fill: #000 !important;
}
#scatterplot circle {
stroke: #991f00;
stroke-width: 2px;
fill: #E64A19;
}
#scatterplot .axis text {
fill: #000;
font-size: 11px;
}
#scatterplot .title {
font-size: 20px;
}
#scatterplot svg {
padding-left: 100px;
padding-bottom: 30px;
padding-top: 20px;
}
#scatterplot button {
background-color:#f2f2f2;
text-align:center;
border-radius: 5px;
font-size: 20px;
font-weight: bold;
}
#scatterplot button:hover {
background-color: #b3b3b3;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<div id="scatterplot">
<p>
Click to toggle between <b>2003</b> to <b>2015</b> data: <button>Change Year</button>
</p>
<div id="scatterSvg">
</div>
</div>
<script type="text/javascript" src="js/d3-tip.js"></script>
<script type="text/javascript">
//JS Object used to switch between 2003 and 2015 data using a simple button
function yearSwitcherConstructor(year) {
this.currentYear = year;
this.prostitutionAttr = "count_pros_"+year;
this.vehicleAttr = "count_veh_"+year;
this.totalAttr = "count_tot_"+year;
}
//Load default 2003 data
currentYear = 2003;
var yearSwitcher = new yearSwitcherConstructor(currentYear);
console.log(yearSwitcher);
function loadScatterplot() {
//Load total data from csv
d3.csv("total.csv", function(data) {
dataset = data;
//Width and height
var w = 1000;
var h = 450;
var padding = 30;
//Create scaled x
var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return +d[yearSwitcher.prostitutionAttr];})]) // from 0 to maximum value of input(x)
.range([padding, w - padding * 2]); //from padding to the number of pixels declared in width - pad in order to avoid the edges
//Create scaled y
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return +d[yearSwitcher.vehicleAttr]; })]) // from 0 to maximum value of input(y)
.range([h - padding, padding]); //from height - padding to the number of pixels declared in pad in order to avoid the edges and turn y upside down
//Create scaled r(radius) of the scatter points
var rScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return +d[yearSwitcher.totalAttr]; })]) // from 0 to maximum value of input(y)
.range([2, 30]); // Size of points
//Define X axis
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
//Define Y axis
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
//Create SVG element
var svg = d3.select("#scatterSvg")
.append("svg")
.attr("width", w)
.attr("height", h);
//Define clipping path
svg.append("clipPath") //Make a new clipPath
.attr("id", "chart-area") //Assign an ID
.append("rect") //Within the clipPath, create a new rect
.attr("x", padding)
.attr("y", padding)
.attr("width", w - padding * 3)
.attr("height", h - padding *2);
//Create circles
svg.append("g")
.attr("id", "circles")
.attr("clip-path", "url(#chart-area)")
.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(+d[yearSwitcher.prostitutionAttr]);
})
.attr("cy", function(d) {
return yScale(+d[yearSwitcher.vehicleAttr]);
})
.attr("r", function(d) {
return rScale(+d[yearSwitcher.totalAttr]);
});
//Create labels
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d.PdDistrict;
})
.attr("x", function(d) {
return xScale(+d[yearSwitcher.prostitutionAttr]);
})
.attr("y", function(d) {
return yScale(+d[yearSwitcher.vehicleAttr]);
});
//Create X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
// Text label for the X axis
svg.append("text")
.attr("transform","translate(" + w/2 + ", " + (h+10) + ")")
.style("text-anchor", "middle")
.text("PROSTITUTION")
.classed("axisLabel",true);
//Create Y axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
// Text label for the Y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - padding)
.attr("x",0 - (h / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("VEHICLE THEFT")
.classed("axisLabel",true);
// Text for the title of the plot
svg.append("text")
.attr("transform","translate(" + w/2 + ",0)")
.style("text-anchor","middle")
.text("Correlation of San Francisco crimes in "+currentYear)
.classed("title",true);
//////////////////////////////////////On click update with new data////////////////////////////////////
d3.select("#scatterplot button").on("click", function(){
if (currentYear==2003)
currentYear = 2015;
else
currentYear = 2003;
yearSwitcher = new yearSwitcherConstructor(currentYear);
//Update all circles
svg.selectAll("circle")
.data(dataset)
.transition()
.duration(1000)
.attr("cx", function(d) {
return xScale(+d[yearSwitcher.prostitutionAttr]);
})
.attr("cy", function(d) {
return yScale(+d[yearSwitcher.vehicleAttr]);
})
.attr("r", function(d) {
return rScale(+d[yearSwitcher.totalAttr]);
});
//Update label's position
svg.selectAll("text")
.data(dataset)
.transition()
.duration(1000)
.attr("x", function(d) {
return xScale(+d[yearSwitcher.prostitutionAttr]);
})
.attr("y", function(d) {
return yScale(+d[yearSwitcher.vehicleAttr]);
});
//Update title
svg.selectAll(".title")
.text("Correlation of San Francisco crimes in "+currentYear);
});
});
}
loadScatterplot();
</script>
</body>
</html>
PdDistrict count_veh_2003 count_pros_2003 count_tot_2003 count_veh_2015 count_pros_2015 count_tot_2015
BAYVIEW 2121 11 15739 985 7 14711
CENTRAL 1193 70 13622 552 44 18565
INGLESIDE 2319 5 14008 1368 5 13414
MISSION 2063 713 21163 1198 66 18542
NORTHERN 1879 581 18975 945 42 20092
PARK 1207 2 8219 640 1 9341
RICHMOND 1081 15 7692 561 9 9082
SOUTHERN 1426 18 25692 795 96 30095
TARAVAL 1665 10 11329 789 81 11966
TENDERLOIN 371 527 12737 113 23 10735
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment