An implementation in D3 of Figure 4-5 "Bar graph showing results from Nathan's Hot Dog Eating Contest" in "Visualize This" by Nathan Yau.
The chart is implemented using SVG, and I've manually added the text boxes as HTML DIV elements. Likely it's better to also add the text boxes as SVG.
I've tried to make the chart as much like the one in the book, but there are at least two issues:
xxxxxxxxxx
<body>
<style>
body {
font-family: Georgia;
font-size: 14px;
position: relative;
}
.axis line {
fill: none;
stroke: #ccc;
shape-rendering: crispEdges;
}
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
stroke-width: 2;
}
.y.axis path {
display: none;
}
.bar {
fill: #cccccc;
}
.bar.newRecord {
fill: #33bb33;
}
#chart-html {
position: absolute;
width: 960px;
height: 500px;
}
#chart-header {
position: absolute;
left: 45px;
width: 630px;
}
#chart-header h1 {
font-size: 16px;
margin: 6px 0;
text-transform: uppercase;
font-weight: strong;
}
.chart-text {
font-size: 13px;
}
.chart-text div {
border-top: 1px dotted #cccccc;
border-right: 1px dotted #cccccc;
}
#text-frank {
position: absolute;
left: 160px;
top: 270px;
width: 220px;
}
#text-frank .text-line {
position: absolute;
width: 35px;
height: 51px;
right: -25px;
top: 16px;
}
#text-takeru {
position: absolute;
left: 290px;
top: 180px;
width: 260px;
}
#text-takeru .text-line {
position: absolute;
width: 110px;
height: 5px;
right: -107px;
top: 23px;
}
#text-joey {
position: absolute;
left: 430px;
top: 100px;
width: 260px;
}
#text-joey .text-line {
position: absolute;
width: 136px;
height: 11px;
right: -119px;
top: 24px;
}
#chart-footer {
position: absolute;
bottom: 0;
right: 50px;
font-size: 12px;
}
</style>
<div id="chart-html">
<div id="chart-header">
<h1>Hot dog eating</h1>
<span>Nathan’s hot dog eating contest every July 4th has been going on since the early 1900s, but it wasn’t until 2001 when things got serious. Takeru Kobayashi from Japan raised the bar, more than doubling the previous world record. Highlighted bars indicate new records.</span>
</div>
<div id="text-frank" class="chart-text">
<strong>Frank Dellarose</strong> sets a new world record with 21 and a half HDBs.
<div class="text-line"></div>
</div>
<div id="text-takeru" class="chart-text">
In 2001, <strong>Takeru Kobayashi</strong> gets his first win in the competition. He went on to win five more years in a row.
<div class="text-line"></div>
</div>
<div id="text-joey" class="chart-text">
For the first time since 1999, an American reclaims the title when <strong>Joey Chestnut</strong> consumes 66 HDBs.
<div class="text-line"></div>
</div>
<div id="chart-footer">
Source Wikipedia | Nathan Yau
</div>
</div>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var width = 960,
height = 500,
margin = { top: 120, right: 50, bottom: 60, left: 100 },
chartWidth = width - margin.left - margin.right,
chartHeight = height - margin.top - margin.bottom;
var xValue = function(d) { return d.year; },
xScale = d3.scale.linear().rangeRound([0, chartWidth]),
xMap = function(d) { return xScale(xValue(d)); },
xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.tickFormat(d3.format('d'))
.tickSize(10, 5, 0)
.ticks(15)
.tickSubdivide(2);
var yValue = function(d) { return d.dogsEaten; },
yScale = d3.scale.linear().rangeRound([chartHeight, 0]),
yMap = function(d) { return yScale(yValue(d)); },
yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.tickSize(15);
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height);
var chart = svg.append('g')
.attr('width', chartWidth)
.attr('height', chartHeight)
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
var csvfile = 'hot-dog-contest-winners.csv';
d3.csv(csvfile, function(d) {
return {
year: +d['Year'],
// country: d['Country'],
// winner: d['Winner'],
dogsEaten: +d['Dogs eaten'],
newRecord: d['New record'] === '1'
};
}, function(error, data) {
// Hardcode nice values for the domain
xScale.domain([1979, 2011]);
yScale.domain([0, 70]);
// Add the X-axis
chart.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, ' + (chartHeight + 1) + ')')
.call(xAxis);
// Add the Y-axis
chart.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(-20, 0)')
.call(yAxis)
.append('text')
.attr('y', 6)
.attr('x', 6)
.style('text-anchor', 'start')
.text('Hot dogs and buns (HDBs)');
// Calculate the width of a bar
var barSpacing = 9;
var barWidth = Math.round(width / d3.range(xScale.domain()[0], xScale.domain()[1] + 1).length - barSpacing);
// Add all the bars
chart.selectAll('.bar')
.data(data)
.enter()
.append('rect')
.attr('class', function(d) {
if (d.newRecord) {
return 'bar newRecord';
} else {
return 'bar';
}
})
.attr('x', xMap)
.attr('width', barWidth)
.attr('transform', 'translate(' + -(barWidth / 2) + ', 0)')
.attr('y', yMap)
.attr('height', function(d) { return chartHeight - yMap(d); })
});
</script>
</body>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js