highcharts: pie chart - reduce number of slice - highcharts

I have a pie chart with so many slices that is very hard to read it. Is it possible to reduce the number of slices, by grouping the smallest in just one named "others", or hiding them?

No. This behaviour is not built into highcharts.
The easiest way to achieve this is by manually changing the data you pass to the chart. Ie if you do the grouping into a category 'Others' before you pass the data and render the chart

Pasting some info in here as a pointer for people that would like to do the above with javascript outside of Highcharts, like i did myself.
for(i=0; i<dataJSON.finished.length; i++) {
//console.info(i);
if(dataJSON.finished[i].name !== '_all_' && dataJSON.finished[i].name !== 'Anders') {
tempValue=0;
for(j=0; j<dataJSON.finished[i].data.length; j++) { tempValue += dataJSON.finished[i].data[j]; }
if(tempValue / totalValue > 0.02) {
pieData.push({ name:dataJSON.finished[i].name, y:tempValue });
} else andersValue += tempValue;
}
}
//console.info(pieData);
pieData.sort(function(a,b) {return (a.y > b.y) ? -1 : ((b.y > a.y) ? 1 : 0);});
pieData.push({ name: "Overig", y: andersValue });

Related

How to get Node Coordinates Data in Sankey Graph

I'm trying to create something similar to the image below. Where each column has a heading with it.
I know that chart.renderer.text can be used to create & place custom text on chart. However, I'm unable to find a way to fetch the column/node coordinates data(x,y) which would help me place them.
Also is there a programmatic way to do this task. For example, a function that fetches all the columns coordinates and populates all the headings from an existing list.
To summarize:
How to fetch a columns (x,y) Coordinates?
How to dynamically place headings for all columns from a list?
Image
You can get the required coordinates and place the headers in render event, for example:
events: {
render: function() {
var chart = this,
series = chart.series[0],
columns = series.nodeColumns,
isFirst,
isLast,
xPos;
if (!series.customHeaders) {
series.customHeaders = [];
}
columns.forEach(function(column, i) {
xPos = column[0].nodeX + chart.plotLeft;
isFirst = i === 0;
isLast = i === columns.length - 1;
if (!series.customHeaders[i]) {
series.customHeaders.push(
chart.renderer.text(
headers[i],
xPos,
80
).attr({
translateX: isFirst ? 0 : (
isLast ?
series.options.nodeWidth :
series.options.nodeWidth / 2
),
align: isFirst ? 'left' : (
isLast ? 'right' : 'center'
)
}).add()
)
} else {
series.customHeaders[i].attr({
x: xPos
});
}
});
}
}
Live demo: https://jsfiddle.net/BlackLabel/6Lvdufbp/
API Reference:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#text

Highcharts : Set an y offset to the series

Situation : Chart with some analogic-series and some digital-series (0-1).
The problem is with the digital series. I would like to make sure that the series do not overlap like the image 1.
My idea is to set an "y-offset" on the digital-series, to have a result like the image 2.
This is a part of the y Axis configuration of the digital series. All the digital-series is related to a single y Axis (with id digital).
id : "digital",
min: 0,
max : 1,
ceiling:1,
floor : 0,
tickInterval: 1
Image 1.
Image 2.
In the documentation i can't find anything that can help me. And this is not my case.
UPDATE
Example on JSFIDDLE. Look (yes it's impossible currently) at the digital series with green color.
If you add a function in the load event, you can change the value of y in a way that makes it look offset. Like this:
chart: {
events: {
load: function() {
var series = this.series;
for (var i = 0; i < series.length; i++) {
if (series[i].yAxis.userOptions.id == "digital") {
for (var j = 0; j < series[i].data.length; j++) {
if (series[i].data[j].y == 1) {
series[i].data[j].y = 1 + 0.1 * i;
} else {
series[i].data[j].y = 0
}
}
this.update(series, true, false);
}
}
}
}
}
This sets the new y value equal to 0.1 * the series index.
Working example: https://jsfiddle.net/u2pzrhgk/27/

Highcharts missing information in scatterplot CSV/XLS export

When exporting scatter plot / bubble chart data as CSV or XLS, it is missing key information, see for example: http://jsfiddle.net/11fum86u/
This is the data (extract):
series: [{
data: [
{ x: 95, y: 95, z: 13.8, name: 'BE', country: 'Belgium' },
And the axis titles are in the tooltip (but perhaps needs to be defined elsewhere):
tooltip: {
pointFormat: '<tr><th colspan="2"><h3>{point.country}</h3></th></tr>' +
'<tr><th>Fat intake:</th><td>{point.x}g</td></tr>' +
'<tr><th>Sugar intake:</th><td>{point.y}g</td></tr>' +
'<tr><th>Obesity (adults):</th><td>{point.z}%</td></tr>',
What is missing in the default export is (i) labels for y and z axis, and (ii) the names of the bubbles (in this example, country codes/names)
I was wondering how I might be able to add this information to the export.
Actually there's no z axis in bubble charts. It's quite confusing, because all points have z property. This property serves to compute the bubble size so no additional axis is needed, because everything is in 2d. zAxis is used in 3d charts.
Please refer to this live working example: http://jsfiddle.net/kkulig/udtr0emL/
You can handle first row labels via columnHeaderFormatter (http://api.highcharts.com/highcharts/exporting.csv.columnHeaderFormatter):
exporting: {
csv: {
columnHeaderFormatter: function(item, key, keyLength) {
if (item.axisTitle) {
return item.axisTitle.textStr; // x axis label
} else if (key === 'y') {
return item.yAxis.axisTitle.textStr; // y axis label
} else if (key === 'z') {
return 'Obesity (adults)'; // z axis label
}
}
}
}
To add another column (countries) added following pieces of code in these three core functions:
1. Highcharts.Chart.prototype.getDataRows
// add original point reference
rows[key].point = point;
2. Highcharts.Chart.prototype.getCSV
// Add point name and header
csv += itemDelimiter;
var point = row['point'];
if (point) {
csv += point.name
} else {
csv += "Country"
}
3. Highcharts.Chart.prototype.getTable (for XLS)
var point = row['point'],
val;
if (point) {
val = point.name;
} else {
val = "Country";
}
html += '<' + tag + ' class="text">' +
(val === undefined ? '' : val) + '</' + tag + '>';
All functions are available in export-data.src.js in this directory: https://github.com/highcharts/highcharts/tree/b4b4221b19a3a50d9ed613b6f50b12f0afcc7d06/js/modules

Maximum number of datapoints allowed in a highcharts/stock series data hash

I seem to be running into some kind of limit to the number of datapoints I can have in my series datahash. I am creating my data hash like so:
var data_hash = [];
var limit = 1000;
for(var i = 0; i < limit; i++)
{
data_hash.push({myData:'blah',
x: i,
y: (i+1)});
}
$(function() {
$('#container').highcharts('StockChart', {
tooltip: {
formatter: function() {
var s = '';
$.each(this.points, function(i, point) {
s += 'x: '+ point.x;
s += ', y: '+point.y;
});
return s;
}
},
series: [{
name: 'series_limit',
data: data_hash
}]
});
});
If I set the limit variable to 1000 or lower the graph will render just fine. However if I were to increase it to any value higher than that the graph will stop rendering. Is there something wrong with the way I am constructing my hash? Or is there some kind of configuration setting I can change to increase the number of datapoints allowed?
Here is a link to the jsfiddle:
http://jsfiddle.net/hYtUj/13/
Default number of datapoints before highcharts starts using arrays is 1000.You can change this value in chart options(parameter threshold)
Set turboThreshhold option to 0 or use two dimensional array with x and y values (turboThreshold)
data_hash.push([i+1, i]); // instead of {x: i, y: i+1}

Highcharts - Keep Zero Centered on Y-Axis with Negative Values

I have an area chart with negative values. Nothing insanely different from the example they give, but there's one twist: I'd like to keep zero centered on the Y axis.
I know this can be achieved by setting the yAxis.max to some value n and yAxis.min to −n, with n representing the absolute value of either the peak of the chart or the trough, whichever is larger (as in this fiddle). However, my data is dynamic, so I don't know ahead of time what n needs to be.
I'm relatively new to Highcharts, so it's possible I'm missing a way to do this through configuration and let Highcharts take care of it for me, but it's looking like I'll need to use Javascript to manually adjust the y axis myself when the page loads, and as new data comes in.
Is there an easy, configuration-driven way to keep zero centered on the Y axis?
I ended up finding a way to do this through configuration after digging even further into the Highcharts API. Each axis has a configuration option called tickPositioner for which you provide a function which returns an array. This array contains the exact values where you want ticks to appear on the axis. Here is my new tickPositioner configuration, which places five ticks on my Y axis, with zero neatly in the middle and the max at both extremes :
yAxis: {
tickPositioner: function () {
var maxDeviation = Math.ceil(Math.max(Math.abs(this.dataMax), Math.abs(this.dataMin)));
var halfMaxDeviation = Math.ceil(maxDeviation / 2);
return [-maxDeviation, -halfMaxDeviation, 0, halfMaxDeviation, maxDeviation];
},
...
}
I know this is an old post, but thought I would post my solution anyway (which is inspired from the one macserv suggested above in the accepted answer) as it may help others who are looking for a similar solution:
tickPositioner: function (min, max) {
var maxDeviation = Math.ceil(Math.max(Math.abs(this.dataMax), Math.abs(this.dataMin)));
return this.getLinearTickPositions(this.tickInterval, -maxDeviation, maxDeviation);
}
You can do this with the getExtremes and setExtremes methods
http://api.highcharts.com/highcharts#Axis.getExtremes%28%29
http://api.highcharts.com/highcharts#Axis.setExtremes%28%29
example:
http://jsfiddle.net/jlbriggs/j3NTM/1/
var ext = chart.yAxis[0].getExtremes();
Here is my solution. The nice thing about this is that you can maintain the tickInterval.
tickPositioner(min, max) {
let { tickPositions, tickInterval } = this;
tickPositions = _.map(tickPositions, (tickPos) => Math.abs(tickPos));
tickPositions = tickPositions.sort((a, b) => (b - a));
const maxTickPosition = _.first(tickPositions);
let minTickPosition = maxTickPosition * -1;
let newTickPositions = [];
while (minTickPosition <= maxTickPosition) {
newTickPositions.push(minTickPosition);
minTickPosition += tickInterval;
}
return newTickPositions;
}
Just in case someone is searching,
One option more. I ended up in a similar situation. Follows my solution:
tickPositioner: function () {
var dataMin,
dataMax = this.dataMax;
var positivePositions = [], negativePositions = [];
if(this.dataMin<0) dataMin = this.dataMin*-1;
if(this.dataMax<0) dataMax = this.dataMax*-1;
for (var i = 0; i <= (dataMin)+10; i+=10) {
negativePositions.push(i*-1)
}
negativePositions.reverse().pop();
for (var i = 0; i <= (dataMax)+10; i+=10) {
positivePositions.push(i)
}
return negativePositions.concat(positivePositions);
},
http://jsfiddle.net/j3NTM/21/
It is an old question but recently I have had the same problem, and here is my solution which might be generalized:
const TICK_PRECISION = 2;
const AXIS_MAX_EXPAND_RATE = 1.2;
function setAxisTicks(axis, tickCount) {
// first you calc the max from the data, then multiply with 1.1 or 1.2
// which can expand the max a little, in order to leave some space from the bottom/top to the max value.
// toPrecision decide the significant number.
let maxDeviation = (Math.max(Math.abs(axis.dataMax), Math.abs(axis.dataMin)) * AXIS_MAX_EXPAND_RATE).toPrecision(TICK_PRECISION);
// in case it is not a whole number
let wholeMaxDeviation = maxDeviation * 10 ** TICK_PRECISION;
// halfCount will be the tick counts on each side of 0
let halfCount = Math.floor(tickCount / 2);
// look for the nearest larger number which can mod the halfCount
while (wholeMaxDeviation % halfCount != 0) {
wholeMaxDeviation++;
}
// calc the unit tick amount, remember to divide by the precision
let unitTick = (wholeMaxDeviation / halfCount) / 10 ** TICK_PRECISION;
// finally get all ticks
let tickPositions = [];
for (let i = -halfCount; i <= halfCount; i++) {
// there are problems with the precision when multiply a float, make sure no anything like 1.6666666667 in your result
let tick = parseFloat((unitTick * i).toFixed(TICK_PRECISION));
tickPositions.push(tick);
}
return tickPositions;
}
So in your chart axis tickPositioner you may add :
tickPositioner: function () {
return setAxisTicks(this, 7);
},

Resources