forked from mattykuch's block: Linked Charts (Line and Bar) with D3.js
Last active
March 9, 2017 04:47
-
-
Save Thanaporn-sk/5b9b0c9d8d8dc66e2b245ead8ae33f63 to your computer and use it in GitHub Desktop.
Linked Charts (Line and Bar) with D3.js
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
license: mit |
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
//Store width, height and margin in variables | |
var wLine = 550; | |
var hLine = 500; | |
var marginLine = {top: 40, right: 10, bottom: 20, left: 50}; | |
//Set up date formatting and years | |
var dateFormat = d3.time.format("%Y"); | |
// Scale the width and height | |
var xScaleLine = d3.time.scale() | |
.range([ marginLine.left, wLine - marginLine.right - marginLine.left ]); | |
var yScaleLine = d3.scale.linear() | |
.range([ marginLine.top, hLine - marginLine.bottom]); | |
// Creat Axes i.e. xAxis and yAxis | |
var xAxisLine = d3.svg.axis() | |
.scale(xScaleLine) | |
.orient("bottom") | |
.ticks(5) | |
.tickFormat(function(d) { | |
return dateFormat(d); | |
}); | |
var yAxisLine = d3.svg.axis() | |
.scale(yScaleLine) | |
.orient("left"); | |
// Setting x position for line labels | |
var xLabelLine = wLine - marginLine.right - marginLine.left; | |
// Configure line generator | |
var line = d3.svg.line() | |
.x(function(d) { | |
return xScaleLine(dateFormat.parse(d.year)); // come back here and replace "year" | |
}) | |
.y(function(d) { | |
return yScaleLine(+d.amount); // come back here and replace "amount" | |
}) | |
//Create an empty svg | |
var linechart = d3.select("#area1") | |
.append("svg") | |
.attr("width", wLine) | |
.attr("height", hLine); | |
var dataset; // This is a Global variable | |
var activeDistrict; // Will be used for linked hovering | |
// Load in csv data | |
d3.csv("div9.csv", function(data) { | |
// Create new array of all years in timeline for linechart. Will be referenced later | |
var years = [ "2011", "2012", "2013", "2014", "2015"]; | |
//Make dataset an empty array (for now) to hold our restructured dataset | |
dataset = []; | |
// Loop once for each row in data | |
for (var i=0; i < data.length; i++) { | |
//Create a new object with the district's name and empty array | |
dataset[i] = { | |
district: data[i].district, | |
rate: [] | |
}; | |
//Loop through all the years | |
for (var j = 0; j < years.length; j++) { | |
//If value is empty | |
if (data[i][years[j]]) { | |
//Add a new object to the Div 9 rate data array | |
//for that district | |
dataset[i].rate.push({ | |
year: years[j], | |
amount: data[i][years[j]] | |
}); // end of push( function | |
} //end of if( | |
} // end of for loop for years | |
} // end of for loop for data | |
// Set scale domains | |
xScaleLine.domain([ | |
d3.min(years, function(d) { | |
return dateFormat.parse(d); | |
}), | |
d3.max(years, function(d) { | |
return dateFormat.parse(d); | |
}) | |
]); | |
yScaleLine.domain([ | |
d3.max(dataset, function(d) { | |
return d3.max(d.rate, function(d) { | |
return +d.amount; | |
}); | |
}), | |
0 | |
]); | |
// Make a group for each district | |
var groups = linechart.selectAll("g") | |
.data(dataset) | |
.enter() | |
.append("g") | |
.classed("national", function(d) { | |
if (d.district == "UGANDA") return true; | |
else return false; | |
}) | |
.on("mouseover", function(d) { | |
activeDistrict = d.district; | |
// Setting positio for the district label | |
var xPosition = wLine/2 + 35; | |
var yPosition = marginLine.top - 10; | |
linechart.append("text") | |
.attr("id", "hoverLabel") | |
.attr("x", xPosition) | |
.attr("y", yPosition) | |
.attr("text-anchor", "start") | |
.attr("font-family", "ff-nuvo-sc-web-pro-1,ff-nuvo-sc-web-pro-2, sans-serif") | |
.attr("font-size", "20px") | |
.text( activeDistrict); | |
d3.selectAll("rect") | |
.classed("barLight", function(d) { | |
if ( d.district == activeDistrict) return true; | |
else return false; | |
}); | |
}) // end of .on mouseover | |
.on("mouseout", function() { | |
d3.select("#hoverLabel").remove(); | |
d3.selectAll("rect") | |
.attr("class", "barBase"); | |
}) // end of .on mouseout | |
// Append a title with the district name (for easy tooltips) | |
groups.append("title") | |
.text(function(d) { | |
return d.district; | |
}); | |
//Within each group, create a new line/path, | |
//binding just the div9 rate data to each one | |
groups.selectAll("path") | |
.data(function(d) { | |
return [ d.rate ]; | |
}) | |
.enter() | |
.append("path") | |
.attr("class", "line") | |
.attr("d", line); | |
//Axes | |
linechart.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + (hLine - marginLine.bottom) + ")") | |
.call(xAxisLine); | |
linechart.append("g") | |
.attr("class", "y axis") | |
.attr("transform", "translate(" + (marginLine.left) + ",0)") | |
.call(yAxisLine) | |
.append("text") | |
.attr("x", 0 - marginLine.left) | |
.attr("y", marginLine.top - 10) | |
.style ("text-anchor", "start") | |
.text("% of candidates who obtained a Division 9 in "); | |
//Labels for highlighted lines - probably better to wrap these into the line elements themselves | |
//with some logic for selecting the ones you want to highlight? Use anonymous function to match objects for highlighting? | |
//National label | |
linechart.append("text") | |
.attr("transform", "translate(" + xLabelLine + ", " + yScaleLine(data[20][years[4]]) + ")") | |
.attr("dy", ".15em") | |
.attr("dx", ".25em") | |
.attr("text-anchor", "start") | |
.attr("class","labelNation") | |
.text( + data[20][years[4]] ); | |
});// end of d3.csv( | |
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
//Store width, height and margin in variables | |
var w = 600; | |
var h = 500; | |
var margin = {top: 40, right: 10, bottom: 20, left: 50}; | |
// Scale the width and height | |
var xScale = d3.scale.linear() | |
.range([0,w - margin.right - margin.left]); | |
var yScale = d3.scale.ordinal() | |
.rangeRoundBands([margin.top, h - margin.bottom],0.2); | |
// Creat Axes i.e. xAxis and yAxis | |
var xAxis = d3.svg.axis() | |
.scale(xScale) | |
.orient("bottom"); | |
var yAxis = d3.svg.axis() | |
.scale(yScale) | |
.orient("left"); | |
// Create SVG | |
var barchart = d3.select("#area2") | |
.append("svg") | |
.attr("width", w) | |
.attr("height", h); | |
// Entering data | |
d3.csv("div9.csv", function(data) { | |
data.sort(function(a, b) { | |
return d3.descending(+a.avg, +b.avg) | |
}); | |
//Setting a dynamic domain for the xScale based on Data | |
xScale.domain([5 | |
/* d3.min(data, function(d) { | |
return +d.avg; })*/, | |
d3.max(data, function(d) { | |
return +d.avg; | |
}) ]); | |
//Setting a dynamic domain for the yScale based on Data | |
yScale.domain(data.map(function(d) { return d.district; } )); | |
//Rendering the xAxis | |
barchart.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(" + (margin.left + 65) + "," + (h - margin.top + 20) + ")") | |
.call(xAxis); | |
//Rendering the yAxis | |
barchart.append("g") | |
.attr("class", "y axis") | |
.attr("transform", "translate(" + (margin.left + 65) + ",0)") // Moving the axis to fit in district names | |
.call(yAxis) | |
.append("text") | |
.attr("x", margin.left - 65) | |
.attr("y", margin.top - 5) | |
.style("font-size", "14") | |
.style("text-anchor", "start") | |
.text("Average failure rate (in %) over the last 5 years by district"); | |
// Rendering the rectangles | |
var rects = barchart.selectAll("rect") | |
.data(data) | |
.enter() | |
.append("rect"); | |
rects.attr("x", margin.left + 70) // Moving the x so district name can fit | |
.attr("y", function(d, i) { | |
return yScale(d.district); | |
}) | |
.attr("width", function(d) { | |
return xScale(d.avg); | |
}) | |
.attr("height",yScale.rangeBand) | |
.attr("class", "barBase") | |
.append("title") | |
.text(function(d) { | |
return d.district + "'s failure rate over the last 5 years is " + d.avg + "%"; | |
}); | |
//rollover functionality | |
barchart.selectAll("rect") | |
.on("mouseover", function(d) { | |
activeDistrict = d.district; | |
linechart.selectAll("g") | |
.each(function(d) { | |
if(d){ | |
if ( d.district == activeDistrict ){ | |
// console.log(d3.select(this).select("path")); | |
d3.select(this).select("path").classed("pathLight", true); | |
var xPosition = wLine/2 + 35; | |
var yPosition = marginLine.top - 10; | |
linechart.append("text") | |
.attr("id", "hoverLabel") | |
.attr("x", xPosition) | |
.attr("y", yPosition) | |
.attr("text-anchor", "start") | |
.attr("font-family", "ff-nuvo-sc-web-pro-1,ff-nuvo-sc-web-pro-2, sans-serif") | |
.attr("font-size", "20px") | |
.text( activeDistrict); | |
return true; | |
} | |
else{ | |
return false; | |
} | |
} | |
}) | |
}) | |
.on("mouseout", function() { | |
d3.selectAll("path") | |
.attr("class", "pathBase"); | |
d3.select("#hoverLabel").remove(); | |
}); | |
}); // end of d3.csv | |
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
rank | district | 2011 | 2012 | 2013 | 2014 | 2015 | avg | div1 | |
---|---|---|---|---|---|---|---|---|---|
1 | BUGIRI | 9.68 | 10.27 | 24.90 | 23.74 | 16.69 | 17.66 | 0.71 | |
2 | BUKWO | 7.04 | 7.74 | 20.19 | 20.76 | 21.59 | 15.68 | 12.65 | |
3 | BUNDIBUGYO | 11.09 | 10.50 | 20.03 | 17.20 | 18.68 | 15.67 | 15.34 | |
4 | BULAMBULI | 13.89 | 13.37 | 15.41 | 15.04 | 15.32 | 14.65 | 12.39 | |
5 | SIRONKO | 8.66 | 10.33 | 20.38 | 13.08 | 16.96 | 13.93 | 15.89 | |
6 | BUSIA | 6.70 | 10.44 | 17.91 | 12.46 | 19.80 | 13.54 | 13.66 | |
7 | MANAFWA | 9.53 | 11.37 | 16.90 | 14.48 | 13.71 | 13.31 | 14.03 | |
8 | BUYENDE | 10.90 | 8.64 | 12.47 | 14.84 | 18.69 | 13.20 | 11.01 | |
9 | MBALE | 7.40 | 10.59 | 14.56 | 13.63 | 16.60 | 12.64 | 9.15 | |
10 | ADJUMANI | 6.98 | 9.33 | 15.85 | 16.95 | 12.68 | 12.36 | 9.71 | |
11 | BUTALEJA | 6.82 | 7.95 | 13.60 | 14.22 | 18.23 | 12.34 | 7.60 | |
12 | BUDUDA | 9.90 | 13.79 | 15.96 | 10.63 | 11.34 | 12.20 | 8.64 | |
13 | KWEEN | 7.84 | 8.74 | 16.30 | 11.15 | 13.83 | 11.57 | 7.79 | |
14 | IGANGA | 7.46 | 9.02 | 14.52 | 11.77 | 14.36 | 11.52 | 5.98 | |
15 | BULIISA | 2.10 | 3.50 | 16.08 | 12.32 | 18.84 | 11.30 | 8.51 | |
16 | NAKAPIRIPIRIT | 7.93 | 5.55 | 16.28 | 9.10 | 16.70 | 11.11 | 7.69 | |
17 | MAYUGE | 5.17 | 6.08 | 14.13 | 11.64 | 15.13 | 10.80 | 8.80 | |
18 | NEBBI | 7.10 | 11.43 | 14.22 | 10.50 | 10.32 | 10.78 | 8.39 | |
19 | ZOMBO | 6.67 | 8.80 | 18.97 | 10.31 | 9.14 | 10.78 | 8.65 | |
20 | YUMBE | 8.57 | 12.27 | 13.67 | 9.00 | 9.67 | 10.67 | 7.74 | |
21 | UGANDA | 4.27 | 5.04 | 9.05 | 7.17 | 9.62 | 7.06 | 0 |
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> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>A Profile on Failure in O'level: Highlighting 20 districts that have consistently performed poorly over the last 5 years (2011 - 2015)</title> | |
<!-- Custom CSS styles --> | |
<link href="style.css" rel="stylesheet" type="text/css" > | |
</head> | |
<body> | |
<div class="container"> | |
<h2> A Profile on Failure in O'level: Highlighting 20 districts that have consistently performed poorly over the last 5 years (2011 - 2015)</h2> | |
<h4> .... </h4> | |
<div id="area1"> <!-- barchart container --> | |
</div> | |
<div id="area2"> <!-- barchart2 container --> | |
</div> | |
</div> | |
<div id="footer"> | |
<strong>Source</strong> : www.data.ug | |
</div> | |
<!-- JS Libraries --> | |
<!--<script src="d3.js" charset="utf-8"></script>--> | |
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script> | |
<!-- Custom JS code --> | |
<script src="area1.js"></script> | |
<script src="area2.js"></script> | |
</body> | |
</html> |
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
.container { | |
width: 1200px; | |
height: 700px; | |
margin: 25px auto 25px auto; | |
padding: 50px 50px 50px 50px; | |
background-color: white; | |
box-shadow: 0 0 20px #ccc; | |
} | |
#footer { | |
border-top: 1px solid silver; | |
color: #888888; | |
font-size: 1.25rem; | |
text-align: center; | |
margin-top: 1rem; | |
padding: 0.5rem; | |
} | |
body { | |
background-color: #fff; | |
font-family: "adelle-1","adelle-2", constantia, cambria, Georgia, serif; | |
font-size:14px; | |
margin: 18px 0 0 30px; | |
} | |
h1 { | |
font-size: 24px; | |
margin: 0; | |
color: #5387bd; | |
font-weight: normal; | |
} | |
h2 { | |
font-weight: normal; | |
color: #808080; | |
} | |
p { | |
color: #808080; | |
} | |
svg { | |
background-color: white; | |
} | |
#intro { | |
width: 740px; | |
line-height: 150%; | |
} | |
#area1 { | |
display: inline-block; | |
/* float: right;*/ | |
} | |
#area2 { | |
display: inline-block; | |
/* float: left;*/ | |
} | |
/*#footer { | |
clear: both; | |
width: 760px; | |
line-height: 150%; | |
font-size: 12px; | |
}*/ | |
path { | |
stroke: #888; | |
stroke-width: 2; | |
opacity: 0.2; | |
-moz-transition: all 0.1s; | |
-o-transition: all 0.1s; | |
-webkit-transition: all 0.1s; | |
transition: all 0.1s; | |
cursor: pointer; | |
fill: none; | |
} | |
g.linklight path{ | |
stroke: #ff0000; | |
opacity: 1; | |
} | |
g.highlight path { | |
stroke: #cfa63e; | |
stroke-width: 4; | |
opacity: 1; | |
} | |
g.national path { | |
stroke: #5387bd; | |
stroke-width: 4; | |
opacity: 1; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #BCBCBC; | |
stroke-width: 1; | |
shape-rendering: crispEdges; | |
} | |
.axis path { | |
opacity: 1; | |
} | |
.line:hover, .pathBase:hover { | |
stroke: black; | |
opacity: 1; | |
} | |
.pathBase { | |
stroke: #888; | |
opacity: 0.2; | |
} | |
.pathLight { | |
stroke: black; | |
opacity: 1; | |
} | |
#hoverlabel { | |
font-family: "ff-nuvo-sc-web-pro-1","ff-nuvo-sc-web-pro-2", sans-serif; | |
fill: #496d64; | |
font-size: 15px; | |
color: #808080; | |
text-anchor: start; | |
} | |
.axis text { | |
font-family: "ff-nuvo-sc-web-pro-1","ff-nuvo-sc-web-pro-2", sans-serif; | |
font-size: 14px; | |
letter-spacing: 0.5px; | |
} | |
.linelabel { | |
font-family: "ff-nuvo-sc-web-pro-1","ff-nuvo-sc-web-pro-2", sans-serif; | |
fill: #333; | |
font-size: 12px; | |
text-anchor: start; | |
opacity: 0.5; | |
} | |
.labelNation { | |
font-family: "ff-nuvo-sc-web-pro-1","ff-nuvo-sc-web-pro-2", sans-serif; | |
fill: #5387bd; | |
font-size: 12px; | |
text-anchor: start; | |
} | |
.labelDistrict { | |
font-family: "ff-nuvo-sc-web-pro-1","ff-nuvo-sc-web-pro-2", sans-serif; | |
fill: #cfa63e; | |
font-size: 12px; | |
text-anchor: start; | |
} | |
.path.active { | |
stroke: black; | |
opacity: 1; | |
} | |
/* Bar specific CSS */ | |
rect:hover { | |
fill: #2E2E31; | |
} | |
.barBase { | |
fill: #5288BE; | |
} | |
.barLight { | |
fill: #2E2E31; | |
} | |
.axisBar text { | |
font-family: "ff-nuvo-sc-web-pro-1","ff-nuvo-sc-web-pro-2", sans-serif; | |
font-size: 11px; | |
} | |
.axisBarTitle { | |
font-family: "ff-nuvo-sc-web-pro-1","ff-nuvo-sc-web-pro-2", sans-serif; | |
font-size: 12px; | |
} | |
.y.axisBar path, | |
.y.axisBar line { | |
opacity: 0; | |
cursor: auto; | |
} | |
.x.axisBar path, | |
.x.axisBar line { | |
opacity: 0.2; | |
cursor: auto; | |
} | |
.barlabel { | |
font-family: "ff-nuvo-sc-web-pro-1","ff-nuvo-sc-web-pro-2", sans-serif; | |
font-size:11px; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment