Built with blockbuilder.org
Last active
March 4, 2018 21:15
-
-
Save mdequeljoe/a4de62784b61333e2b6992c6a5414d3a to your computer and use it in GitHub Desktop.
grouped arc chords
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
(function (global, factory) { | |
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array')) : | |
typeof define === 'function' && define.amd ? define(['exports', 'd3-array'], factory) : | |
(factory((global.d3 = global.d3 || {}),global.d3)); | |
}(this, function (exports,d3Array) { 'use strict'; | |
function compareValue(compare) { | |
return function(a, b) { | |
return compare( | |
a.source.value + a.target.value, | |
b.source.value + b.target.value | |
); | |
}; | |
} | |
function chord2() { | |
var padAngle = 0, | |
arcGroups = null, | |
chordSum = null, | |
sortArcGroups = null, | |
sortSubgroups = null, | |
sortChords = null; | |
function chord2(matrix) { | |
var n = matrix.length, | |
arcn = arcGroups.length, | |
ag = d3Array.range(arcn), | |
tau = Math.PI * 2, | |
groupSums = [], | |
groupIndex = d3Array.range(n), | |
arcGroupIndex = [], | |
arcGroupSums = [], | |
subgroupIndex = [], | |
chords = [], | |
groups = chords.groups = new Array(n), | |
subgroups = new Array(n * n), | |
x, | |
x0, | |
i, | |
j, | |
g, | |
sj = 0, | |
gs = 0, | |
k, | |
k0, | |
dx, | |
dxIndex = []; | |
//add in any groups (rows) not specified under arcGroups | |
// to arcGroups and arcGroupsIndex | |
arcGroupIndex = [].concat.apply([], arcGroups) | |
for (i = 0; i < groupIndex.length; i++){ | |
if (arcGroupIndex.indexOf(groupIndex[i]) == -1) { | |
arcGroupIndex.push(groupIndex[i]) | |
arcGroups.push(groupIndex[i]) | |
} | |
} | |
// Compute the sum. | |
k = 0, i = -1; while (++i < n) { | |
x = 0, j = -1; while (++j < n) { | |
x += matrix[i][j]; | |
} | |
groupSums.push(x); | |
subgroupIndex.push(d3Array.range(n)); | |
k += x; | |
} | |
// Convert the sum to scaling factor for [0, 2pi]. | |
// scale by chordSum - adjust dx to space groups evenly | |
if (chordSum) { | |
k0 = k; | |
k = (chordSum > k0) ? chordSum: k; | |
} | |
//need to account for uneven groupings | |
if (arcGroups) k = Math.max(0, tau - padAngle * (n - arcn)) / k; | |
else k = Math.max(0, tau - padAngle * n) / k; | |
dx = k ? padAngle : tau / n; | |
if (chordSum) dx = (tau - padAngle - k0 * k) / arcn | |
if (arcGroups){ | |
//calc sum for arc groups | |
//set dx for each group according to arcGroup and shift forward one | |
for (i = 0; i < arcGroups.length; i++){ | |
g = (arcGroups[i].length) ? arcGroups[i].length : 1 | |
for (j = 0; j < g; j++){ | |
sj += groupSums[gs] | |
gs++ | |
if (i < 1 || j > 0) dxIndex.push(0) | |
else dxIndex.push(dx) | |
} | |
arcGroupSums.push(sj) | |
sj = 0; | |
} | |
dxIndex.shift() | |
dxIndex.push(0) | |
groupIndex = arcGroupIndex | |
} | |
//sort groups excluded by sortArcGroups ? | |
//this needs to be fixed... | |
if (sortArcGroups) { | |
ag.sort(function(a, b) { | |
return sortArcGroups(arcGroupSums[a], arcGroupSums[b]); | |
}); | |
var ags = []; | |
ag.forEach(function(i){ags.push(arcGroups[i])}) | |
groupIndex = [].concat.apply([], ags) | |
for (i = 0; i < n; i++){ | |
if (groupIndex.indexOf(arcGroupIndex[i]) == -1) { | |
groupIndex.push(arcGroupIndex[i]) | |
} | |
} | |
} | |
// Sort subgroups… | |
if (sortSubgroups) subgroupIndex.forEach(function(d, i) { | |
d.sort(function(a, b) { | |
return sortSubgroups(matrix[i][a], matrix[i][b]); | |
}); | |
}); | |
// Compute the start and end angle for each group and subgroup. | |
// Note: Opera has a bug reordering object literal properties! | |
x = 0, i = -1; while (++i < n) { | |
x0 = x, j = -1; while (++j < n) { | |
var di = groupIndex[i], | |
dj = subgroupIndex[di][j], | |
v = matrix[di][dj], | |
a0 = x, | |
a1 = x += v * k; | |
subgroups[dj * n + di] = { | |
index: di, | |
subindex: dj, | |
startAngle: a0, | |
endAngle: a1, | |
value: v | |
}; | |
} | |
groups[di] = { | |
index: di, | |
startAngle: x0, | |
endAngle: x, | |
value: groupSums[di] | |
}; | |
if (arcGroups) x += dxIndex[i] | |
else x += dx; | |
} | |
// Generate chords for each (non-empty) subgroup-subgroup link. | |
i = -1; while (++i < n) { | |
j = i - 1; while (++j < n) { | |
var source = subgroups[j * n + i], | |
target = subgroups[i * n + j]; | |
if (source.value || target.value) { | |
chords.push(source.value < target.value | |
? {source: target, target: source} | |
: {source: source, target: target}); | |
} | |
} | |
} | |
return sortChords ? chords.sort(sortChords) : chords | |
} | |
chord2.padAngle = function(_) { | |
return arguments.length ? (padAngle = Math.max(0, _), chord2) : padAngle; | |
}; | |
chord2.arcGroups = function(_){ | |
return arguments.length ? ((arcGroups = _), chord2) : arcGroups; | |
}; | |
chord2.chordSum = function(_){ | |
return arguments.length ? (chordSum = _, chord2) : chordSum; | |
} | |
chord2.sortArcGroups = function(_) { | |
return arguments.length ? (sortArcGroups = _, chord2) : sortArcGroups; | |
}; | |
chord2.sortSubgroups = function(_) { | |
return arguments.length ? (sortSubgroups = _, chord2) : sortSubgroups; | |
}; | |
chord2.sortChords = function(_) { | |
return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord2) : sortChords && sortChords._; | |
}; | |
return chord2 | |
} | |
exports.chord2 = chord2; | |
Object.defineProperty(exports, '__esModule', { value: true }); | |
})); |
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> | |
<script src="d3-chord2.js"></script> | |
<style> | |
body { | |
margin:0; position:fixed; top:0; right:0; bottom:0; left:0; } | |
</style> | |
</head> | |
<body> | |
<script> | |
var m1 = [[0,0,0,0,0,0,0,0,0,2.58],[0,0,14.97,0,0.45,0,0.76,0,0,0],[0,14.97,0,0,0,0,0,2.26,0,0],[0,0,0,0,0.08,0,0,0,14.54,0],[0,0.45,0,0.08,0,0,0,0,0,0],[0,0,0,0,0,0,0.69,0,5.11,0],[0,0.76,0,0,0,0.69,0,0,0,1.98],[0,0,2.26,0,0,0,0,0,0,0],[0,0,0,14.54,0,5.11,0,0,0,0],[2.58,0,0,0,0,0,1.98,0,0,0]]; | |
var sectors = [ | |
[0, 1], | |
[2, 3], | |
[4, 5], | |
[6, 7], | |
[8, 9] | |
] | |
var width = 300, | |
height = 400, | |
outerRadius = Math.min(width, height) * 0.5 - 35, | |
innerRadius = outerRadius - 20; | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var chord = d3.chord2() | |
.padAngle(0.35) | |
.arcGroups(sectors) | |
.sortArcGroups(d3.ascending) | |
.sortSubgroups(d3.descending) | |
var arc = d3.arc() | |
.innerRadius(innerRadius) | |
.outerRadius(outerRadius); | |
var ribbon = d3.ribbon() | |
.radius(innerRadius) | |
var color = d3.scaleOrdinal() | |
.domain(d3.range(2)) | |
.range(["steelblue", "#b1b5b7"]); | |
var g = svg.append("g") | |
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") | |
.datum(chord(m1)); | |
var group = g.append("g") | |
.attr("class", "groups") | |
.selectAll("g") | |
.data(function(d) { return d.groups; }) | |
.enter().append("g"); | |
group.append("path") | |
.style("fill", function(d) { return color(d.index); }) | |
.style("stroke", "black") | |
.attr("opacity", 0.4) | |
.attr("d", arc); | |
g.append("g") | |
.attr("class", "ribbons") | |
.selectAll("path") | |
.data(function(d) {return d; }) | |
.enter().append("path") | |
.attr("d", ribbon) | |
.style("opacity", 0.4) | |
.style("fill", 'gray') | |
.style("stroke", "black") | |
.on('mouseover', function(){ | |
d3.select(this).style('opacity', 0.9) | |
}) | |
.on('mouseout', function(){ | |
d3.select(this).style('opacity', 0.4) | |
}) | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment