A StreamGraph visualization of 150 years of immigration in Canada, Chart 3 and Chart 4, aggregated into regions. Inspired by The Economist: Where do Canada’s immigrants come from?, in which a similar aggregation was performed.
See also:
Uses d3-area-label to position labels.
forked from curran‘s block: All Foreign born population in Canada
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://unpkg.com/d3@4.10.0"></script>
<script src="https://unpkg.com/d3-area-label@1.2.0"></script>
<title>Foreign Born in Canada</title>
<style>
body {
margin: 0px;
}
.area-label {
font-family: sans-serif;
fill-opacity: 0.7;
fill: white;
}
path:hover {
fill-opacity: 1;
fill:black;
}
path {
fill-opacity: 0.8;
stroke-width: 0.5;
}
text {
pointer-events: none;
}
.axis--major .tick text, .legend text, .tooltip text {
fill: #585858;
font-family: sans-serif;
font-size: 16pt;
}
.axis--minor .tick text {
display: none;
}
.axis--major .tick line{
stroke: #ddd;
stroke-width: 2px;
}
.axis--minor .tick line{
stroke: #eee;
}
.axis .domain {
display: none;
}
</style>
</head>
<body>
<svg width="960" height="500"></svg>
<script>
function processChart3Data (chart3Data) {
const keys = Object.keys(chart3Data[0]).filter(key => key !== 'Year');
const data = chart3Data.map(d => {
d.date = new Date(d.Year);
keys.forEach(key => {
d[key] = +d[key].replace(/,/g, '');
});
return d;
});
return { data, keys };
}
function processChart4Data (chart4Data) {
const nameColumn = 'Area of interest';
const years = Object.keys(chart4Data[0]).filter(key => key !== nameColumn);
const keys = chart4Data.map(d => d[nameColumn]);
const data = years.map(year => {
const row = {
date: new Date(year),
Year: year
};
chart4Data.forEach(d => {
row[d[nameColumn]] = +d[year].replace(/,/g, '');
});
return row;
});
return { data, keys };
}
d3.queue()
.defer(d3.csv, 'chart3Data.csv')
.defer(d3.csv, 'chart4Data.csv')
.await(function(error, chart3Data, chart4Data) {
const chart3 = processChart3Data(chart3Data);
const chart4 = processChart4Data(chart4Data);
const chart4DataByYear = {};
chart4.data.forEach(d => chart4DataByYear[d.Year] = d);
const keys = chart3.keys.concat(chart4.keys);
const data = chart3Data.map(d => {
const chart4d = chart4DataByYear[d.Year];
chart4.keys.forEach(key => {
d[key] = chart4d ? chart4d[key] : 0;
});
return d;
});
const aggregations = {
'United States': ['United States'],
'British Isles': ['British Isles'],
'Europe': [
'Western Europe',
'Eastern Europe',
'Scandinavia',
'Southern Europe'
],
'Caribbean and Bermuda': ['Caribbean and Bermuda'],
'Central and South America': ['Central and South America'],
'Africa': [
'Northern Africa',
'Sub-Saharan Africa'
],
'Asia': [
'Eastern Asia',
'Southeast Asia',
'Southern Asia'
],
'Oceania': ['Oceania'],
'Middle East': ['Western Asia and Middle East']
};
const aggregatedData = data.map(d => {
const row = { date: d.date};
Object.keys(aggregations).forEach(aggregation => {
row[aggregation] = 0;
aggregations[aggregation].forEach(key => {
row[aggregation] += d[key];
});
});
return row;
});
render(aggregatedData, Object.keys(aggregations));
});
var margin = { top: 0, bottom: 25, left: 0, right: 20 };
var svg = d3.select('svg');
var width = +svg.attr('width');
var height = +svg.attr('height');
var g = svg.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
var xAxisG = g.append('g')
.attr('class', 'axis');
var xAxisMinorG = xAxisG.append('g')
.attr('class', 'axis axis--minor');
var xAxisMajorG = xAxisG.append('g')
.attr('class', 'axis axis--major');
var marksG = g.append('g');
var stack = d3.stack()
.offset(d3.stackOffsetWiggle)
.order(d3.stackOrderInsideOut)
;
var xValue = function (d) { return d.date; };
var xScale = d3.scaleTime();
var yScale = d3.scaleLinear();
var colorScale = d3.scaleOrdinal().range(d3.schemeCategory10);
var xAxisMajor = d3.axisBottom().scale(xScale);
var xAxisMinor = d3.axisBottom().scale(xScale).ticks(30);
var area = d3.area()
.x(d => xScale(xValue(d.data)))
.y0(d => yScale(d[0]))
.y1(d => yScale(d[1]))
.curve(d3.curveBasis);
// Render StreamGraph
function render(data, keys) {
stack.keys(keys);
var stacked = stack(data);
var innerWidth = width - margin.right - margin.left;
var innerHeight = height - margin.top - margin.bottom;
xScale
.domain(d3.extent(data, xValue))
.range([0, innerWidth]);
yScale
.domain([
d3.min(stacked, function (series) {
return d3.min(series, function (d) { return d[0]; });
}),
d3.max(stacked, function (series) {
return d3.max(series, function (d) { return d[1]; });
})
])
.range([innerHeight, 0]);
colorScale.domain(d3.range(keys.length));
var paths = marksG.selectAll('path').data(stacked);
var pathsEnter = paths
.enter().append('path');
pathsEnter.merge(paths)
.attr('fill', function (d) { return colorScale(d.index); })
.attr('stroke', function (d) { return colorScale(d.index); })
.attr('d', area);
paths.select('title')
.merge(pathsEnter.append('title'))
.text(function (d) { return d.key; })
var labels = marksG.selectAll('text').data(stacked)
labels
.enter().append('text')
.attr('class', 'area-label')
.merge(labels)
.text(function (d) { return d.key; })
.attr('transform', d3.areaLabel(area).interpolateResolution(1000));
xAxisMajor.tickSize(-innerHeight);
xAxisMinor.tickSize(-innerHeight);
xAxisG.attr('transform', `translate(0,${innerHeight})`);
xAxisMajorG.call(xAxisMajor);
xAxisMinorG.call(xAxisMinor);
}
</script>
</body>
</html>
Year,United States,Western Europe,Eastern Europe,Scandinavia,British Isles,Southern Europe
1871,"64,600","27,200",400,600,"496,600",500
1881,"77,800","31,400","7,000","2,100","470,900","1,400"
1891,"80,900","35,400","10,600","12,600","477,700","3,400"
1901,"127,900","47,600","52,300","21,400","390,000","8,000"
1911,"303,700","100,700","191,100","72,300","784,500","41,700"
1921,"374,000","99,700","238,900","77,000","1,025,000","45,300"
1931,"344,600","110,400","415,400","120,400","1,138,900","69,000"
1941,"312,500","94,000","397,500","96,800","960,100","66,400"
1951,"282,000","157,700","443,700","86,600","936,600","92,600"
1961,"283,900","470,100","493,800","104,100","1,000,600","346,900"
1971,"309,600","477,100","458,200","85,100","971,500","634,900"
1981,"301,500","458,400","409,400","70,900","895,700","728,900"
1991,"249,100","431,500","420,500","55,000","746,100","707,300"
2001,"237,900","423,800","471,400","45,200","631,800","715,400"
2011,"263,500","397,400","501,600","36,200","565,400","626,600"
Area of interest,1951,1961,1971,1981,1991,2001,2011
Caribbean and Bermuda,"4,400","12,400","68,100","173,200","232,500","294,100","351,400"
Central and South America,"3,100",0,"36,000","106,800","219,400","304,700","442,700"
Northern Africa,400,0,"28,700","38,700","53,200","93,200","186,700"
Sub-Saharan Africa,"2,400","4,000","10,700","63,000","113,000","189,500","305,300"
Western Asia and Middle East,"6,500",0,"25,200","63,200","151,100","285,600","456,000"
Eastern Asia,"30,800","43,500","66,600","195,500","377,200","730,600","962,600"
Southeast Asia,800,0,"13,100","152,200","312,000","469,100","729,800"
Southern Asia,"4,200","9,000","46,300","130,000","228,800","503,900","892,800"
Oceania,"6,100","6,700","14,300","33,000","38,000","47,900","54,500"