Bump plot for 80 popular female names. Data from baby-name-scraper collected from Social Security Administration by Eric Socolofsky.
Also see Popular Baby Names by Nadieh Bremer for another application of bump charts to this dataset.
forked from syntagmatic‘s block: Bump Plot
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fff;
font: 12px sans-serif;
}
svg,
canvas {
position: absolute;
}
.axis path,
.axis line {
fill: none;
stroke: #d0d0d0;
}
.x.axis .tick text {
font: 10px sans-serif;
fill: #555;
}
</style>
<body>
<canvas></canvas>
<svg></svg>
<script src="//d3js.org/d3.v4.0.0-alpha.40.js"></script>
<script>
var num = 80;
var margin = {top: 30, right: 60, bottom: 30, left: 60};
var width = 960,
height = 800;
var devicePixelRatio = window.devicePixelRatio || 1;
var canvas = d3.select("canvas")
.attr("width", width * devicePixelRatio)
.attr("height", height * devicePixelRatio)
.style("width", width + "px")
.style("height", height + "px");
var svg = d3.select("svg")
.style("width", width + "px")
.style("height", height + "px");
var color = d3.scaleOrdinal()
.range(["#DB7F85", "#50AB84", "#4C6C86", "#C47DCB", "#B59248", "#DD6CA7", "#E15E5A", "#5DA5B3", "#725D82", "#54AF52", "#954D56", "#8C92E8", "#D8597D", "#AB9C27", "#D67D4B", "#D58323", "#BA89AD", "#357468", "#8F86C2", "#7D9E33", "#517C3F", "#9D5130", "#5E9ACF", "#776327", "#944F7E"]);
var xscale = d3.scaleLinear()
.domain([1880,2015])
.range([margin.left,width-margin.right]);
var xaxis = d3.axisBottom()
.scale(xscale)
.ticks(20)
.tickFormat(d3.format(""));
var xaxis2 = d3.axisTop()
.scale(xscale)
.ticks(20)
.tickFormat(d3.format(""));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height-margin.bottom) + ")")
.call(xaxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (margin.top-10) + ")")
.call(xaxis2);
var yscale = d3.scaleLinear()
.domain([0,num])
.range([margin.top, height-margin.bottom]);
var radius = d3.scaleSqrt()
.domain([0,0.1])
.range([0,4]);
d3.csv("girl-names.csv", function(error, data) {
data.forEach(function(d) {
d.fraction = +d.fraction;
d.year = +d.year;
});
// only girls
data = data.filter(function(d) {
return d.sex == "f";
});
// nest by name and rank by total popularity
var nested = d3.nest()
.key(function(d) { return d.name; })
.rollup(function(leaves) {
return {
data: leaves,
sum: d3.sum(leaves, function(d) { return d.fraction; })
};
})
.sortValues(function(a,b) { return a.sum - b.sum; })
.entries(data);
var topnames = nested.slice(0,num).map(function(d) { return d.key; });
data = data.filter(function(d) {
return topnames.indexOf(d.name) > -1;
});
// nest by name and rank by total popularity
window.byYear = {}
d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.name; })
.sortValues(function(a,b) { return a.fraction - b.fraction; })
.rollup(function(leaves,i) {
return leaves[0].fraction;
})
.entries(data)
.forEach(function(year) {
byYear[year.key] = {};
year.values.forEach(function(name,i) {
byYear[year.key][name.key] = i;
});
});
var ctx = canvas.node().getContext("2d");
ctx.scale(devicePixelRatio, devicePixelRatio);
ctx.fillStyle = "#1a1a1a";
ctx.strokeStyle = "#1a1a1a";
ctx.textAlign = "right";
ctx.textBaseline = "middle";
nested.slice(0,num).reverse().forEach(function(name,i) {
var yearspopular = name.values.data;
if (i > num-11) {
ctx.globalAlpha = 0.85;
ctx.strokeStyle = color(name.key);
ctx.lineWidth = 2.5;
} else {
ctx.globalAlpha = 0.55;
ctx.strokeStyle = "#888";
ctx.lineWidth = 1;
}
// bump line
ctx.globalCompositeOperation = "darken";
ctx.beginPath();
ctx.lineCap = "round";
yearspopular.forEach(function(d,j) {
if (j == 0 || ((d.year - yearspopular[j-1].year) > 1)) {
ctx.moveTo(xscale(d.year), yscale(byYear[d.year][name.key]))
} else {
ctx.lineTo(xscale(d.year), yscale(byYear[d.year][name.key]));
}
});
ctx.stroke();
ctx.closePath();
});
ctx.font = "10px sans-serif";
nested.slice(0,num).reverse().forEach(function(name,i) {
var yearspopular = name.values.data;
if (i > num-11) {
ctx.fillStyle = color(name.key);
} else {
ctx.fillStyle = "#555";
}
// start names
ctx.globalCompositeOperation = "source-over";
ctx.globalAlpha = 0.9;
ctx.textAlign = "end";
var start = yearspopular[0].year;
ctx.fillText(name.key, xscale(start)-4, yscale(byYear[start][name.key]));
// end names
ctx.textAlign = "start";
var end= yearspopular[yearspopular.length-1].year;
ctx.fillText(name.key, xscale(end)+4, yscale(byYear[end][name.key]));
});
});
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fff;
font: 12px sans-serif;
}
svg,
canvas {
position: absolute;
}
.axis path,
.axis line {
fill: none;
stroke: #d0d0d0;
}
.x.axis .tick text {
font: 10px sans-serif;
fill: #555;
}
</style>
<body>
<canvas></canvas>
<svg></svg>
<script src="//d3js.org/d3.v4.0.0-alpha.40.js"></script>
<script>
var num = 1000;
var margin = {top: 30, right: 60, bottom: 30, left: 60};
var width = 960,
height = 7600;
var devicePixelRatio = window.devicePixelRatio || 1;
var canvas = d3.select("canvas")
.attr("width", width * devicePixelRatio)
.attr("height", height * devicePixelRatio)
.style("width", width + "px")
.style("height", height + "px");
var svg = d3.select("svg")
.style("width", width + "px")
.style("height", height + "px");
var color = d3.scaleOrdinal()
.range(["#DB7F85", "#50AB84", "#4C6C86", "#C47DCB", "#B59248", "#DD6CA7", "#E15E5A", "#5DA5B3", "#725D82", "#54AF52", "#954D56", "#8C92E8", "#D8597D", "#AB9C27", "#D67D4B", "#D58323", "#BA89AD", "#357468", "#8F86C2", "#7D9E33", "#517C3F", "#9D5130", "#5E9ACF", "#776327", "#944F7E"]);
var xscale = d3.scaleLinear()
.domain([1880,2015])
.range([margin.left,width-margin.right]);
var xaxis = d3.axisBottom()
.scale(xscale)
.ticks(20)
.tickFormat(d3.format(""));
var xaxis2 = d3.axisTop()
.scale(xscale)
.ticks(20)
.tickFormat(d3.format(""));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height-margin.bottom) + ")")
.call(xaxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (margin.top-10) + ")")
.call(xaxis2);
var yscale = d3.scaleLinear()
.domain([0,num])
.range([margin.top, height-margin.bottom]);
var radius = d3.scaleSqrt()
.domain([0,0.1])
.range([0,4]);
d3.csv("boy-names.csv", function(error, data) {
data.forEach(function(d) {
d.fraction = +d.fraction;
d.year = +d.year;
});
// only girls
data = data.filter(function(d) {
return d.sex == "m";
});
// nest by name and rank by total popularity
var nested = d3.nest()
.key(function(d) { return d.name; })
.rollup(function(leaves) {
return {
data: leaves,
length: leaves.length,
sum: d3.sum(leaves, function(d) { return d.fraction; })
};
})
.sortValues(function(a,b) { return a.length - b.length; })
.entries(data);
var topnames = nested.map(function(d) { return d.key; });
data = data.filter(function(d) {
return topnames.indexOf(d.name) > -1;
});
// nest by name and rank by total popularity
window.byYear = {}
d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.name; })
.sortValues(function(a,b) { return a.fraction - b.fraction; })
.rollup(function(leaves,i) {
return leaves[0].fraction;
})
.entries(data)
.forEach(function(year) {
byYear[year.key] = {};
year.values.forEach(function(name,i) {
byYear[year.key][name.key] = i;
});
});
var ctx = canvas.node().getContext("2d");
ctx.scale(devicePixelRatio, devicePixelRatio);
ctx.fillStyle = "#1a1a1a";
ctx.strokeStyle = "#1a1a1a";
ctx.textAlign = "right";
ctx.textBaseline = "middle";
// color fiddling
d3.range(8).map(color);
nested.reverse().forEach(function(name,i) {
var yearspopular = name.values.data;
ctx.globalCompositeOperation = "darken";
if (i > nested.length-11) {
ctx.strokeStyle = color(name.key);
ctx.lineWidth = 2;
ctx.globalAlpha = 0.75;
} else {
ctx.strokeStyle = "#777";
ctx.globalAlpha = 0.15;
ctx.lineWidth = 1;
}
// bump line
ctx.beginPath();
yearspopular.forEach(function(d,j) {
if (j == 0 || ((d.year - yearspopular[j-1].year) > 1)) {
ctx.moveTo(xscale(d.year), yscale(byYear[d.year][name.key]))
} else {
ctx.lineTo(xscale(d.year), yscale(byYear[d.year][name.key]));
}
});
ctx.stroke();
ctx.closePath();
});
nested.reverse().forEach(function(name,i) {
var yearspopular = name.values.data;
ctx.globalCompositeOperation = "source-over";
if (i > nested.length-11) {
ctx.fillStyle = color(name.key);
} else {
ctx.fillStyle = "#111";
}
ctx.font = "bold 9px sans-serif";
// start names
ctx.globalAlpha = 1;
ctx.textAlign = "end";
var startyear = yearspopular[0].year;
ctx.fillText(name.key, xscale(startyear)-4, yscale(byYear[startyear][name.key]));
ctx.font = "9px sans-serif";
// end names
ctx.textAlign = "start";
var endyear = yearspopular[yearspopular.length-1].year;
ctx.fillText(name.key, xscale(endyear)+4, yscale(byYear[endyear][name.key]));
});
});
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fff;
font: 12px sans-serif;
}
svg,
canvas {
position: absolute;
}
.axis path,
.axis line {
fill: none;
stroke: #d0d0d0;
}
.x.axis .tick text {
font: 10px sans-serif;
fill: #555;
}
</style>
<body>
<canvas></canvas>
<svg></svg>
<script src="//d3js.org/d3.v4.0.0-alpha.40.js"></script>
<script>
var num = 1000;
var margin = {top: 30, right: 60, bottom: 30, left: 60};
var width = 960,
height = 7600;
var devicePixelRatio = window.devicePixelRatio || 1;
var canvas = d3.select("canvas")
.attr("width", width * devicePixelRatio)
.attr("height", height * devicePixelRatio)
.style("width", width + "px")
.style("height", height + "px");
var svg = d3.select("svg")
.style("width", width + "px")
.style("height", height + "px");
var color = d3.scaleOrdinal()
.range(["#DB7F85", "#50AB84", "#4C6C86", "#C47DCB", "#B59248", "#DD6CA7", "#E15E5A", "#5DA5B3", "#725D82", "#54AF52", "#954D56", "#8C92E8", "#D8597D", "#AB9C27", "#D67D4B", "#D58323", "#BA89AD", "#357468", "#8F86C2", "#7D9E33", "#517C3F", "#9D5130", "#5E9ACF", "#776327", "#944F7E"]);
var xscale = d3.scaleLinear()
.domain([1880,2015])
.range([margin.left,width-margin.right]);
var xaxis = d3.axisBottom()
.scale(xscale)
.ticks(20)
.tickFormat(d3.format(""));
var xaxis2 = d3.axisTop()
.scale(xscale)
.ticks(20)
.tickFormat(d3.format(""));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height-margin.bottom) + ")")
.call(xaxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (margin.top-10) + ")")
.call(xaxis2);
var yscale = d3.scaleLinear()
.domain([0,num])
.range([margin.top, height-margin.bottom]);
var radius = d3.scaleSqrt()
.domain([0,0.1])
.range([0,4]);
d3.csv("girl-names.csv", function(error, data) {
data.forEach(function(d) {
d.fraction = +d.fraction;
d.year = +d.year;
});
// only girls
data = data.filter(function(d) {
return d.sex == "f";
});
// nest by name and rank by total popularity
var nested = d3.nest()
.key(function(d) { return d.name; })
.rollup(function(leaves) {
return {
data: leaves,
length: leaves.length,
sum: d3.sum(leaves, function(d) { return d.fraction; })
};
})
.sortValues(function(a,b) { return a.length - b.length; })
.entries(data);
var topnames = nested.map(function(d) { return d.key; });
data = data.filter(function(d) {
return topnames.indexOf(d.name) > -1;
});
// nest by name and rank by total popularity
window.byYear = {}
d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.name; })
.sortValues(function(a,b) { return a.fraction - b.fraction; })
.rollup(function(leaves,i) {
return leaves[0].fraction;
})
.entries(data)
.forEach(function(year) {
byYear[year.key] = {};
year.values.forEach(function(name,i) {
byYear[year.key][name.key] = i;
});
});
var ctx = canvas.node().getContext("2d");
ctx.scale(devicePixelRatio, devicePixelRatio);
ctx.fillStyle = "#1a1a1a";
ctx.strokeStyle = "#1a1a1a";
ctx.textAlign = "right";
ctx.textBaseline = "middle";
// color fiddling
d3.range(8).map(color);
nested.reverse().forEach(function(name,i) {
var yearspopular = name.values.data;
if (i > nested.length-11) {
ctx.strokeStyle = color(name.key);
ctx.lineWidth = 2;
ctx.globalAlpha = 0.75;
} else {
ctx.strokeStyle = "#777";
ctx.globalAlpha = 0.15;
ctx.lineWidth = 1;
}
// bump line
ctx.beginPath();
yearspopular.forEach(function(d,j) {
if (j == 0 || ((d.year - yearspopular[j-1].year) > 1)) {
ctx.moveTo(xscale(d.year), yscale(byYear[d.year][name.key]))
} else {
ctx.lineTo(xscale(d.year), yscale(byYear[d.year][name.key]));
}
});
ctx.stroke();
ctx.closePath();
});
nested.reverse().forEach(function(name,i) {
var yearspopular = name.values.data;
if (i > nested.length-11) {
ctx.fillStyle = color(name.key);
} else {
ctx.fillStyle = "#111";
}
ctx.font = "bold 9px sans-serif";
// start names
ctx.globalAlpha = 1;
ctx.textAlign = "end";
var startyear = yearspopular[0].year;
ctx.fillText(name.key, xscale(startyear)-4, yscale(byYear[startyear][name.key]));
ctx.font = "9px sans-serif";
// end names
ctx.textAlign = "start";
var endyear = yearspopular[yearspopular.length-1].year;
ctx.fillText(name.key, xscale(endyear)+4, yscale(byYear[endyear][name.key]));
});
});
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fff;
font: 12px sans-serif;
}
svg,
canvas {
position: absolute;
}
.axis path,
.axis line {
fill: none;
stroke: #d0d0d0;
}
.x.axis .tick text {
font: 10px sans-serif;
fill: #555;
}
</style>
<body>
<canvas></canvas>
<svg></svg>
<script src="//d3js.org/d3.v4.0.0-alpha.40.js"></script>
<script>
var num = 80;
var margin = {top: 30, right: 60, bottom: 30, left: 60};
var width = 960,
height = 700;
var devicePixelRatio = window.devicePixelRatio || 1;
var canvas = d3.select("canvas")
.attr("width", width * devicePixelRatio)
.attr("height", height * devicePixelRatio)
.style("width", width + "px")
.style("height", height + "px");
var svg = d3.select("svg")
.style("width", width + "px")
.style("height", height + "px");
var color = d3.scaleOrdinal()
.range(["#DB7F85", "#50AB84", "#4C6C86", "#C47DCB", "#B59248", "#DD6CA7", "#E15E5A", "#5DA5B3", "#725D82", "#54AF52", "#954D56", "#8C92E8", "#D8597D", "#AB9C27", "#D67D4B", "#D58323", "#BA89AD", "#357468", "#8F86C2", "#7D9E33", "#517C3F", "#9D5130", "#5E9ACF", "#776327", "#944F7E"]);
var xscale = d3.scaleLinear()
.domain([1880,2015])
.range([margin.left,width-margin.right]);
var xaxis = d3.axisBottom()
.scale(xscale)
.ticks(20)
.tickFormat(d3.format(""));
var xaxis2 = d3.axisTop()
.scale(xscale)
.ticks(20)
.tickFormat(d3.format(""));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height-margin.bottom) + ")")
.call(xaxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (margin.top-10) + ")")
.call(xaxis2);
var yscale = d3.scaleLinear()
.domain([0,num])
.range([margin.top, height-margin.bottom]);
var radius = d3.scaleSqrt()
.domain([0,0.1])
.range([0,4]);
d3.csv("boy-names.csv", function(error, data) {
data.forEach(function(d) {
d.fraction = +d.fraction;
d.year = +d.year;
});
// only girls
data = data.filter(function(d) {
return d.sex == "m";
});
// nest by name and rank by total popularity
var nested = d3.nest()
.key(function(d) { return d.name; })
.rollup(function(leaves) {
return {
data: leaves,
sum: d3.sum(leaves, function(d) { return d.fraction; })
};
})
.sortValues(function(a,b) { return a.sum - b.sum; })
.entries(data);
var topnames = nested.slice(0,num).map(function(d) { return d.key; });
data = data.filter(function(d) {
return topnames.indexOf(d.name) > -1;
});
// nest by name and rank by total popularity
window.byYear = {}
d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.name; })
.sortValues(function(a,b) { return a.fraction - b.fraction; })
.rollup(function(leaves,i) {
return leaves[0].fraction;
})
.entries(data)
.forEach(function(year) {
byYear[year.key] = {};
year.values.forEach(function(name,i) {
byYear[year.key][name.key] = i;
});
});
var ctx = canvas.node().getContext("2d");
ctx.scale(devicePixelRatio, devicePixelRatio);
ctx.fillStyle = "#1a1a1a";
ctx.strokeStyle = "#1a1a1a";
ctx.font = "9px sans-serif";
ctx.textAlign = "right";
ctx.textBaseline = "middle";
// color fiddling
d3.range(8).map(color);
nested.slice(0,num).reverse().forEach(function(name,i) {
var yearspopular = name.values.data;
if (i > num-11) {
ctx.strokeStyle = color(name.key);
ctx.lineWidth = 2;
} else {
ctx.strokeStyle = "#bbb";
ctx.lineWidth = 1;
}
// bump line
ctx.globalAlpha = 0.75;
ctx.beginPath();
yearspopular.forEach(function(d,j) {
if (j == 0 || ((d.year - yearspopular[j-1].year) > 1)) {
ctx.moveTo(xscale(d.year), yscale(byYear[d.year][name.key]))
} else {
ctx.lineTo(xscale(d.year), yscale(byYear[d.year][name.key]));
}
});
ctx.stroke();
ctx.closePath();
});
nested.slice(0,num).reverse().forEach(function(name,i) {
var yearspopular = name.values.data;
if (i > num-11) {
ctx.fillStyle = color(name.key);
} else {
ctx.fillStyle = "#555";
}
// start names
ctx.globalAlpha = 0.9;
ctx.textAlign = "end";
var start = yearspopular[0].year;
ctx.fillText(name.key, xscale(start)-4, yscale(byYear[start][name.key]));
// end names
ctx.textAlign = "start";
var end= yearspopular[yearspopular.length-1].year;
ctx.fillText(name.key, xscale(end)+4, yscale(byYear[end][name.key]));
});
});
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fff;
}
</style>
<body>
<canvas width="960" height="700"></canvas>
<script src="//d3js.org/d3.v4.0.0-alpha.40.js"></script>
<script>
var width = 960,
height = 700,
margin = {top: 10, right: 10, bottom: 10, left: 70};
var devicePixelRatio = window.devicePixelRatio || 1;
var canvas = d3.select("canvas")
.attr("width", width * devicePixelRatio)
.attr("height", height * devicePixelRatio)
.style("width", width + "px")
.style("height", height + "px");
var ctx = canvas.node().getContext("2d");
ctx.scale(devicePixelRatio, devicePixelRatio);
var xscale = d3.scaleLinear()
.domain([1880,2015])
.range([margin.left,width-margin.right]);
var yscale = d3.scalePoint()
.domain(d3.range(70))
.range([margin.top, height-margin.bottom]);
var radius = d3.scaleSqrt()
.domain([0,0.1])
.range([0,4]);
d3.csv("girl-names.csv", function(error, data) {
data.forEach(function(d) {
d.fraction = +d.fraction;
d.year = +d.year;
});
// only girls
data = data.filter(function(d) {
return d.sex == "f";
});
// nest by name and rank by total popularity
var nested = d3.nest()
.key(function(d) { return d.name; })
.rollup(function(leaves) {
return {
data: leaves,
sum: d3.sum(leaves, function(d) { return d.fraction; })
};
})
.sortValues(function(a,b) { return a.sum - b.sum; })
.entries(data);
console.log(nested);
ctx.fillStyle = "#1a1a1a";
ctx.font = "11px sans-serif";
ctx.textAlign = "right";
ctx.textBaseline = "middle";
nested.forEach(function(name,i) {
ctx.fillText(name.key, xscale.range()[0]-6, yscale(i));
name.values.data.forEach(function(d) {
ctx.beginPath()
ctx.arc(xscale(d.year), yscale(i), radius(d.fraction), 0, 2*Math.PI);
ctx.fill();
});
});
});
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background: #fff;
}
svg,
canvas {
position: absolute;
}
</style>
<body>
<canvas></canvas>
<svg></svg>
<script src="//d3js.org/d3.v4.0.0-alpha.40.js"></script>
<script>
var num = 50;
var margin = {top: 10, right: 10, bottom: 30, left: 60};
var width = 960,
height = 500;
var devicePixelRatio = window.devicePixelRatio || 1;
var canvas = d3.select("canvas")
.attr("width", width * devicePixelRatio)
.attr("height", height * devicePixelRatio)
.style("width", width + "px")
.style("height", height + "px");
var svg = d3.select("svg")
.style("width", width + "px")
.style("height", height + "px");
var color = d3.scaleOrdinal()
.range(["#DB7F85", "#50AB84", "#4C6C86", "#C47DCB", "#B59248", "#DD6CA7", "#E15E5A", "#5DA5B3", "#725D82", "#54AF52", "#954D56", "#8C92E8", "#D8597D", "#AB9C27", "#D67D4B", "#D58323", "#BA89AD", "#357468", "#8F86C2", "#7D9E33", "#517C3F", "#9D5130", "#5E9ACF", "#776327", "#944F7E"]);
var xscale = d3.scaleLinear()
.domain([1880,2015])
.range([margin.left,width-margin.right]);
var xaxis = d3.axisBottom()
.scale(xscale);
svg.append("g")
.attr("transform", "translate(0," + (height-margin.bottom) + ")")
.call(xaxis);
var yscale = d3.scaleLinear()
.domain([0,num])
.range([margin.top, height-margin.bottom]);
var radius = d3.scaleSqrt()
.domain([0,0.1])
.range([0,4]);
d3.csv("girl-names.csv", function(error, data) {
data.forEach(function(d) {
d.fraction = +d.fraction;
d.year = +d.year;
});
// only girls
data = data.filter(function(d) {
return d.sex == "f";
});
// nest by name and rank by total popularity
var nested = d3.nest()
.key(function(d) { return d.name; })
.rollup(function(leaves) {
return {
data: leaves,
sum: d3.sum(leaves, function(d) { return d.fraction; })
};
})
.sortValues(function(a,b) { return a.sum - b.sum; })
.entries(data);
var topnames = nested.slice(0,num).map(function(d) { return d.key; });
data = data.filter(function(d) {
return topnames.indexOf(d.name) > -1;
});
// nest by name and rank by total popularity
window.byYear = {}
d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.name; })
.sortValues(function(a,b) { return a.fraction - b.fraction; })
.rollup(function(leaves,i) {
return leaves[0].fraction;
})
.entries(data)
.forEach(function(year) {
byYear[year.key] = {};
year.values.forEach(function(name,i) {
byYear[year.key][name.key] = i;
});
});
var ctx = canvas.node().getContext("2d");
ctx.scale(devicePixelRatio, devicePixelRatio);
ctx.fillStyle = "#1a1a1a";
ctx.strokeStyle = "#1a1a1a";
ctx.font = "10px sans-serif";
ctx.textAlign = "right";
ctx.textBaseline = "middle";
nested.slice(0,num).reverse().forEach(function(name,i) {
if (i > num-11) {
ctx.fillStyle = color(name.key);
ctx.strokeStyle = color(name.key);
ctx.lineWidth = 2;
} else {
ctx.fillStyle = "#999";
ctx.strokeStyle = "#bbb";
ctx.lineWidth = 1;
}
if (!(i % 0)) {
ctx.fillText(name.key, xscale.range()[0]-6, yscale(byYear[1880][name.key]));
}
ctx.beginPath();
name.values.data.forEach(function(d,j) {
if (j == 0 || ((d.year - name.values.data[j-1].year) > 1)) {
ctx.moveTo(xscale(d.year), yscale(byYear[d.year][name.key]))
} else {
ctx.lineTo(xscale(d.year), yscale(byYear[d.year][name.key]));
}
});
ctx.stroke();
ctx.closePath();
});
});
</script>