block by micahstubbs 391b2dd451189df324c68192e3e25848

es2015 d3 v4 curve interpolation comparison

Full Screen

lest you think I’ve abandoned modernity entirely, I present you with this ES2015 version of the bl.ock v4 curve interpolation comparison. the code found here follows the Airbnb JavaScript Style Guide, with the rule modifications described in this .eslintrc

{
  "extends": "airbnb",
  "rules": {
    "comma-dangle": "off",
    "no-param-reassign": "off",
    "no-restricted-syntax": "off",
    newline-per-chained-call: "off"
  }
}

this iteration also uses only inline styles, because reasons

a fork of this bl.ock which in turn is an iteration on @d3noob‘s’ v4 curve interpolation comparison


Original README.md:


This bl.ock demonstrates the range of interpolation curves available in v4 of d3.js.

You can click on any of the legend labels to toggle visibility of the lines.

Details of the curve can be found on the D3 wiki.

This graph is part of the code samples for the update to the book D3 Tips and Tricks to version 4 of d3.js.

index.html

<!DOCTYPE html>
<meta charset='utf-8'>
<body>
<!-- load the d3.js library -->    	
<script src='https://d3js.org/d3.v4.min.js'></script>
<!-- load the babel ES2015 to ES5 transpiler library --> 
<script src='https://npmcdn.com/babel-core@5.8.34/browser.min.js'></script>
<script lang='babel' type='text/babel'>
  // set the dimensions and margins of the graph
  const margin = { top: 20, right: 150, bottom: 30, left: 50 };
  const width = 960 - margin.left - margin.right;
  const height = 470 - margin.top - margin.bottom;

  // array of curve functions and titles
  const curveArray = [
    {
      d3Curve: d3.curveLinear,
      curveTitle: 'curveLinear'
    },
    {
      d3Curve: d3.curveStep,
      curveTitle: 'curveStep'
    },
    {
      d3Curve: d3.curveStepBefore,
      curveTitle: 'curveStepBefore'
    },
    {
      d3Curve: d3.curveStepAfter,
      curveTitle: 'curveStepAfter'
    },
    {
      d3Curve: d3.curveBasis,
      curveTitle: 'curveBasis'
    },
    {
      d3Curve: d3.curveCardinal,
      curveTitle: 'curveCardinal'
    },
    {
      d3Curve: d3.curveMonotoneX,
      curveTitle: 'curveMonotoneX'
    },
    {
      d3Curve: d3.curveCatmullRom,
      curveTitle: 'curveCatmullRom'
    }
  ];

  // parse the date and time
  const parseTime = d3.timeParse('%d-%b-%y');

  // set the range of the scales
  const x = d3.scaleTime()
    .range([0, width]);

  const y = d3.scaleLinear()
    .range([height, 0]);

  // append the svg object to the body of the page
  // append a 'group' element to 'svg'
  // move the 'group' element to the top left margin
  const 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})`);

  // get the data
  d3.csv('data-3.csv', (error, data) => {
    if (error) throw error;

    // format the data
    data.forEach(d => {
      d.date = parseTime(d.date);
      d.close = +d.close;
    });

    // set the color scale
    const color = d3.scaleOrdinal(d3.schemeCategory10);

    curveArray.forEach((daCurve, i) => {
      // scale the range of the data
      x.domain(d3.extent(data, d => d.date));
      y.domain(d3.extent(data, d => d.close));

      // create and configure line pathstring generator
      const line = d3.line()
                     .curve(daCurve.d3Curve)
                     .x(d => x(d.date))
                     .y(d => y(d.close));

      // add the paths with different curves
      svg.append('path')
        .datum(data)
        .attr('class', 'line')
        .style('stroke', () => {
          // Add the colors dynamically
          daCurve.color = color(daCurve.curveTitle);
          return daCurve.color;
        })
        .attr('id', `tag${i}`) // assign an ID
        .attr('d', line);

      // add the legend
      svg.append('text')
        .attr('x', width + 5) // space the legend
        .attr('y', margin.top + 20 + (i * 20))
        .attr('class', 'legend') // style the legend
        .style('fill', () => {
          // add the colors dynamically
          daCurve.color = color(daCurve.curveTitle);
          return daCurve.color;
        })
        .on('click', () => {
          // determine if current line is visible
          const active = daCurve.active !== true;
          const newOpacity = active ? 0 : 1;
          // hide or show the elements based on the ID
          d3.select(`#tag${i}`)
            .transition()
              .duration(100)
              .style('opacity', newOpacity);
          // update whether or not the elements are active
          daCurve.active = active;
        })
        .text(daCurve.curveTitle);
    });

    // add the 'all' option to the Legend
    svg.append('text')
        .attr('x', width + 5) // space the legend
        .attr('y', margin.top + 20 + (8 * 20))
        .attr('class', 'legend') // style the legend
        .style('fill', () => d3.schemeCategory10[8]) // add the colors dynamically
        .on('click', () => {
          d3.selectAll('.line')
            .transition()
            .duration(100)
            .style('opacity', 1);
        })
        .text('all');

      // add the 'none'option to the Legend
    svg.append('text')
      .attr('x', width + 5) // space the legend
      .attr('y', margin.top + 20 + (9 * 20))
      .attr('class', 'legend') // style the legend
      .style('fill', () => d3.schemeCategory10[9]) // add the colors dynamically
      .on('click', () => {
        d3.selectAll('.line')
          .transition()
          .duration(100)
          .style('opacity', 0);
      })
      .text('none');

    // add the scatterplot
    svg.selectAll('dot')
      .data(data)
      .enter().append('circle')
        .attr('r', 4)
        .attr('cx', d => x(d.date))
        .attr('cy', d => y(d.close));

    // configure the x-axis generator
    const xAxis = d3.axisBottom(x)
      .tickFormat(d3.timeFormat('%j')); // format as day-of-year

    // add the x-axis
    svg.append('g')
      .attr('class', 'axis')
      .attr('transform', `translate(0, ${height})`)
      .call(xAxis);

    // add the y-axis
    svg.append('g')
      .attr('class', 'axis')
      .call(d3.axisLeft(y));
    
    // styles
    d3.selectAll('.line')
      .style('fill', 'none')
      .style('stroke-width', '2px');

    d3.select('body')
      .style('font', '12px Arial');

    d3.selectAll('.legend')
      .style('font-size', '16px')
      .style('font-weight', 'bold')
      .style('text-anchor', 'left');
  });
</script>
</body>

data-3.csv

date,close
1-May-12,558.13
30-Apr-12,553.98
27-Apr-12,567.00
26-Apr-12,589.70
25-Apr-12,599.00
24-Apr-12,630.28
23-Apr-12,666.70
20-Apr-12,634.98
19-Apr-12,645.44
18-Apr-12,643.34
17-Apr-12,543.70
16-Apr-12,580.13
13-Apr-12,605.23
12-Apr-12,622.77
11-Apr-12,626.20
10-Apr-12,628.44
9-Apr-12,636.23
5-Apr-12,633.68
4-Apr-12,624.31
3-Apr-12,629.32
2-Apr-12,618.63
30-Mar-12,599.55
29-Mar-12,609.86
28-Mar-12,617.62
27-Mar-12,614.48
26-Mar-12,606.98