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