Skip to content

Instantly share code, notes, and snippets.

@mforando
Last active February 9, 2020 18:07
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 mforando/4a6c31d8450bf168dcbd66b00cebd209 to your computer and use it in GitHub Desktop.
Save mforando/4a6c31d8450bf168dcbd66b00cebd209 to your computer and use it in GitHub Desktop.
Radial Sets
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
var dimensions = d3.range(4);
var data = [{'categoryA':'A', 'categoryB': 'A','categoryC':'A', 'categoryD': 'C'},
{'categoryA':'A', 'categoryB': 'B','categoryC':'B', 'categoryD': 'C'},
{'categoryA':'A', 'categoryB': 'B','categoryC':'A', 'categoryD': 'C'},
{'categoryA':'A', 'categoryB': 'C','categoryC':'A', 'categoryD': 'C'},
{'categoryA':'A', 'categoryB': 'B','categoryC':'A', 'categoryD': 'C'},
{'categoryA':'B', 'categoryB': 'A','categoryC':'B', 'categoryD': 'C'},
{'categoryA':'B', 'categoryB': 'A','categoryC':'A', 'categoryD': 'C'},
{'categoryA':'C', 'categoryB': 'B','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'C', 'categoryB': 'C','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'C','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'C','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'C','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'B','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'A','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'A','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'C', 'categoryB': 'A','categoryC':'B', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'A','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'B', 'categoryB': 'B','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'B','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'D', 'categoryB': 'B','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'E', 'categoryB': 'A','categoryC':'A', 'categoryD': 'A'},
{'categoryA':'E', 'categoryB': 'A','categoryC':'A', 'categoryD': 'A'}]
//
var compiled = [];
data.forEach((d, i)=>{
var combinations = d3.cross(Object.keys(d), Object.keys(d)).filter((z)=>{return z[0] != z[1];});
combinations.forEach((columns)=>{
compiled.push({'sourceDimension': columns[0], 'sourceCategory': d[columns[0]], 'targetDimension': columns[1], 'targetCategory': d[columns[1]],});
})
d.id = i;
})
//calculate each groups percent of total for each category.
var nested = d3.nest()
.key((d)=>{return d.sourceDimension;})
.key((d)=>{return d.sourceCategory;})
.key((d)=>{return d.targetCategory;})
.entries(compiled);
nested.forEach((sourceDim)=>{
var sourceTotal = 0;
sourceDim.values.forEach((sourceCat)=>{
sourceCat.values.forEach((targetCategory)=>{
sourceTotal = sourceTotal + targetCategory.values.length;
targetCategory.count = targetCategory.values.length;
});
sourceCat.count = sourceTotal;
})
sourceDim.count = sourceTotal;
});
console.log(nested);
// Feel free to change or delete any of the code you see in this editor!
var width = 500;
var height = 500;
var pad = 50;
var radius = Math.min(width - pad*2, height - pad*2)/2;
// compute an initial pie layout
var pie = d3.pie().value(1)(nested);
var bars = [];
//first level = dimensions
//second level = stacked bars
//third level = chords
// use d3 interpolator to get x,y values along line.
pie.forEach((d)=>{
var x1 = Math.cos(d.startAngle)*radius;
var x2 = Math.cos(d.endAngle)*radius;
var y1 = Math.sin(d.startAngle)*radius;
var y2 = Math.sin(d.endAngle)*radius;
// push coordinates for the stacked bars to begin and end.
d.polarCoords = [d3.interpolate([x1,y1],[x2,y2])(0.2),d3.interpolate([x1,y1],[x2,y2])(.8)];
d.data.values.forEach((bar)=>{
var cumulative = 0;
bar.pcnt = bar.count/d.data.count;
bar.cumulative = cumulative;
cumulative = cumulative + bar.pcnt;
bars.push({'x1':d3.interpolate(d.polarCoords[0],d.polarCoords[1])(bar.cumulative)[0],
'x2':d3.interpolate(d.polarCoords[0],d.polarCoords[1])(bar.cumulative + bar.pcnt)[0],
'y1':d3.interpolate(d.polarCoords[0],d.polarCoords[1])(bar.cumulative)[1],
'y2':d3.interpolate(d.polarCoords[0],d.polarCoords[1])(bar.cumulative + bar.pcnt)[1],
'data':bar,
})
})
console.log(d.data.values);
console.log(bars);
//figure out
})
// figure out the distance for the total scale.
// convert polar coordinates back to normal for easy axes.
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
var chart = svg.append('g')
.attr('transform','translate(' + width/2 + ',' + height/2 + ')')
var lines = chart.selectAll("line").data(bars);
lines.enter()
.append('line')
.attr("x1", (d)=>{return d.x1})
.attr("x2", (d)=>{return d.x2})
.attr("y1", (d)=>{return d.y1})
.attr("y2", (d)=>{return d.y2})
.attr("stroke", "black")
.style('opacity',(d,i)=>{
return i*.05;
})
.style('stroke-width', '12px')
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment