Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Week 9: Stacked Bars Transition
Country Year Age Any method Any modern method Female Sterilization Male Sterilization Pill Injectable IUD Male condom Vaginal barrier methods Implant Other modern methods Any traditional method Rhythm Withdrawal Other traditional methods
Burkina Faso 2014 15-49 17 17 0 0 2 7 0.1 0 0 7.8 0.1 0 0 0 0
Cambodia 2014 15-49 56.3 38.8 3 0.1 17.8 9.1 4.4 2.1 2.2 0.1 17.5 3 14.5 0.1
Cuba 2014 15-49 73.7 72.2 24.5 0 7.3 0.6 23.8 15.5 0.2 0 0.3 1.5 1.5
Democratic Republic of the Congo 2013-2014 15-49 20.4 7.5 0.7 0.1 0.7 1.2 0.2 3.4 0.4 0.7 0 12.9 7.5 4.5 0.9
Dominican Republic 2013 15-49 71.9 68.4 40.9 0.2 16.6 5.7 1.7 2.6 0.5 0.2 3.5 1.2 1.8 0.5
Egypt 2014 15-49 58.5 56.9 1.2 0 16 8.5 30.1 0.5 0.1 0.5 0 1.6 0.3 0.3 1
Ethiopia 2014 15-49 35 33.8 0.3 0 1.6 23.8 0.7 0.2 0 7.2 0 1.2 1.2
Gambia 2013 15-49 9 8.1 0.6 2.1 3.9 0.3 0.6 0.6 0.9 0.2 0.3 0.4
Ghana 2014 15-49 19.5 17.7 0 0 4.3 7.3 0.4 0.8 0 3.2 1.7 1.8 0 0 1.8
Kenya 2014 15-49 55.7 55.4 1.6 7.3 29.1 3.4 1.8 11.1 0.8 0.2 0.2
Kyrgyzstan 2014 15-49 42 38.5 1.3 0 4.1 0.2 22.4 10.4 0 0 0 3.4 0.7 1.1 1.6
Lesotho 2014 15-49 60.2 59.8 1.7 0.1 14.2 24 1.3 16.9 1.4 0.2 0.4 0.2 0.2
Liberia 2013 15-49 20.2 19.1 0.3 5 11.2 0.4 2.1 0.2 1.1 1.1 0 0
Malawi 2013-2014 15-49 58.6 57.4 10.2 0.1 2.2 32.2 1 2 9.4 0.3 1.2 0.5 0.3 0.5
Montenegro 2013 15-49 23.3 15.4 0.1 2.7 5.6 6.9 7.8 0.3 7.4 0.1
Namibia 2013 15-49 56.1 55.2 6.4 0.3 7 26.8 1.2 12 0 0.2 1.3 0.9 0.2 0.3 0.5
Nepal 2014 15-49 49.6 47.1 18 4.7 4.7 13 1.7 3.7 0.1 1.3 2.5 0.2 2.2 0.1
Nigeria 2013 15-49 15.1 9.4 0.3 0 1.8 3.2 1.1 2.1 0 0.4 0.3 5.8 2.3 2.5 1.1
Panama 2013 15-49 62.8 59.9 25 0.5 11.4 16.3 2.4 3.7 0.6 0.2 2.9 0.9 1.1 0.7
Peru 2013 15-49 74 51.2 8.8 0.3 9.1 17.4 2.5 12.6 0.2 0.2 0 22.7 13.9 7.9 0.9
Philippines 2013 15-49 55.1 36.9 8.5 0.1 19.1 3.7 3.5 1.9 0.1 18.2 5.3 12.1 0.7
Serbia 2014 15-49 58.4 18.4 0.4 0 3.3 0 2.2 12.4 0 0 0.1 40 4.9 35 0.1
Sierra Leone 2013 15-49 16.6 14.6 0.5 3.9 7.5 0.1 0.2 2.4 0 2 0.1 0.1 1.8
Togo 2013-2014 15-49 19.9 17.3 0.3 2.2 7.1 0.8 2.1 4.7 0 2.6 2.2 0.3 0.1
Turkey 2013 15-49 73.5 47.3 9.4 0 4.6 0.6 16.8 15.8 0.1 0 0 26 0.3 25.5 0.2
Uganda 2014 15-49 27.2 25.5 1.9 0 2.1 15 0.8 1.9 0 3.3 0.6 1.6 0 0 1.6
Vanuatu 2013 15-49 49 36.4 11 0.6 10.5 9.7 2.4 2.1 12.5 6.5 4.7 1.3
Viet Nam 2013-2014 15-49 75.7 56.9 2.8 0.1 11.9 1.7 28.2 11.8 0 0.2 0.2 18.8 13.4 5.4 0
Yemen 2013 15-49 33.5 25.2 2.3 0.1 11.6 4.2 5.9 0.5 0 0.6 0 8.3 1.6 2.6 4.1
Zambia 2013-2014 15-49 49 43.9 1.9 11.8 19.3 1.2 4 5.5 0.2 5.2 0.8 3.2 1.2
Zimbabwe 2014 15-49 66.9 66.3 0.9 0 43.9 9 0.4 3.3 0.2 8.4 0.2 0.6 0.1 0.3 0.2
var margin = {
top: 20,
right: 150,
bottom: 100,
left: 40
},
width = 1150 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, width], .5);
var yScale = d3.scale.linear()
.rangeRound([height, 0]);
//var color = d3.scale.category20c();
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.innerTickSize([0]);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.tickFormat(d3.format(".2s")); // for the stacked totals version
var stack = d3.layout
.stack(); // default view is "zero" for the count display.
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 + ")");
var myTooltip = d3.select("body")
.append("div")
.attr("class", "myTooltip");
var percentClicked = false;
d3.csv("Contraceptive-Types-select-countries-2013-2014.csv", function (error, data) {
if (error) {
console.log(error);
}
data.sort(function (a, b) {
return b["Any method"] - a["Any method"];
});
// how would we sort by largest total bar? what would we have to calculate?
var methods = d3.keys(data[0]).filter(function (d) {
return (d !== "Country" && d !== "Year" && d !== "Age" && d !== "Any method" && d !== "Any modern method" && d !== "Any traditional method");
});
var color = d3.scale.ordinal()
.domain(methods)
.range(['#fd8d3c', '#e6550d', ' #c6dbef', '#9ecae1', '#6baed6', '#1797E5', '#3182bd', '#2956A8', '#19344F','#31a354', '#74c476', '#a1d99b', '#c7e9c0']);
console.log("methods", methods);
var stacked = stack(makeData(methods, data)); // needed for default view
xScale.domain(data.map(function (d) {
return d.Country;
}));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("dy", ".5em")
.attr("transform", "rotate(-30)")
.style("text-anchor", "end");
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("Contraceptive Prevalence");
var country = svg.selectAll(".country")
.data(stacked)
.enter().append("g")
.attr("class", "country")
.style("fill", function (d, i) {
// console.log("method method", d[i].method);
return color(d[i].method);
});
console.log("country", country);
var rectangles = country.selectAll("rect")
.data(function (d) {
// console.log("array for a rectangle", d);
return d;
}) // this just gets the array for bar segment.
.enter().append("rect")
.attr("width", xScale.rangeBand());
// this just draws them in the default way, now they're appended.
transitionCount();
drawLegend();
d3.selectAll("input").on("change", handleFormClick);
// All the functions for stuff above!
function handleFormClick() {
if (this.value === "bypercent") {
percentClicked = true;
transitionPercent();
} else {
percentClicked = false;
transitionCount();
}
}
function makeData(methods, data) {
return methods.map(function (method) {
return data.map(function (d) {
return {
x: d["Country"],
y: +d[method],
method: method
};
})
});
}
function transitionPercent() {
yAxis.tickFormat(d3.format("%"));
stack.offset("expand"); // use this to get it to be relative/normalized!
var stacked = stack(makeData(methods, data));
// call function to do the bars, which is same across both formats.
transitionRects(stacked);
}
function transitionCount() {
yAxis.tickFormat(d3.format(".2s")); // for the stacked totals version
stack.offset("zero");
var stacked = stack(makeData(methods, data));
transitionRects(stacked);
console.log("stacked", stacked);
}
function transitionRects(stacked) {
// this domain is using the last of the stacked arrays, which is the last illness, and getting the max height.
yScale.domain([0, d3.max(stacked[stacked.length - 1], function (d) {
return d.y0 + d.y;
})]);
// attach new fixed data
var country = svg.selectAll(".country")
.data(stacked);
// same on the rects
country.selectAll("rect")
.data(function (d) {
console.log("array for a rectangle");
return d;
}) // this just gets the array for bar segment.
svg.selectAll("g.country rect")
.transition()
.duration(250)
.attr("x", function (d) {
return xScale(d.x);
})
.attr("y", function (d) {
return yScale(d.y0 + d.y);
}) //
.attr("height", function (d) {
return yScale(d.y0) - yScale(d.y0 + d.y);
}); // height is base - tallness
svg.selectAll(".y.axis").transition().call(yAxis);
}
/*======================================================================
Legend
======================================================================*/
// Building a legend by hand, based on http://bl.ocks.org/mbostock/3886208
function drawLegend() {
var legend = svg.selectAll(".legend")
.data(color.domain().slice()) // what do you think this does?
.enter().append("g")
.attr("class", "legend")
.attr("transform", function (d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width + 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function (d, i) {
return methods[i];
});
}
/*======================================================================
Mouse Events
======================================================================*/
rectangles
.on("mouseover", mouseoverFunc)
.on("mousemove", mousemoveFunc)
.on("mouseout", mouseoutFunc);
function mouseoverFunc(d) {
console.log("moused over", d.x);
if(percentClicked) {
myTooltip
.style("display", null)
.html("<p><span class='tooltipHeader'>" + d.x + "</span><br>"+ d.method + ": " + d3.format("%")(d.y) + "</p>");
} else {
console.log("method", d.method, "percent", d.y);
myTooltip
.style("display", null)
.html("<p><span class='tooltipHeader'>" + d.x + "</span><br>"+ d.method + ": " +d.y + "%</p>");
}
}
function mousemoveFunc(d) {
myTooltip
.style("top", (d3.event.pageY - 5) + "px")
.style("left", (d3.event.pageX + 10) + "px");
}
function mouseoutFunc(d) {
return myTooltip.style("display", "none"); // this sets it to invisible!
}
/*======================================================================
======================================================================*/
});
<!DOCTYPE html>
<!-- Modification of an example by Scott Murray from Knight D3 course -->
<html lang="en">
<head>
<meta charset="utf-8">
<title>Stacked Bar</title>
<link href='https://fonts.googleapis.com/css?family=Roboto:400,400italic,700,700italic|Lora:400,400italic,700,700italic' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="main.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<body>
<h1 class="header">Types of Contraception Used in Select Countries</h1>
<h2 class="header"></h2>
<p id="sources" class="header">Source: <a href="http://www.un.org/en/development/desa/population/publications/dataset/contraception/wcu2015.shtml">United Nations, Department of Economic and Social Affairs</a>. Only countries with complete data from the years 2013-2014 are represented.</p>
<div class="header" id="form">
<label><input type="radio" name="mode" value="bycount" checked>% Contraceptive Use by Country</label>
<label><input type="radio" name="mode" value="bypercent">Percent Breakdown of Overall Use</label>
</div>
<div id="chart"></div>
<script type="text/javascript" src="contraceptives.js"></script>
</body>
</html>
body {
box-sizing: border-box;
}
svg {
/* padding: 1em;*/
background-color: rgb(255, 255, 255);
}
svg rect:hover {
opacity: .3;
}
svg circle:hover {
opacity: .3;
}
svg g {
fill: #ACACAC;
}
svg g text.label,
svg g text.ylabel {
fill: #2A2A2A;
}
svg {
background-color: white;
}
.axis path,
.axis line {
fill: none;
stroke: #D3D3D3;
stroke-width: 1px;
}
.line {
stroke: #FF9900;
fill: none;
stroke-opacity: 25%;
stroke-width: 1px;
}
.unfocused {
stroke-opacity: 25%;
}
.focused {
stroke-width: 2px;
stroke-opacity: 100%;
}
.MDG {
stroke: #2A2A2A;
fill: none;
stroke-opacity: 100%;
stroke-width: 1px;
}
.axis text, .legend text,
.aside {
font-family: sans-serif;
font-size: 11px;
}
.header {
width: 70%;
margin-left: 16px;
}
h1 {
font-family: 'Roboto', sans-serif;
font-size: 1.75em;
margin-top: 1em;
font-weight: 700;
color: #0099FF;
text-transform: uppercase;
}
h2 {
font-family: 'Roboto', sans-serif;
text-align: justify;
line-height: 1.25em;
font-weight: 700;
font-size: 1em;
}
p {
font-family: 'Lora', serif;
font-size: 15px;
line-height: 1.25em;
text-align: justify;
}
#sources {
font-size: 12px;
font-style: italic;
color: rgb(0, 0, 0);
font-style: italic;
}
a {
color: #0099FF;
text-decoration: none;
}
a:hover {
color: rgb(255, 0, 153);
}
.sans {
font-family: sans-serif;
}
.orange {
color: #FF9900;
}
.blue {
color: #0099FF;
}
.red {
color: red;
}
.myTooltip {
position: absolute;
z-index: 10;
}
.myTooltip p {
font-family: 'Roboto', sans-serif;
background-color: rgba(255, 255, 255, 1);
padding: .5em 1em;
font-size: 12px;
line-height: 17px;
color: black;
}
.tooltipHeader {
font-weight: 700;
font-size: 12.5px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.