JSFiddle - React, Tailwind, and code Playground

by John Schulz

HTML

<form>
  <label><input type="radio" name="mode" value="multiples" checked> Multiples</label>
  <label><input type="radio" name="mode" value="stacked"> Stacked</label>
</form>

CSS

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  margin: auto;
  position: relative;
  width: 960px;
}

text {
  font: 10px sans-serif;
}

.axis path {
  display: none;
}

.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.group-label {
  font-weight: bold;
  text-anchor: end;
}

form {
  position: absolute;
  right: 10px;
  top: 10px;
}

Babel + JSX

const stacksTSV = 'https://gist.githubusercontent.com/jfsiii/9c286eabcc93605e48ea/raw/38a853bcd1f53f5f1f6286ec4342ae766c98f5eb/data.tsv';

d3.tsv(stacksTSV, function(error, data) {

  const parseDate = d3.time.format("%Y-%m").parse,
      formatYear = d3.format("02d"),
      formatDate = d => "Q" + ((d.getMonth() / 3 | 0) + 1) + formatYear(d.getFullYear() % 100);

  const margin = {top: 10, right: 20, bottom: 20, left: 60},
      width = 960 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;

  const y0 = d3.scale.ordinal()
      .rangeRoundBands([height, 0], 0.2);

  const y1 = d3.scale.linear();

  const x = d3.scale.ordinal()
      .rangeRoundBands([0, width], 0.1, 0);

  const xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom")
      .tickFormat(formatDate);

  const nestedByGroup = d3.nest().key(d => d.group);

  const stack = d3.layout.stack()
      .values(d => d.values)
      .x(d => d.date)
      .y(d => d.value)
      .out((d, y0) => d.valueOffset = y0);

  const color = d3.scale.category10();

  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})`);

  data.forEach(d => {
    d.date = parseDate(d.date);
    d.value = +d.value;
  });

  const dataByGroup = nestedByGroup.entries(data);

  stack(dataByGroup);
  x.domain(dataByGroup[0].values.map(d => d.date));
  y0.domain(dataByGroup.map(d => d.key));
  y1.domain([0, d3.max(data, d => d.value)]).range([y0.rangeBand(), 0]);

  const group = svg.selectAll(".group")
      .data(dataByGroup)
    .enter().append("g")
      .attr("class", "group")
      .attr("transform", d => `translate(0, ${ y0(d.key) })`);

  group.append("text")
      .attr({
        class: "group-label",
        x: -6,
        y: d => y1(d.values[0].value / 2),
        dy: ".35em"
      })
      .text(d => "Group...