D3 Chord Duplication Prevention
This demo (not my code) compares two different categories of items to each other, so - unlike a chord diagram where any item can be connected to any other item - coffee shops cannot be connected to a coffee shop and states cannot be connected to states.
Some wedges look like this if Donkin donuts appear first:
But other wedges look like this if Starbucks has a higher value in state:
An unnecessary overlap in my opinion. The order of the elements should not be dictated by their value, but instead by the order of the elements to the left - that is, always Dunkin 'first.
I see the view that is happening in
var chord = d3.layout.chord()
.padding(.02)
.sortSubgroups(d3.descending)
but I'm not sure how I can specify a custom sorting for the state items. It makes sense to sort the subgroups by coffee shop (or in ascending order), but conditions should not be treated the same way.
How do we know if a chord is a state or not? It looks like the information can be pulled by passing the chord to the rdr
function instance chordRdr
that binds matrix
, which is what is sorted for meta information from the object mmap
.
How do I create a conditional subgroup?
source to share
Short answer: you cannot do this in d3.
This is how d3 does the sort:
// Sort subgroups…
if (sortSubgroups) {
subgroupIndex.forEach(function(d, i) {
d.sort(function(a, b) {
return sortSubgroups(matrix[i][a], matrix[i][b]);
});
});
}
It will sort for each subgroup.
The only way you can finish this job is to create a custom copy d3.chord.layout()
, which can be found at the link above if you want to play around with it.
source to share
I would not recommend using this solution :
//all the values in matrix are integers
//we can track the numbers that are starbucks stores
//by adding a small decimal to them
matrix = matrix.map(function(row){
return row.map(function(d, i){
return d + (i == row.length - 1 ? 1e-7 : 0) })
})
//now we can do a lexicographic sort
//first checking for the presence of a decimal and then size
var chord = d3.layout.chord()
.sortSubgroups(function(a, b){
if (a != Math.round(a)) return false
if (b != Math.round(b)) return true
return b < a ? -1 : b > a ? 1 : 0;
})
Modifying d3.layout.chord
or starting with something simpler that doesn't require a redundant matrix of values will probably work better in most situations.
source to share