Be warned, there is a lot of badly written javascript ahead - and you will have to know how to draw a d3 sunburst chart already. This is just explaining how to intergrate it with crossfilter and DC.js.
As a reference, our data looks something like....
YEAR,COURT,OFFENCE,AGEGROUP,SENTENCE,Value
2000,10,012,F,28,1
2000,10,012,F,T,1
2000,10,0132,D,7,1
2000,10,0132,D,T,1
2000,10,0132,G,28,1
2000,10,0132,G,T,1
Crossfilter doesn't do hierarchical data so, dc.js doesn't normally do so either, but we have never let this stop us in the past, so here we go.
step one, turn one of your dimensions into an array. This will give you the hierarchical aspect to the data.
In my case, we are building a new courts data visualization.
One of our columns in our tsv is an offence code. It breaks down like this
01 Homicide And Related Offences
010 Homicide And Related Offences not further defined
011 Murder
012 Attempted murder
013 Manslaughter and driving causing death
0131 Manslaughter
0132 Driving causing death
02 Acts Intended To Cause Injury
021 Assault
029 Other acts intended to cause injury
03 Sexual Assault And Related Offences
031 Sexual assault
0311 Aggravated sexual assault
0312 Non-aggravated sexual assault
032 Non-assaultive sexual offences
The first 2 numbers is the main categories, each digit after that gives us a sub category.
We can use this to turn it into an array (a little bit of underscore is used here)
function parseOffenceCode(code) {
result = [];
result.push(parseInt(code.substring(0,2)));
_.each(code.substring(2), function (c) {
result.push(parseInt(c))
});
return result;
}
so.... a 'Murder' would have a key of [1,1] where as a 'Non-aggravated sexual assault' would have a key of [3,1,2]
All good! (Well as good as conversations about Murders etc can be)
so, we push this into crossfilter.
offencesDim = ndx.dimension(_.property('OFFENCE'))
offencesGroup = offencesDim.group().reduceSum(getValue);
Soooo
if we call offencesGroup.all()
we will get something that looks like....
[{"key":[1,0],"value":12},
{"key":[1,1],"value":736},
{"key":[1,2],"value":238},
{"key":[1,3,1],"value":806},
{"key":[1,3,2],"value":528},
{"key":[10,1],"value":1700},
...
]
huh... this looks like all the stuff you would want for a hierarchy.
so... we will need a function to turn the results into one.
function buildHierarchy(list) {
var root = {"name": "root", "children": []};
for (var i = 0; i < list.length; i++) {
var parts = list[i].key;
var value = +list[i].value;
var currentNode = root;
for (var j = 0; j < parts.length; j++) {
var children = currentNode["children"];
var nodeName = parts[j];
var childNode;
if (j + 1 < parts.length) {
var foundChild = false;
for (var k = 0; k < children.length; k++) {
if (children[k]["name"] == nodeName) {
childNode = children[k];
foundChild = true;
break;
}
}
if (!foundChild) {
childNode = {"name": nodeName, "children": []};
children.push(childNode);
}
currentNode = childNode;
} else {
// Reached the end of the sequence; create a leaf node.
childNode = {"name": nodeName, "value": value};
children.push(childNode);
}
}
}
return root;
}
ok, it isn't pretty, and there are most likely 100 better ways of doing this, but.... the results are, it is in d3's standard json format for hierarchical data. :)
you can now build yourself a sunburst with it (we warned this is a pretty frustrating thing to do)
I'm not putting the code for doing this here, since there is a lot of it.
The data that is in flare.json, we already have if we call
buildHierarchy(offencesGroup.all())
Integrating this with dc.js
You will need a function to redraw your sunburst chart.
function redrawSunburst() {
tree = buildHierarchy(offencesGroup.all());
var nodes = partition.nodes(tree)
path.data(nodes)
...
}
and on the end of each chart, you will need to have
.on('filtered', redrawSunburst);
so, when you filter anything, your sunburst chart gets redrawn.
likewise, if you put an onclick or something on your chart, and you want to filter the dc.charts....
then call .filterExact on the dimension you are drawing your sunburst chart with (in my case, offencesDim) then call dc.redraw() to get dc to redraw the charts.
Now you have 2 way filtering with your d3 sunburst chart, and dc.js.
I'm putting up some examples soon (just putting in the last few bits)
--- Blair