D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
tomgp
Full window
Github gist
Stacked and stepped area chart
<html> <head> <style> body{ font-family:sans-serif; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.5.0/d3.min.js"></script> </head> <body> <h1>stacked & stepped area chart</h1> <svg></svg> </body> <script> const categoryColours = [ 'rgba(255,0,0,1)', 'rgba(0,255,0,1)', 'rgba(0,0,255,1)', 'rgba(255,255,0,1)', 'rgba(255,0,255,1)', 'rgba(0,255,255,1)', ]; const stackLayout = (data, properties, range, blockWidth = 30) => { const rowTotals = data .map(row => d3.sum(properties.map(key => row[key]))); const blockScale = d3.scaleLinear() .range(range) .domain([0,d3.max(rowTotals)]); const colorScale = d3.scaleOrdinal() .range(categoryColours) .domain(properties); const areas = []; const rowPositions = data.map((row,i) => { let rowAccumulator = plotHeight; properties.forEach((property) => { const blockSize = blockScale(row[property]); rowAccumulator -= blockSize; row[property] = { height: blockSize, x: blockWidth * i, y: rowAccumulator, data: { value:row[property], property }, color: colorScale(property), width: blockWidth, }; areas.push(row[property]); }); return row; }); const areaSeparators = properties.map((property, i)=>{ let xAccumulator = 0; const line = []; data.forEach(d => { const y = d[property].y; line.push({ x: xAccumulator, y }); xAccumulator += blockWidth; line.push({ x: xAccumulator, y }); }); return { property, line }; }); return { rects: areas, lines: areaSeparators, } } const width = 700, height = 700, margin = { top:20, bottom:20, left:20, right:20 }; const plotWidth = width - (margin.left+margin.right); const plotHeight = height - (margin.top+margin.bottom); d3.select('svg') .attr('width',width) .attr('height',height) .append('g') .attr('class','plot') .attr('transform',`translate(${margin.left}, ${margin.right})`); d3.csv('data.csv') .then((data) => { const { rects, lines } = stackLayout( data, 'A,B,C,D,E,F'.split(','), [0, plotHeight], plotWidth/data.length, ); d3.select('.plot') .selectAll('rect') .data(rects) .enter() .append('rect') .attr('x', d=>d.x) .attr('y', d=>d.y) .attr('width', d=>d.width) .attr('height', d=>d.height) .attr('fill', d=>d.color) .attr('stroke', d=>d.color) .attr('data-key', d=>d.data.property) .attr('data-value', d=>d.data.value); const separator = d3.line() .x(d=>d.x) .y(d=>d.y); d3.select('.plot') .selectAll('path') .data(lines) .enter() .append('path') .attr('d', d=>separator(d.line)) .attr('fill','none') .attr('stroke','rgba(0,0,0,1)') .attr('stroke-width', 3); }); </script> </html>
https://cdnjs.cloudflare.com/ajax/libs/d3/5.5.0/d3.min.js