D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
tezzutezzu
Full window
Github gist
Incremental nested grouped chart
<!DOCTYPE html> <style> .container { fill:none; stroke: black; } </style> <svg width="960" height="500"></svg> <script src="https://d3js.org/d3.v4.min.js"></script> <script> var svg = d3.select("svg"), margin = {top: 20, right: 20, bottom: 30, left: 40}, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom, g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var y = d3.scaleLinear() .rangeRound([height, 0]); let colors =["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]; var z = d3.scaleOrdinal().range(colors); function weightedRand(spec) { var i, j, table=[]; for(i=0; i<spec.length; i++) { for (j=0; j<spec[i]*10; j++) { table.push(i); } } return function() { return table[Math.floor(Math.random() * table.length)]; } } let randFirst = weightedRand([.8, .4, .2]); let randSecond = weightedRand([.9, .2, .01,.01]); const ELEMENTS = 100; const GROUPS = 4; const PADDING = 1; const INNERPADDING = .1; let data = []; d3.range(0,GROUPS).forEach(d=>{ d3.range(0, ((Math.random()*4)|0)+1 ).forEach(dd=>{ if(Math.random() > .6) { d3.range(0, ELEMENTS).forEach(ddd=>{ data.push({ first: "f"+d, second: "s"+dd, third: Math.random() }); }); } }) }); let nestedData = d3.nest() .key(d=>d.first).sortKeys(d3.descending) .key(d=>d.second).sortKeys(d3.descending) .key(d=>d.third) .rollup(d=>d.length).entries(data) nestedData.forEach(d=>{ d.max = d3.max(d.values, dd=>dd.values.length) d.sum = d3.sum(d.values, dd=>dd.values.length) d.values.sort((a,b)=>b.values.length-a.values.length) console.log(d.values) }); nestedData.sort((a,b)=>b.sum-a.sum); let groupsNumber = d3.nest().key(d=>d.first + d.second).rollup(d=>d.length).entries(data).length; let y0 = d3.scaleLinear().domain([0, groupsNumber + (PADDING * (nestedData.length-1)) + (INNERPADDING * (groupsNumber))]).range([0,height]).range([0, height]); let x0 = d3.scaleLinear().domain([0, ELEMENTS]).range([0,width]).range([0, width]); let yPositions = []; let yPos = 0; let gs = g.append("g") .selectAll("g") .data(nestedData) .enter() .append("g") .attr("transform", (d,i)=>{ let t = `translate(0, ${y0(yPos)})`; yPos += d.values.length + PADDING + d.values.length * INNERPADDING; return t; }) let gs2 = gs.selectAll(".bar") .data(d=>d.values) .enter() .append("g") .attr("transform", (d,i)=>{ let t = `translate(0, ${y0(i + INNERPADDING)})`; return t; }) gs2.selectAll(".bar") .data((d,i)=>d.values.map(dd=>{ return { data: dd, parent: d } })) .enter() .append("rect") .attr("class", "bar") .attr("fill", d=>z(d.parent.key)) .attr("height", (d,i)=>y0(d.data.key -INNERPADDING)) .attr("width", x0(1)) .attr("x", (d,i)=>x0(i)) .attr("y", (d,i)=>y0(1)-y0(d.data.key)) </script>
https://d3js.org/d3.v4.min.js