Last active
August 9, 2018 23:08
-
-
Save mikelotis/fa824557ccbb76051b0ce7e382723f4a to your computer and use it in GitHub Desktop.
Edmonton - 311 Requests - Joy Plot
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
width: 720 | |
height: 660 |
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
{ | |
"name": "data", | |
"children": [ | |
{ | |
"name": 2014, | |
"children": [ | |
{ | |
"name": "Jan", | |
"value": 14289 | |
}, | |
{ | |
"name": "Feb", | |
"value": 2054 | |
}, | |
{ | |
"name": "Mar", | |
"value": 4951 | |
}, | |
{ | |
"name": "Apr", | |
"value": 4832 | |
}, | |
{ | |
"name": "May", | |
"value": 4676 | |
}, | |
{ | |
"name": "Jun", | |
"value": 5543 | |
}, | |
{ | |
"name": "Jul", | |
"value": 6634 | |
}, | |
{ | |
"name": "Aug", | |
"value": 4415 | |
}, | |
{ | |
"name": "Sep", | |
"value": 3746 | |
}, | |
{ | |
"name": "Oct", | |
"value": 3040 | |
}, | |
{ | |
"name": "Nov", | |
"value": 2642 | |
}, | |
{ | |
"name": "Dec", | |
"value": 4936 | |
} | |
] | |
}, | |
{ | |
"name": 2015, | |
"children": [ | |
{ | |
"name": "Jan", | |
"value": 5195 | |
}, | |
{ | |
"name": "Feb", | |
"value": 5062 | |
}, | |
{ | |
"name": "Mar", | |
"value": 7702 | |
}, | |
{ | |
"name": "Apr", | |
"value": 5323 | |
}, | |
{ | |
"name": "May", | |
"value": 5212 | |
}, | |
{ | |
"name": "Jun", | |
"value": 5284 | |
}, | |
{ | |
"name": "Jul", | |
"value": 4861 | |
}, | |
{ | |
"name": "Aug", | |
"value": 3922 | |
}, | |
{ | |
"name": "Sep", | |
"value": 3657 | |
}, | |
{ | |
"name": "Oct", | |
"value": 3069 | |
}, | |
{ | |
"name": "Nov", | |
"value": 2602 | |
}, | |
{ | |
"name": "Dec", | |
"value": 1788 | |
} | |
] | |
}, | |
{ | |
"name": 2016, | |
"children": [ | |
{ | |
"name": "Jan", | |
"value": 2368 | |
}, | |
{ | |
"name": "Feb", | |
"value": 3561 | |
}, | |
{ | |
"name": "Mar", | |
"value": 2815 | |
}, | |
{ | |
"name": "Apr", | |
"value": 4199 | |
}, | |
{ | |
"name": "May", | |
"value": 4214 | |
}, | |
{ | |
"name": "Jun", | |
"value": 5182 | |
}, | |
{ | |
"name": "Jul", | |
"value": 5269 | |
}, | |
{ | |
"name": "Aug", | |
"value": 4805 | |
}, | |
{ | |
"name": "Sep", | |
"value": 3591 | |
}, | |
{ | |
"name": "Oct", | |
"value": 2887 | |
}, | |
{ | |
"name": "Nov", | |
"value": 2476 | |
}, | |
{ | |
"name": "Dec", | |
"value": 1923 | |
} | |
] | |
}, | |
{ | |
"name": 2017, | |
"children": [ | |
{ | |
"name": "Jan", | |
"value": 3160 | |
}, | |
{ | |
"name": "Feb", | |
"value": 3194 | |
}, | |
{ | |
"name": "Mar", | |
"value": 6309 | |
}, | |
{ | |
"name": "Apr", | |
"value": 6894 | |
}, | |
{ | |
"name": "May", | |
"value": 10683 | |
}, | |
{ | |
"name": "Jun", | |
"value": 11066 | |
}, | |
{ | |
"name": "Jul", | |
"value": 8365 | |
}, | |
{ | |
"name": "Aug", | |
"value": 8092 | |
}, | |
{ | |
"name": "Sep", | |
"value": 6859 | |
}, | |
{ | |
"name": "Oct", | |
"value": 6156 | |
}, | |
{ | |
"name": "Nov", | |
"value": 5897 | |
}, | |
{ | |
"name": "Dec", | |
"value": 7784 | |
} | |
] | |
}, | |
{ | |
"name": 2018, | |
"children": [ | |
{ | |
"name": "Jan", | |
"value": 6103 | |
}, | |
{ | |
"name": "Feb", | |
"value": 8713 | |
}, | |
{ | |
"name": "Mar", | |
"value": 10029 | |
}, | |
{ | |
"name": "Apr", | |
"value": 9436 | |
}, | |
{ | |
"name": "May", | |
"value": 10612 | |
}, | |
{ | |
"name": "Jun", | |
"value": 11233 | |
}, | |
{ | |
"name": "Jul", | |
"value": 5524 | |
} | |
] | |
} | |
] | |
} |
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
svg { | |
display: block; | |
margin: 0 auto; | |
background-color: whitesmoke; | |
margin-top: 30px; | |
} | |
text{ | |
font: 1em 'Roboto', sans-serif; | |
} | |
.axis .domain { | |
display: none; | |
} | |
.axis--x text, .text--title{ | |
fill: #999; | |
} | |
.text--title { | |
font-size: 1.2em; | |
} | |
.axis--x line { | |
stroke: #aaa; | |
} | |
.axis--year .tick line { | |
display: none; | |
} | |
.axis--year text { | |
font-size: 1.1em; | |
fill: #777; | |
} | |
.axis--year .tick:nth-child(odd) text { | |
fill: #222; | |
} | |
.line { | |
fill: none; | |
stroke: whitesmoke; | |
stroke-width: 1.5px; | |
} | |
.area { | |
fill: #448cab; | |
opacity: 0.9; | |
} | |
.year:nth-child(odd) .area { | |
fill: #5ca3c1; | |
} |
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"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title>Document</title> | |
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet"> | |
<link rel="stylesheet" href="index.css"> | |
</head> | |
<body> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.5.0/d3.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script> | |
<script src="index.js" lang="babel" type="text/babel"></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
const log = console.log; | |
const margin = {top: 150, right: 0, bottom: 20, left: 80}; | |
const width = 700 - margin.left - margin.right; | |
const height = 600 - margin.top - margin.bottom; | |
// define svg | |
const svg = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append('g') | |
.attr('transform', `translate(${margin.left},${margin.top})`); | |
// load pre-processed data | |
d3.json("311-Flattened-(July-20-2018).json") | |
.then(ridgelinePlot); | |
// Creates the ridgeline plot/ joy plot | |
function ridgelinePlot(responses) { | |
// accessors and pre-processed data | |
const data = responses.children; | |
const accessorName = d => d.name; | |
const accesorValue = d => d.value; | |
const overlap = 1.5; | |
const allValues = data.map(d => { return d.children.map(accesorValue); }) | |
.reduce((acc, curVal) => acc.concat(curVal), []); | |
// chart x axis | |
const xScale = d3.scaleBand().domain(data[0].children.map(accessorName)).range([0, width]); | |
const xValue = d => xScale(accessorName(d)); | |
const xAxis = d3.axisBottom(xScale); | |
// chart y axis | |
const yearScale = d3.scaleBand().domain(data.map(accessorName)).range([height, 0]); | |
const yearValue = d => yearScale(accessorName(d)); | |
const yearAxis = d3.axisLeft(yearScale); | |
// area scale | |
const areaChartHeight = (1 + overlap) * (height / yearScale.domain().length); | |
const yScale = d3.scaleLinear().domain(d3.extent(allValues)).range([areaChartHeight, 0]); | |
const yValue = d => yScale(accesorValue(d)); | |
// area and line generators | |
const area = d3.area().x(xValue).y1(yValue).curve(d3.curveBasis); | |
const line = area.lineY1(); | |
// ordered to get a pleasing overlapping effect | |
// However 2016 area is still behind 2017 area - d3 raise solves the issue | |
// Further learning required to avoid this | |
// https://beta.observablehq.com/@mbostock/d3-ridgeline-plot | |
// https://beta.observablehq.com/@pstuffa/nyc-building-permits-api-neighborhood-trends | |
const order = [2016, 2015, 2014, 2018, 2017].map(d => data.filter(p => p.name == d)[0]); | |
// year groups | |
const gYear= svg.append('g').attr("class", "years") | |
.selectAll(".year").data(order) | |
.enter().append('g') | |
.attr("class",d => "year year--" + d.name) | |
.attr("transform", (d) => { | |
const ty = yearValue(d) - yearScale.bandwidth() - 110; | |
return `translate(0,${ty})`; | |
}); | |
area.y0(yScale(0)); | |
// add x axis | |
svg.append('g').attr("class", "axis axis--x") | |
.attr("transform", `translate(-25,${height - 30})`) | |
.call(xAxis); | |
// add y axis | |
svg.append('g').attr("class", "axis axis--year") | |
.attr("transform", "translate(0,2)") | |
.call(yearAxis); | |
// add area paths | |
gYear.append('path').attr('class', 'area') | |
.datum(d => d.children) | |
.attr('d', area); | |
// add line paths | |
gYear.append('path').attr('class', 'line') | |
.datum(d => d.children) | |
.attr('d', line); | |
// Add title texts | |
svg.append("text") | |
.attr("class", "text--title") | |
.attr("x", 400) | |
.attr("y", -60) | |
.html("311 Requests"); | |
svg.append("text") | |
.attr("class", "text--title") | |
.attr("x", 400) | |
.attr("y", -38) | |
.html("Yearly Trends"); | |
// gets the desired overlapping effect | |
order.slice(0, 3).forEach(d => { | |
d3.select(`.year--${d.name}`).raise(); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment