The D3.js code that I used as the base for the Life Expectancy New Year’s card that I designed. You can see the end result of all 4 cards and read about the design process in my blog Saying “Happy new year” with data
You can find the design of the two other cards here
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #F7F7F7;
shape-rendering: crispEdges;
}
.axis path {
display: none;
}
.line {
fill: none;
stroke-width: 1px;
opacity: 0.4;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 60, right: 80, bottom: 60, left: 80},
width = 1000 - margin.left - margin.right,
height = 460 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width])
.domain([1950,2015]);
var y = d3.scale.linear()
.range([height, 0])
.domain([65,85]);
var color = d3.scale.ordinal()
.range(["#8A9B0F", "#C82026"])
.domain(["men", "women"]);
var colorRange = ['#8a9b0f','#939213','#9b8917','#a3801a','#a9771c','#af6d1e',
'#b56320','#ba5622','#bf4924','#c43725','#c82026'];
var colorSeq = d3.scale.ordinal()
.range(colorRange)
.domain([d3.range(colorRange.length)]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.format("d"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickSize(-width, 0, 0);
var line = d3.svg.line()
.interpolate("cardinal")
.x(function(d) { return x(d.year); })
.y(function(d) { return y(d.gender); });
var svg = d3.select("body").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 + ")");
d3.csv("lifeExpectancy.csv", function(error, data) {
if (error) throw error;
data.forEach(function (d,i) {
d.year = +d.year;
d.men = +d.men;
d.women = +d.women;
d.diff = d.women - d.men;
})
var rScale = d3.scale.linear()
.domain([1, Math.round(d3.max(data, function(d) { return d.diff; })) ])
.range([3, 40]);
var keys = d3.keys(data[0]).filter(function(key) { return key !== "year" && key !== "diff"; });
var genderLines = keys.map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
year: d.year,
gender: d[name]};
})
};
});
//Append axes
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
//Wrapper for the background circles
var strokes = svg.append("g").attr("class","strokeWrapper");
//Append difference circles
data.forEach(function(d,index) {
var numLoops = Math.round(d.diff);
for(var j = 1; j < (numLoops+1); j++) {
strokes.append("circle")
.attr("cx", x(d.year))
.attr("cy", y(Math.random() * (d.men*0.95 - d.women*1.05) + d.women*1.05).toFixed(4))
.attr("r", rScale(j))
.style("stroke", colorSeq(randomIntFromInterval(0,colorRange.length)))
.style("stroke-width", (Math.random() * (0.5 - 6) + 6).toFixed(1))
.style("opacity", (Math.random() * (0.05 - 0.1) + 0.1).toFixed(1))
.style("fill", "none");
}//for j
})
//Append the two lines
var lines = svg.selectAll(".lines")
.data(genderLines)
.enter().append("g")
.attr("class", "lines");
lines.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
//Append circles
var circles = svg.selectAll(".circleWrapper")
.data(data)
.enter().append("g")
.attr("class","circleWrapper")
.attr("transform", function(d) { return "translate(" + x(d.year) + ")"; });
//Append men
circles.append("circle")
.attr("class", "circleWoman")
.attr("cy", function(d) { return y(d.men); })
.attr("r", 8)
.style("fill", color("men"))
.style("fill-opacity", 0.1);
circles.append("circle")
.attr("class", "circleMen")
.attr("cy", function(d) { return y(d.men); })
.attr("r", 3)
.style("fill", color("men"))
.style("stroke", color("men"))
.style("stroke-width", 3)
.style("stroke-opacity", 0.3);
//Append women
circles.append("circle")
.attr("class", "circleWoman")
.attr("cy", function(d) { return y(d.women); })
.attr("r", 8)
.style("fill", color("women"))
.style("fill-opacity", 0.1);
circles.append("circle")
.attr("class", "circleWoman")
.attr("cy", function(d) { return y(d.women); })
.attr("r", 3)
.style("fill", color("women"))
.style("stroke", color("women"))
.style("stroke-width", 3)
.style("stroke-opacity", 0.3);
});
function randomIntFromInterval(min,max) {
return Math.floor(Math.random()*(max-min+1)+min);
}
</script>
year,men,women
1950,70.29,72.58
1951,70.24,72.75
1952,70.96,73.29
1953,70.41,72.97
1954,70.96,73.83
1955,70.94,74.08
1956,70.97,74.1
1957,71.39,74.58
1958,71.46,74.84
1959,71.24,75.16
1960,71.39,75.3
1961,71.45,75.74
1962,70.95,75.56
1963,71.02,75.77
1964,71.27,76.27
1965,71.12,76.14
1966,71.03,76.12
1967,71.17,76.57
1968,70.92,76.44
1969,70.92,76.29
1970,70.81,76.5
1971,70.99,76.77
1972,70.81,76.79
1973,71.3,77.13
1974,71.61,77.61
1975,71.45,77.71
1976,71.53,77.92
1977,72.08,78.52
1978,71.95,78.5
1979,72.46,78.93
1980,72.48,79.19
1981,72.71,79.32
1982,72.75,79.44
1983,72.93,79.56
1984,72.96,79.67
1985,73.07,79.66
1986,73.09,79.61
1987,73.51,80.06
1988,73.69,80.24
1989,73.67,79.93
1990,73.84,80.11
1991,74.05,80.15
1992,74.3,80.28
1993,73.98,80
1994,74.58,80.31
1995,74.59,80.36
1996,74.66,80.35
1997,75.17,80.55
1998,75.19,80.69
1999,75.34,80.45
2000,75.54,80.58
2001,75.8,80.71
2002,75.99,80.69
2003,76.23,80.93
2004,76.87,81.44
2005,77.19,81.6
2006,77.63,81.89
2007,78.01,82.31
2008,78.32,82.28
2009,78.53,82.65
2010,78.77,82.72
2011,79.18,82.85
2012,79.14,82.82
2013,79.41,83.04
2014,79.87,83.29