Skip to content

Instantly share code, notes, and snippets.

@tomgp
Created October 18, 2018 13:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomgp/52c357df19e79c8336052c831e5e0f8a to your computer and use it in GitHub Desktop.
Save tomgp/52c357df19e79c8336052c831e5e0f8a to your computer and use it in GitHub Desktop.
Stacked and stepped area chart
A B C D E F
1233 1037 2433 15167 5 33
1430 1161 3134 15956 4 34
1338 1258 2342 15416 1 44
1304 1224 2646 15176 1 29
1524 1478 2426 14601 2 31
1350 1381 2732 15405 3 37
1354 1534 2673 16022 17 36
1375 1394 2144 12426 9 30
1563 1293 2903 14888 7 42
1589 1461 2664 17040 7 35
1695 1466 3168 16945 9 45
1309 1596 2402 14898 3 24
1190 1585 2657 14506 3 31
1060 1461 2154 15428 5 31
1416 1570 2241 16746 9 43
1329 1339 2206 15042 4 31
1488 1335 2504 15362 6 34
1232 1212 2473 16423 8 44
1004 1459 2226 15380 8 36
1002 1332 1607 15036 4 50
1351 1784 2385 15898 2 43
1196 1830 2503 16040 5 47
1172 1923 2411 15079 6 35
1050 2025 2558 12790 8 36
1068 1347 1870 13899 13 31
1116 1658 2180 12533 3 35
1397 1471 2179 13065 5 43
<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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment