Hyperbolic Tree Maps and Tree maps
Treemaps is currently under development, but here is a small taste of what you can expect in the future.
At the moment there is four algorithms implemented to get users up and running quickly. These are the SliceAndDice, Stripes, Squarified, and Strip algorithm. By extending the series object, the users can also add their own algorithms for layouting the data.
A levels object is introduced to let the users set wanted options to a specific level, this is displayed in some of the demos. The levels object is great for using a mix of several algorithms in the same chart.
Demos:
- http://jsfiddle.net/highcharts/sqxqq1ry/
- http://jsfiddle.net/highcharts/pa1eoqps/
- http://jsfiddle.net/highcharts/tm720ufm/
-
@Himanshu Please note that the treemaps are currently a work in progress, and the API is also not settled upon.
-
Himanshu commented
I am trying to understand all the options for Treemap (http://jsfiddle.net/highcharts/tm720ufm/)
Can someone please help me.I am looking to have drilldown option in Treemap. ( I click on any box, I see another Treemap for that cell ).. Is there a example?
Also, series argument is Array. What does this represent ? If I add more series ..
Similarly, Levels is a array ?? What is level value .? 1,2 ..Thank you.
-
I can have a look at your settings if you would like to? You could send either the raw code for the chart or a link to an example at my email: jon.arild@highsoft.com
-
Sorinel commented
Hi Jon,
I saw your example, I took exactly the same treemap.src.js, and I don't understand what do I do wrong but all the labels from the level 1 out of 2, are all centered and placed in the middle.
Although, just put back the old code for the drawLabels function (only this one) into the new treemap.src.js (as shown below) and I have the labels correctly dipsplayed in the top-left corner and underlined.
drawDataLabels: function () {
var series = this,
points = series.points,
options,
level,
dataLabels;
each(points, function (point) {
level = series.levelMap[point.level];
options = series.options.dataLabels;
// If not a leaf, then label should be disabled as default
if (!point.isLeaf) {
options = merge(options, {enabled: false});
}
if (level) {
dataLabels = level.dataLabels;
if (dataLabels) {
options = merge(options, dataLabels);
series._hasPointLabels = true;
}
}
options = merge(options, point.options.dataLabels);
point.options.dataLabels = options;
});
H.Series.prototype.drawDataLabels.call(this);
},Maybe you can figure out the difference between the above old code with the new one. I mean time I will check if I didn't do any typo in the config object.
Regards,
Sorinel C. -
Hi Sorinel,
You are most likely using the highcharts.src.js from master branch or something similar. There has been a change to that core file on the treemap branch which is not merged into the other branches.
Therefore I think that your problem will be fixed if you refer to this other core file.
Have a look at this demo: http://jsfiddle.net/jon_a_nygaard/rx19ctmw/If you risk destroying something by changing the highcharts.src.js file, then I can give you the necessary patches to fix this issue.
Hope this helps, otherwise let me know and I will have look at it.
-
Sorinel commented
Hi Jon,
I come back with an issue of the latest version of treemap.src.js (as of today - 01 dec 2014):
- the labels.I used to configure the labels in the levels, like this:
- 1. set the series.dataLabels.ebaled : false
- 2. each level has its own configuration like this:
[
// parents level
{
level : 1,
borderColor : 'yellow',
borderWidth : 3,dataLabels : {
enabled : true,
align : 'left',
verticalAlign : 'top',style : {
fontSize : fontSize + 'px',
textDecoration : underline
}},
layoutAlgorithm : 'sliceAndDice'
},// leafs level
{
level : 2,
borderColor : 'green',
borderWidth : 1,dataLabels : {
enabled : true,align : 'center',
verticalAlign : 'middle',style : {
fontSize : fontSize + 'px'
}}
}
],
and it is not displaying any label at all (that's NOK).
If I enable the series.dataLabels.enable=true then all the labels are displayed, but the style from the level.dataStyle.style is not used --> so, I have all the labels being centered in the middle (this is OK for leafs, but NOK for the parents, which I want to put in the top-left corner and underlined).
Can you tell me if I missed something, please?
Cheers,
Sorinel C. -
Sorinel commented
Hi Jon,
Thanks for the responses:
1. for the animation the setting was OK, it worked (thx).
2. for the cell title-bar, I will follow closely your dev. My 2 cents: if it isn't a big challenge then I would make it configurable (with or without).
3. It would be great for the zoom-in to allow having "strategies" to choose one way or another (so I can plug my code, strategy).
4. the color axis worked like magic (thx again).
5. the 'no data' issue I solve it by analyzing a little the dataset that I provide as input to the chart.
Regards,
Sorinel C. -
Hi Sorinel,
To remove animation on first draw, then you can set the series.animation to false.
If you want to display no data, then you can try using our no-data-to-display module: http://jsfiddle.net/gh/get/jquery/1.7.2/highslide-software/highcharts.com/tree/master/samples/highcharts/no-data-to-display/no-data-pie/When it comes to title bars and how point interaction should work (for instance hovering the cells), then we are currently discussing how it should be implemented.
Most likely we will add a new option, so that our users can choose between the functionality which we have today, and the one you have described in your comments. -
Sorinel commented
Hi Jon,
I have a question about a small detail of rendering:
- first displaying of the treemap there is an animation from left->right.
- this is not nice in the context of my appliation.
- is there any way to remove it? we just want to have the first display direct without animation, but we like the drill-down (zoom-in) animation, which I like to keep it.Is it possible to configure it like above?
Cheers,
Sorinel C. -
Sorinel commented
Hi Jon,
Here are the findings:
- I had all values = 0 in all cells, so it was normal to display nothing, or "no data" label, would be better.
With the last treemap.src.js code I see changes in the following areas:
- the labels are not present with my previous config -- did you change something in the way the labels are displayed/set ?
- the way of mouse "hovering" over the cells is different, but I believe that the best approach would be to keep hover on the smaller cells (like before), and provide a title bar for the parent cells to select the bigger rectangle.
BTW, how going the development for the title bar at the level 2 or 3 big cells (like displayed in the first picture of the wikipedia link, which you posted above, http://en.wikipedia.org/wiki/Treemapping) ?
Cheers!
Sorinel C.
-
Sorinel commented
Hi Jon,
This is great news (color axis), I will use it for sure.
Although, with the current treemap.src.js from GIT, I have not any treemap rendered at all -- just an empty page (good news is that the old charts are still working :).
- I am debugging and come back with my findings.Regards,
Sorinel C. -
Hi Sorinel,
Your idea is completely applicable.
You can achieve this by defining the colorAxis and set colorValue on the points. If colorAxis is used then the heatmap module must be included.Here is a simple demo: http://jsfiddle.net/jon_a_nygaard/chjz8hev/
-
Sorinel commented
Hi Jon,
I have a new idea, maybe it's strange ... but:
- what if the treemap provides an color axis (like the heatmap) ?!
* ( we can use one information for the cell size in treemap, and another information for its colors).
* (this will means that we should be able to display the color axis as legend of the treemap, the same like it's done for heatmap.)What is your opinion?
Cheers,
Sorinel C. -
Sorinel commented
In the below code I made a small error: I need to use isLeaf attribute instead of leaf, like below:
// if the point is not leaf then use it itself as drill-node, not it's parent
if (!point.isLeaf) {
....
} -
Sorinel commented
one more detail Jon:
- with the current code the function drillCloser (point) is not used.
- So, we should implement the drill-down logic to the function drillCloser (point) ... and then call this one in the 'above click events on points' logic.
- few 'code plugin' point should be allowed here, to make it more configurable.
Regards,
Sorinel C. -
Sorinel commented
Hi Jon,
Here is how I re-wrote the 'click events on points' to implement the below desired rules:
- if click on 'leaf' get it immediate parent as drill-node.
- if we click on non-leaf then get the clicked point as drill-node.@line: 632
<code>
// Set click events on points
if (series.options.allowDrillToNode) {
each(points, function (point) {
if (!point.graphic) {
return;
}
point.graphic.css({ cursor: 'default' });
var drillNode = series.nodeMap[point.id],
parent,
valid = true;
while (valid) {
parent = series.nodeMap[drillNode.parent];
valid = (parent.parent !== null) && (parent.id !== series.rootNode);
if (valid) {
drillNode = parent;
// here stop at the first parent - we don't need to go up,
// becuase in case of multi-levels we select always first node under root.
break;
}
}
if (!parent) {
return;
}// if the point is not leaf then use it itself as drill-node, not it's parent
if (!point.leaf) {
drillNode = series.nodeMap[point.id];
}
// If drill node is defined
if (drillNode) {
// delete previous handlerer -- not very nice, because
// here we can plug a custom 'click' handlerer.
H.removeEvent(point, 'click');// add new click handlerer.
H.addEvent(point, 'click', function () {
series.drillToNode(drillNode.id);
series.showDrillUpButton((parent.name || parent.id));
});
// set cursor pointer to show that we can drill.
point.graphic.css({ cursor: 'pointer' });
}
});
}</code>
-
Sorinel commented
Hi Jon,
Thank you for fixing the below issues - it's better indeed.
Although, id we have a huge number of cells (> 3000), some very small points have no graphic and drawing point function "drawPoints: function (){ ..}" fails at the end when it tries to register the drill event on very small point.
The below last code:
H.removeEvent(point, 'click');
point.graphic.css({ cursor: 'default' });
// If it is not the same point, then drill to it
if (drillNode.id !== point.id) {
H.addEvent(point, 'click', function () {
series.drillToNode(drillNode.id);
series.showDrillUpButton((parent.name || parent.id));
});
point.graphic.css({ cursor: 'pointer' });
}should be protected against null graphic, like this:
if (point.graphic) {
H.removeEvent(point, 'click');
point.graphic.css({ cursor: 'default' });
// If it is not the same point, then drill to it
if (drillNode.id !== point.id) {
H.addEvent(point, 'click', function () {
series.drillToNode(drillNode.id);
series.showDrillUpButton((parent.name || parent.id));
});
point.graphic.css({ cursor: 'pointer' });
}
}Cheers!
Sorinel C. -
Hi Sorinel,
Thank you for all the comments, it is really appriciated.
There has been some updates lately, among them is:
- your solution for text in drillUpButton is added
- problems with hover and borders is fixed
- points are sorted descending as they should by default
- drilling functionality is improvedComments:
- I will look at your suggestion about drilling. At the moment it will always drill down one level at a time. But this might be an option.
- The treemap module should support as many levels as the user wants.
- If any would like to have the points ascending, then they can set the option reversed to true on the xAxis and yAxis.Further on I will have a look at how the titles in small boxes should be handled.
-
Sorinel commented
Zoom-in behavior is not very good. The function "drillCloser(point)" is getting the first parent from under the root, doesn't care at what level is leaf node located (this is OK, for tree with 2 levels, but not for 3).
The best behavior for me is like this:
- for 2 levels as you did it so far.- for the 3 levels then:
** leaf nodes from level 3 will drill to the first parent.
** nodes from level 2 will drill to themselves.So I think we can generalize the drill rules like below (and we satisfy all levels: 2, 3, 4...)
** leafs (from level n) always go to their first parent.
** levels 1,2 ... n-1 always go to themselves.Cheers,
Sorinel C. -
Sorinel commented
Also, I have seen that is very hard to configure the text of the zoom "back" button.
drillUpButton : {
*** text : '<- Back',
position: {
align: 'right',
x: -10,
y: 10
}
}The above *** "text" attribute is not used in the function "showDrillUpButton: function (name)" where you hard-code the 'backText' local variable.
Can you make it working, like I did it below, please?
showDrillUpButton: function (name) {
var series = this,
backText = (name || '< Back'),
buttonOptions = series.options.drillUpButton,
attr,
states;// START MY CODE:
if (buttonOptions.text) {
backText = buttonOptions.text;
}
// END MY CODEif (!this.drillUpButton) {
attr = buttonOptions.theme;
states = attr && attr.states;this.drillUpButton = this.chart.renderer.button( ....