An implementation in D3 of Figure 4-21 "Stacked bar chart showing top three eaters from 2000 to 2010" in "Visualize This" by Nathan Yau.
xxxxxxxxxx
<body>
<style>
body {
position: relative;
width: 100%;
font-family: Georgia;
font-size: 14px;
color: #333;
}
#container {
width: 500px;
height: 500px;
margin: 0 auto;
padding: 20px;
position: relative;
border: 1px solid #ccc;
}
#header {
font-size: 20px;
font-weight: bold;
margin-bottom: 10px;
}
#footer {
position: absolute;
bottom: 20px;
right: 20px;
}
#place-tick1 {
position: absolute;
top: 420px;
left: 495px;
}
#place-tick2 {
position: absolute;
top: 350px;
left: 495px;
}
#place-tick3 {
position: absolute;
top: 290px;
left: 495px;
}
#y-tick {
position: absolute;
top: 151px;
left: 50px;
}
svg {
position: absolute;
left: 20px;
top: 20px;
right: 20px;
bottom: 20px;
}
.axis path {
display: none;
}
.y.axis-line {
stroke: #eee;
stroke-width: 1;
shape-rendering: crispEdges;
}
.y.axis-line-strong {
stroke: #333;
stroke-width: 2;
shape-rendering: crispEdges;
}
.bar {
stroke: #ffffff;
stroke-width: 1;
shape-rendering: crispEdges;
}
.first {
fill: #009D47;
}
.second {
fill: #00C04B;
}
.third {
fill: #76D03C;
}
</style>
<div id="container">
<div id="header">TOP THREE HOT DOG EATERS</div>
<div id="header-text">The year before Takeru Kobayashi started to compete in Nathan’s Hot Dog Eating Contest, the top three eaters were close in skills. However, from 2001 to 2005, Kobayashi always had a substantial lead. That changed in 2006 when Joey Chestnut started competing.</div>
<div id="footer">Source: Wikipedia | Nathan Yau</div>
<div id="place-tick1">1st</div>
<div id="place-tick2">2nd</div>
<div id="place-tick3">3rd</div>
<div id="y-tick">Hot dogs and buns (HDBs)</div>
</div>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var width = 500,
height = 500,
margin = { top: 150, right: 50, bottom: 50, left: 50 },
xDomain = [2000, 2010],
yDomain = [0, 200], // todo: should be the max sum of values
barWidth = 33;
var xValue = function(d) { return d; },
xScale = d3.scale.linear()
.rangeRound([0, width - margin.left - margin.right])
.domain(xDomain),
xMap = function(d) { return xScale(xValue(d)); },
xAxis = d3.svg.axis()
.scale(xScale)
.tickFormat(function(d) {
// todo: should be an apostrophe
return "'" + d.toString().substr(2,2);
});
var yValue = function(d) { return d; },
yScale = d3.scale.linear()
.rangeRound([height - margin.top - margin.bottom, 0])
.domain(yDomain),
yMap = function(d) { return yScale(yValue(d)); },
yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.tickValues([0, 50, 100, 150, 200])
var colorClass = d3.scale.ordinal().range(['first', 'second', 'third']);
var csvFile = 'hot-dog-places.csv';
var svg = d3.select('#container').append('svg')
.attr('width', width)
.attr('height', height)
var chart = svg.append('g')
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')')
d3.csv(csvFile, function(rawData) {
// change the format of the data to become an Array containing a year,
// value, place Hash for each of the data points.
var data = [];
rawData.forEach(function(row, place) {
d3.entries(row).forEach(function(kv) {
data.push({
year: +kv.key,
value: +kv.value,
place: place + 1
});
});
});
var stack = d3.layout.stack()
.offset('zero')
.values(function(d) { return d.values; })
.x(function(d) { return d.year; })
.y(function(d) { return d.value; });
var nest = d3.nest()
.key(function(d) { return d.place; });
var layers = stack(nest.entries(data));
// Add the X-axis
chart.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, 300)')
.call(xAxis);
// todo: adding a class to a line doesn't work, plus I don't know how
// to wrap it in a 'g'
var lines = [50, 100, 150, 200];
chart.selectAll('.lines')
.data(lines)
.enter()
.append('line')
.attr('class', 'y axis-line')
.attr('x1', -65)
.attr('x2', width - 84)
.attr('y1', yScale)
.attr('y2', yScale);
// Add the Y-axis
chart.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(-15, -10)')
.call(yAxis);
// Add the bars
var place = chart.selectAll('g.place')
.data(layers)
.enter()
.append('g')
.attr('class', 'place');
place.selectAll('rect')
.data(function(d) { return d.values; })
.enter()
.append('rect')
.attr('class', function(d) {
return 'bar ' + colorClass(d.place);
})
.attr('transform', 'translate(' + -barWidth / 2 + ', 0)')
.attr('x', function(d) { return xScale(d.year); })
.attr('width', barWidth)
.attr('y', function(d) { return yScale(d.y + d.y0); })
.attr('height', function(d) { return yScale(d.y0) - yScale(d.y + d.y0); });
// Add the 0 line
chart
.append('line')
.attr('class', 'y axis-line-strong')
.attr('x1', -65)
.attr('x2', width - 84)
.attr('y1', yScale(0) + 1)
.attr('y2', yScale(0) + 1)
});
</script>
</body>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js