Open xhkong opened 11 years ago
TreeMap is a good way to visualize hierarchical data however crossfilter currently does not support hierarchical data (drill down/drill up). I am doing some related hierarchical data visualization in some other project and hopefully will be able to incorporate some ideas into dc.js eventually. As of now I don’t think it is possible with crossfilter.
Will keep this in the backlog as a future feature request, cheers.
Nick,
Treemap uses are not limited to hierarchical data, especially the Marimekko / Mosaic variant is highly useful to assess interdependencies in data comprising several categorical dimensions. I like to think of it as the 2D+ variant of (normalised) stacked bars, and it's apparently well-implemented in D3 v3 (treemap.mode("slice-dice")
, see https://github.com/mbostock/d3/pull/169).
For some additional background check the following slide decks: http://www.interactivegraphics.org/Slides_files/Chapter31.pdf http://www.interactivegraphics.org/Slides_files/Chapter41.pdf
Cheers Marc
Agree, though not sure I have enough bandwidth to tackle this anytime soon (just had a new baby this week :) Will slot it in v1.5 for now.
Congrats on the baby, and good luck! :-) I only hope it won't make you lose interest in this other baby of yours entirely! ;-)
I implemented one for my report, here is how I added the treemap to dc:
dc.treemapChart = function (parent, chartGroup) {
var _chart = dc.baseMixin({});
var _treemap;
_chart._doRedraw = function() {
var _cellData = {
name:'tree',
children: _chart.data()
};
_chart.root()
.selectAll('.node')
.data(_treemap.nodes)
.transition().duration(1000)
.call(_updateCell);
_highlightFilters();
return _chart;
};
_chart._doRender = function () {
var color = d3.scale.category20c();
_treemap = d3.layout.treemap()
.size([_chart.width(), _chart.height()])
.sticky(true)
.value(function (d) { return d.value; });
var _cellData = {
name:'tree',
children: _chart.data()
};
_chart.root()
.classed('treemap', true)
.style('position', 'relative')
.style('height', _chart.height() + 'px')
.style('width', _chart.width() + 'px');
var _node = _chart.root()
.datum(_cellData)
.selectAll('.node')
.data(_treemap.nodes)
.enter()
.append('div')
.attr('class', 'node')
.call(_updateCell)
.style('background', function(d) { return color(d.key); })
.style('position', 'absolute')
.text(function(d) { return d.key; })
.attr('title', _chart.title())
.on('click', onClick);
return _chart;
};
function _updateCell() {
this.style('left', function (d) { return d.x + 'px'; })
.style('top', function (d) { return d.y + 'px'; })
.style('width', function (d) { return (d.dx - 1) + 'px'; })
.style('height', function (d) { return (d.dy - 1) + 'px'; })
.style('font-size', function (d) { return d.value > 0 ? 0.1 * Math.sqrt(d.dx * d.dy) +'px' : 0; });
}
function onClick(d, i) {
_chart.onClick(d, i);
}
function _highlightFilters() {
if (_chart.hasFilter()) {
_chart.root().selectAll('.node').each(function (d) {
if (_chart.hasFilter(d.key)) {
_chart.highlightSelected(this);
}
else {
_chart.fadeDeselected(this);
}
});
}
else {
_chart.root().selectAll('.node').each(function (d) {
_chart.resetHighlight(this);
});
}
}
return _chart.anchor(parent, chartGroup);
};
That's excellent! Any change to post this as a pull request for core?
pierco's example causes a call stack size limit error. Needs more work to incorporate the .margins method other box charts have in DC.
Could you give me an example of this method implementation or point me to the right direction ? Thanks
There is a margins mixin for DC.js that takes top left right bottom. Also, can you send an example of the data object you used and the crossfilter dimension and group functions you used to get yours to work?
Margins mixin https://github.com/dc-js/dc.js/blob/master/src/margin-mixin.js
BTW The margins is a suggestion to help place the chart and the call stack error was due to data input. I figured that out, but would like to see how you did the crossfilter dimensions and group to get this chart to display. I was using a demension from a pie chart with 5-6 groups with .group().reduceCount() as the group object, and the chart was displaying but caused a call stack exceeded error.
On Thursday, March 20, 2014, pierco notifications@github.com wrote:
Could you give me an example of this method implementation or point me to the right direction ? Thanks
Reply to this email directly or view it on GitHubhttps://github.com/dc-js/dc.js/issues/129#issuecomment-38214264 .
I was wondering if any further work had been done on this?
Hi, I made a minor modification to allow caps/valueAccessor/KeyAccessor.
dc.treemapChart = function (parent, chartGroup) {
var _chart = dc.capMixin(dc.marginMixin(dc.baseMixin({})));
var _treemap;
_chart.rowsCap = _chart.cap;
_chart._doRedraw = function() {
var _cellData = {
name:'tree',
children: _chart.data()
};
_chart.root()
.selectAll('.node')
.data(_treemap.nodes)
.transition().duration(1000)
.call(_updateCell);
_highlightFilters();
return _chart;
};
_chart._doRender = function () {
var color = d3.scale.category20c();
_treemap = d3.layout.treemap()
.size([_chart.width(), _chart.height()])
.sticky(true)
.value(function (d) { console.log('treemap value', d); return _chart.valueAccessor()(d); });
var _cellData = {
name:'tree',
children: _chart.data()
};
_chart.root()
.classed('treemap', true)
.style('position', 'relative')
.style('height', _chart.height() + 'px')
.style('width', _chart.width() + 'px');
var _node = _chart.root()
.datum(_cellData)
.selectAll('.node')
.data(_treemap.nodes)
.enter()
.append('div')
.attr('class', 'node')
.call(_updateCell)
.style('background', function(d) { return color(d.key); })
.style('position', 'absolute')
.text(function(d) { return _chart.keyAccessor()(d); })
.attr('title', _chart.title())
.on('click', onClick);
return _chart;
};
function _updateCell() {
this.style('left', function (d) { return d.x + 'px'; })
.style('top', function (d) { return d.y + 'px'; })
.style('width', function (d) { return (d.dx - 1) + 'px'; })
.style('height', function (d) { return (d.dy - 1) + 'px'; })
.style('font-size', function (d) { return d.value > 0 ? 0.1 * Math.sqrt(d.dx * d.dy) +'px' : 0; });
}
function onClick(d, i) {
_chart.onClick(d, i);
}
function _highlightFilters() {
if (_chart.hasFilter()) {
_chart.root().selectAll('.node').each(function (d) {
if (_chart.hasFilter(d.key)) {
_chart.highlightSelected(this);
}
else {
_chart.fadeDeselected(this);
}
});
}
else {
_chart.root().selectAll('.node').each(function (d) {
_chart.resetHighlight(this);
});
}
}
return _chart.anchor(parent, chartGroup);
};
I tried both versions of dc.treemapChart and I got this error:
c.utils.GroupStack is not a constructor
Any ideas?
@KatiRG, I haven't tried the code myself, but I don't understand that error since GroupStack
is not a symbol in either this code or dc.js
ok that's weird! I'm trying the sunburst now, as you suggested. I'll let you know what happens, thanks!
@jannah @ghost Thanks for adding treemap support. Did you submit a pull request?
Wow! This is exactly what I need. I don't see a PR. Is there something I could do to contribute, @jannah @ghost ?
Since no one has submitted a PR, I think the best thing you can do is try this code out on your own @oakley808 and let us know how it works.
Then if you feel ambitious and neighborly, submit a PR yourself!
You should be able to just add this code in another script loaded after dc, as long as module gunk doesn't get in the way. dc is very extensible.
@jannah I did some tests, but the filters aren't working properly. In https://codepen.io/rafaneri/pen/dKjqeJ is possible to see, that "Empresa 0143" has one data where gender is "M", but when I filter on pie chart for gender "M", the slot "Empresa 0143" is hidden.
Nick,
Can we add TreeMap support as single (multiple when supported) selection chart? This can be really useful in some cases. And I assume this will not be too hard to achieve, but I might be wrong.
Thanks a lot!
Javy