block by curran 43033756ea06f95a7f6794fe438ba48b

150 years of immigration in Canada

Full Screen

A stacked area chart visualization of 150 years of immigration in Canada. This variant shows the data scaled by percentages.

See also:

Uses d3-area-label to position labels.

Inspired by The Economist: Where do Canada’s immigrants come from?

forked from curran‘s block: How Americans Spend Time

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>
      
      d3.csv('data.csv', function (rawData) {
        
        const years = Object.keys(rawData[0])
          .filter(key => key !== 'Country/Area Name');
        const keys = rawData
          .map(d => d['Country/Area Name'])
          .filter(key => key !== 'Total - foreign-born population');
        
        const data = years.map(year => {
          const row = { date: new Date(year) };
          rawData.forEach(d => {
            row[d['Country/Area Name']] = +d[year];
          });
          return row;
        });
        console.log(data);
        render(data, keys);
      });

      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.stackOffsetExpand)
        .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>

data.csv

Country/Area Name,1871,1881,1891,1901,1911,1921,1931,1941,1951,1961,1971,1981,1991,2001,2011
Total - foreign-born population,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100
British Isles,83.6,78.1,74.2,55.8,49.4,52.4,49.4,47.6,45.5,35.2,29.5,23.3,17.2,11.6,8.3
Scandinavia,0.1,0.3,2,3.1,4.6,3.9,5.2,4.8,4.2,3.7,2.6,1.8,1.3,0.8,0.5
Western Europe,4.6,5.2,5.5,6.8,6.3,5.1,4.8,4.7,7.7,16.5,14.5,11.9,9.9,7.8,5.9
Eastern Europe,0.1,1.2,1.6,7.5,12,12.2,18,19.7,21.5,17.4,13.9,10.7,9.7,8.7,7.4
Southern Europe,0.1,0.2,0.5,1.1,2.6,2.3,3,3.3,4.5,12.2,19.3,19,16.3,13.1,9.2
United States,10.9,12.9,12.6,18.3,19.1,19.1,14.9,15.5,13.7,10,9.4,7.8,5.7,4.4,3.9
Caribbean and Bermuda,0,0.2,0.1,0.1,0.1,0.2,0.2,0.2,0.2,0.4,2.1,4.5,5.4,5.4,5.2
Central and South America,0,0,0,0,0.1,0.1,0.1,0.1,0.1,0,1.1,2.8,5.1,5.6,6.5
Northern Africa,0,0,0,0,0,0,0,0,0,0,0.9,1,1.2,1.7,2.8
Sub-Saharan Africa,0,0,0,0,0.1,0.1,0.1,0.1,0.1,0.1,0.3,1.6,2.6,3.5,4.5
Western Asia and Middle East,0,0,0,0.3,0.3,0.3,0.3,0.3,0.3,0,0.8,1.6,3.5,5.2,6.7
Eastern Asia,0,0.7,1.5,3.1,2.3,2.5,2.4,1.9,1.5,1.5,2,5.1,8.7,13.4,14.2
Southeast Asia,0,0,0,0,0,0,0,0,0,0,0.4,4,7.2,8.6,10.8
Southern Asia,0,0.1,0.1,0.2,0.3,0.2,0.2,0.2,0.2,0.3,1.4,3.4,5.3,9.2,13.2
Oceania and other,0.7,1,1.8,3.7,2.6,1.5,1.5,1.6,0.4,2.7,2,1.5,1.1,1,0.8