Built with blockbuilder.org
Last active
February 9, 2020 18:07
-
-
Save mforando/4a6c31d8450bf168dcbd66b00cebd209 to your computer and use it in GitHub Desktop.
Radial Sets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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