Skip to content

Instantly share code, notes, and snippets.

@tezzutezzu
Last active December 22, 2017 23:08
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 tezzutezzu/087047d6e9d8bf088cad86d6517e129a to your computer and use it in GitHub Desktop.
Save tezzutezzu/087047d6e9d8bf088cad86d6517e129a to your computer and use it in GitHub Desktop.
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment