block by curran 649fe7203bf995a23478986f623b9673

Aggregated Foreign born population in Canada

Full Screen

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

index.html

<!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>

chart3Data.csv

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"

chart4Data.csv

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"