Last active
January 4, 2016 01:29
-
-
Save eoiny/8548406 to your computer and use it in GitHub Desktop.
Multi-line Chart with Info
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
date | series1 | series2 | series3 | series4 | series5 | series6 | series7 | series8 | |
---|---|---|---|---|---|---|---|---|---|
2005-01-01 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | |
2005-02-01 | 100.4 | 100.5 | 100.1 | 100.1 | 100.3 | 101.1 | 100.8 | 101.7 | |
2005-03-01 | 100.6 | 100.8 | 99.9 | 100.3 | 100.6 | 101.2 | 101.2 | 101.3 | |
2005-04-01 | 101.3 | 101.6 | 99.7 | 100.9 | 101.2 | 102.2 | 102.4 | 101.5 | |
2005-05-01 | 102 | 102.3 | 99.7 | 101.5 | 101.9 | 102.8 | 103.4 | 101.1 | |
2005-06-01 | 102.9 | 103.4 | 99.6 | 102.6 | 103.1 | 103.5 | 104.2 | 101.5 | |
2005-07-01 | 104.3 | 105 | 100 | 104 | 104.7 | 104.7 | 105.6 | 102 | |
2005-08-01 | 105.9 | 106.6 | 101.5 | 105.6 | 106.2 | 106.4 | 107.3 | 103.5 | |
2005-09-01 | 107.2 | 107.8 | 103.8 | 106.5 | 107.1 | 108.5 | 109.4 | 106 | |
2005-10-01 | 109 | 109.5 | 106.2 | 107.9 | 108.3 | 111.1 | 112 | 108.3 | |
2005-11-01 | 110 | 110.5 | 106.9 | 108.6 | 109.1 | 112.6 | 113.7 | 109.2 | |
2005-12-01 | 111.5 | 112 | 108.3 | 110.3 | 110.7 | 113.7 | 114.9 | 110 | |
2006-01-01 | 111.8 | 112.4 | 108.4 | 110.7 | 111.1 | 113.9 | 115.2 | 109.9 | |
2006-02-01 | 112.6 | 113.1 | 109.1 | 111.2 | 111.6 | 114.9 | 116.4 | 110.5 | |
2006-03-01 | 113.1 | 113.8 | 109 | 111.6 | 112 | 116 | 117.8 | 110.6 | |
2006-04-01 | 114.6 | 115.2 | 111 | 112.7 | 113.2 | 117.9 | 119.4 | 113.4 | |
2006-05-01 | 116.8 | 117.4 | 112.9 | 114.7 | 115.3 | 120.5 | 122.1 | 115.3 | |
2006-06-01 | 119 | 119.7 | 114.7 | 116.4 | 117 | 123.6 | 125.6 | 117.4 | |
2006-07-01 | 121.3 | 122.2 | 115.7 | 118.1 | 118.7 | 127 | 129.9 | 118.2 | |
2006-08-01 | 123.5 | 124.4 | 117.8 | 119.8 | 120.4 | 130.3 | 133.3 | 120.9 | |
2006-09-01 | 125.1 | 125.9 | 119.9 | 121.5 | 122.1 | 131.6 | 134.4 | 123.1 | |
2006-10-01 | 126 | 126.8 | 120.9 | 122.5 | 123 | 132.4 | 135.3 | 123.7 | |
2006-11-01 | 126.1 | 126.9 | 120.7 | 122.9 | 123.4 | 131.9 | 134.6 | 123.4 | |
2006-12-01 | 127.3 | 128.3 | 120.8 | 124 | 124.7 | 133.1 | 136.2 | 123.7 | |
2007-01-01 | 128.4 | 129.3 | 122.5 | 125.6 | 126.4 | 133.4 | 135.7 | 125.9 | |
2007-02-01 | 129.6 | 130.5 | 123.9 | 126.9 | 127.6 | 134.5 | 136.7 | 127.4 | |
2007-03-01 | 129.9 | 130.9 | 123.2 | 127.7 | 128.4 | 133.9 | 136.4 | 126 | |
2007-04-01 | 130.3 | 131.7 | 121.6 | 128.1 | 128.9 | 134 | 137.8 | 123.3 | |
2007-05-01 | 130.2 | 131.5 | 121.7 | 128.7 | 129.4 | 132.7 | 135.9 | 123.1 | |
2007-06-01 | 130.2 | 131.4 | 122.5 | 128.4 | 129.1 | 133.4 | 136.6 | 123.9 | |
2007-07-01 | 130.2 | 131.4 | 123 | 128.5 | 129.2 | 133.3 | 135.9 | 125.4 | |
2007-08-01 | 130.4 | 131.7 | 122.1 | 128.5 | 129.3 | 133.6 | 136.8 | 124.1 | |
2007-09-01 | 130.5 | 132 | 121.5 | 128.8 | 129.7 | 133.5 | 136.9 | 123.4 | |
2007-10-01 | 130.1 | 131.4 | 121.5 | 128.3 | 129 | 133.1 | 136.6 | 122.6 | |
2007-11-01 | 130.1 | 131.6 | 120.7 | 128.6 | 129.3 | 132.7 | 136.7 | 121.3 | |
2007-12-01 | 129.5 | 130.8 | 121.3 | 128.4 | 129.1 | 131.2 | 134.1 | 122.6 | |
2008-01-01 | 128.7 | 130.1 | 120.3 | 128.5 | 129.5 | 128.6 | 130.6 | 122.3 | |
2008-02-01 | 127.6 | 128.8 | 120.1 | 127.3 | 128.4 | 127.7 | 128.9 | 123.4 | |
2008-03-01 | 126.6 | 127.7 | 119.5 | 126.3 | 127.3 | 126.9 | 128.2 | 122.2 | |
2008-04-01 | 125.7 | 126.9 | 118.5 | 124.8 | 125.6 | 127.4 | 129.6 | 121.1 | |
2008-05-01 | 124.6 | 126 | 116 | 123.3 | 124.2 | 126.9 | 130.6 | 117.8 | |
2008-06-01 | 123.4 | 125.1 | 113.5 | 122.1 | 122.9 | 125.9 | 130.7 | 114.7 | |
2008-07-01 | 122.5 | 124.3 | 112.4 | 121.4 | 122.2 | 124.4 | 129.3 | 112.9 | |
2008-08-01 | 121.5 | 123.2 | 111.7 | 120.8 | 121.5 | 122.5 | 127.1 | 111.8 | |
2008-09-01 | 120.1 | 121.9 | 109.9 | 120.2 | 120.9 | 119.5 | 123.9 | 109.1 | |
2008-10-01 | 117.7 | 120 | 105.3 | 118.4 | 119.2 | 116 | 121.4 | 103.6 | |
2008-11-01 | 115.7 | 118.2 | 102.1 | 117 | 117.9 | 112.5 | 118.3 | 99.5 | |
2008-12-01 | 113.5 | 116.2 | 99.3 | 114.7 | 115.7 | 110.6 | 116.7 | 97 |
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
/* Normalize */ | |
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, figure, form, fieldset, input, p, blockquote, th, td, legend { | |
margin: 0; | |
padding: 0; | |
} | |
body { | |
font-family: 'Cardo', serif; | |
} | |
p { line-height: 1.4em; margin-bottom: 1.0em; } | |
a { color: #821122; } | |
table { | |
width: 925px; | |
border-collapse: collapse; | |
border-top: 0px solid #ccc; | |
margin-right: 2px; | |
} | |
table td { padding: 15; | |
margin: 0; | |
vertical-align:top; | |
padding-top: 40px; | |
} | |
#chart { | |
min-height: 500px; | |
width: 960px; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.dot { | |
stroke: #000; | |
} | |
.line { | |
fill: none; | |
stroke: #e2e2e2; | |
stroke-width: 1.5px; | |
} | |
.lineOver { | |
fill: none; | |
stroke: orange; | |
stroke-width: 2.5px; | |
} | |
text { | |
font-family: Helvetica, Arial, sans-serif; | |
font-size: 12px; | |
stroke: #000; | |
} | |
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
//create svg container + inner drawing space using the d3 conventional margin | |
var margin = {top: 20, right: 80, bottom: 30, left: 30}, | |
width = 960 - margin.left - margin.right, | |
height = 400 - margin.top - margin.bottom; | |
//create time formatting function | |
var parseDate = d3.time.format("%Y-%m-%d").parse; | |
//create a time scaling function for the x-axis data, from 0 to width of the inner drwg space | |
var x = d3.time.scale() | |
.range([0, width]); | |
//create a linear scaling function for the y-axis data, from height of inner drwg space to 0 | |
var y = d3.scale.linear() | |
.range([height, 0]); | |
//create ordinal scaling function for the colours | |
var color = d3.scale.category10(); | |
//******testing | |
var places = d3.scale.ordinal(); | |
//createe x- & y-axes functions, bring in scaling functions & orientate | |
var xAxis = d3.svg.axis() | |
.scale(x) | |
.orient("bottom"); | |
var yAxis = d3.svg.axis() | |
.scale(y) | |
.orient("left"); | |
//create d3 path generation function | |
var line = d3.svg.line() | |
.interpolate("basis") | |
.x(function(d) { return x(d.date); }) | |
.y(function(d) { return y(d.pindex); }); | |
//create svg drawing container & inner drwg space | |
var svg = d3.select("#chart").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 + ")"); | |
//asynchrous callback function to retrieve data from tsv file | |
d3.tsv("data.tsv", function(error, data) { | |
//look at the 1st data element, gets the object keys, | |
//data[0] returns the 1st js object, d3.keys functionality looks at eack key:value pair in the object | |
//& returns only the keys, as an array. Then the js array.filter method is applied to each element in the | |
//the array and returns the element as long as it does not equal "date". This array of keys is used to set | |
//the domain of the ordinal scale function. | |
//data is an array of 106 objects in the form: | |
// [{ | |
// series1: "100", | |
// series2: "100", | |
// series3: "100", | |
// series4: "100", | |
// series5: "100", | |
// series6: "100", | |
// series7: "100", | |
// series8: "100", | |
// Date: "2005-01-01", | |
// } ..... 105 other objects for each date value..] | |
// | |
//console.log(data); | |
places.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; })); | |
//iterate thru the js objects & for each object convert the date str into a js date object | |
//& assign it back to the d.date key | |
data.forEach(function(d) { | |
d.date = parseDate(d.date); | |
}); | |
//reorganise data for use by the d3 pattern: i.e. Nesting data | |
//1. apply a function to every element in the ordinal domain i.e. each pindex | |
//2. return an object with 2 key:value pairs | |
//3. end up with an array of 8 objects for each pindex series, consisting of an array | |
// of names and a value, where the value is an array of 106 objects, consisting of a | |
//date and a pindex value: | |
// [{ | |
// name: "series1", | |
// values: [{date: "2005-01-01", | |
// pindex: "100"}, | |
// {date: "2005-02-01" | |
// pindex: "100.4"}, ...etc for all 106 data points i.e. dates | |
// ] | |
// }, | |
// ....+7 more objects for each series | |
// ] | |
// | |
var cities = places.domain().map(function(name) { | |
return { | |
name: name, | |
values: data.map(function(d) { | |
return {date: d.date, pindex: +d[name]}; | |
}) | |
}; | |
}); | |
//console.log(cities); | |
//create an array using d3.extent, & use it to set the x-scale fuction's input domain, | |
// returns an array of two elements - min & max dates | |
x.domain(d3.extent(data, function(d) { return d.date; })); | |
//as with x-axis, create an array to setup the y-scale function input domain, | |
//as this is a nested array we need the max & min values for the entire data set | |
//but also for each individual series | |
y.domain([ | |
d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.pindex; }); }), | |
d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.pindex; }); }) | |
]); | |
//create a svg group element for the x axis & for the y axis, append labels | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis); | |
svg.append("g") | |
.attr("class", "y axis") | |
.call(yAxis) | |
.append("text") | |
.attr("transform", "rotate(-90)") | |
.attr("y", 6) | |
.attr("dy", ".71em") | |
.style("text-anchor", "end") | |
.text("House Price Index¹"); | |
//create an svg g-element for each of the 8 series | |
var city = svg.selectAll(".city") | |
.data(cities) | |
.enter().append("g") | |
.attr("class", "city"); | |
//and generate a path for each series using the line function | |
city.append("path") | |
.attr("class", "line") | |
.attr("d", function(d) { return line(d.values); }) | |
//****testing | |
// .style("stroke", "lightgrey") | |
//...testing | |
//.style("stroke-dasharray", (3,3) ) | |
.style("stroke", function(d){ | |
if (d.name === "series1") {return "black"} | |
else {return "lightgrey"} | |
;}) | |
//set an mouseover event listener for when the mouseover occurs on any give path g-element | |
//using d3.select(this) | |
//and also select the corresponding text g-element, | |
//in both selections make path and text go orange | |
.on("mouseover", function(d){ | |
//console.log(d.name); | |
d3.select(this) | |
.style("stroke", "orange"); | |
//use the following to select the specific path g-element & bring it to the top | |
//of the svg drawing container | |
this.parentNode.parentNode.appendChild(this.parentNode); | |
//selection for grabbing corresponding text | |
d3.select('#text-' + d.name) | |
.attr("visibility","visible") | |
.style("stroke", "orange") | |
.text(function(d) {return d.name;}); | |
}) | |
//when mouseout occurs revert the path to grey & the text to invisible | |
.on("mouseout", function(d){ | |
d3.select(this) | |
.style("stroke", function(d){ | |
if (d.name === "series1") {return "black"} | |
else {return "lightgrey"} | |
;}) | |
d3.select('#text-' + d.name) | |
.attr("visibility","hidden") | |
}) | |
//create an id for the path DOM element that has the name of the data series in it | |
.attr("id", function(d, i) { return "path-" + d.name; }) | |
; | |
//create the text label for each data series, | |
//find the position the apppend it to at the end each path using the array.length method | |
city.append("text") | |
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) | |
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.pindex) + ")"; }) | |
.attr("x", 5) | |
.attr("dy", ".35em") | |
//.attr("visibility","hidden") | |
//****testing | |
.attr("visibility",function(d){ | |
if (d.name === "series1") {return "visible"} | |
else {return "hidden"} | |
;}) | |
//as with the path mouseover event above, set an event listener for the text. | |
.on("mouseover", function(d){ | |
d3.select('#path-' + d.name) | |
.style("stroke", "orange") | |
this.parentNode.parentNode.appendChild(this.parentNode); | |
d3.select(this) | |
.attr("visibility", "visible") | |
.style("stroke", "orange"); | |
}) | |
.on("mouseout", function(d) { | |
d3.select('#path-' + d.name) | |
//.style("stroke", "lightgrey") | |
.style("stroke", function(d){ | |
if (d.name === "series1") {return "black"} | |
else {return "lightgrey"} | |
;}) | |
d3.select(this) | |
.attr("visibility",function(d){ | |
if (d.name == "series1") {return "visible"} | |
else {return "hidden"} | |
;}) | |
}) | |
.text(function(d) { return d.name; }) | |
.attr("id", function(d, i) { return "text-" + d.name; }); | |
//filter the "series1" series | |
//and append "points of interest" i.e. circles visible at points: 1.max, 2.min, 3.first, 4.last, | |
//& set them as mouseover points for further explanations | |
var filtered = city | |
.filter(function(d){ | |
return d.name == "series1" | |
}) | |
filtered | |
.selectAll('circle') | |
.data( | |
function(d){return d.values} | |
) | |
.enter().append('circle') | |
.attr({ | |
cx: function(d,i){ | |
return x(d.date) | |
}, | |
cy: function(d,i){ | |
return y(d.pindex) | |
}, | |
r: 5 | |
}) | |
//at this point all the data points have circles appended | |
//but need to set all visibility attrs to "hidden" | |
//except for : 1.max, 2.min, 3.first, 4.last | |
/*.attr("visibility", function(f) { | |
// if (d.pindex == d3.max(filtered, function(v) {return d.pindex;}) {return "visible"} | |
//if (d.pindex == d3.max(d3.values(filtered))) {return "visible"} | |
if (+f.pindex == d3.max(filtered, function(d,i) {return +d.pindex;})) {return "visible"} | |
// <== max | |
// if (d.pindex == d3.min(filtered) {return "visible"} // <== min | |
else { return "hidden" } // <== Add these | |
;})*/ | |
.style("fill", "orange") | |
//mouseover cirlces | |
.on('mouseover', function(d){ | |
filtered.append("text") | |
.attr({ | |
x: function(dd){ | |
return x(d.date) | |
}, | |
y: function(dd){ | |
return y(d.pindex) | |
}, | |
dx:-3, | |
dy:".35em", | |
"text-anchor":"end" | |
}) | |
.style("fill", "black") | |
.text( | |
function(dd){ | |
var formatDate = d3.time.format("%d-%B-%Y") | |
return 'Date:' + formatDate(d.date) + ',index:' + d.pindex | |
} | |
) | |
}) | |
.on('mouseout', function(dd){ | |
d3.select(this.parentElement) | |
.selectAll('text').remove() | |
}) | |
; | |
}); |
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
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<html> | |
<head> | |
<title>House Price Index</title> | |
<link rel="stylesheet" type="text/css" href="houses.css" /> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
</head> | |
<body> | |
<table class="left"> | |
<tr> | |
<td><div id="chart"></div> </td> | |
</tr> | |
</table> | |
<script type="text/javascript" src="houses.js"></script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment