Add plotbonds to Gaps defined by GapSize in Highcharts - javascript

I am trying to add background color to gaps in data to be more visible on large intervals, I know that I can do that by adding plotbonds with the color I want, the problem is I don't have the start and end of the gap because it is created by defining the GapSize and GapUnit (no dates with null data, juste a gap in the dates).
I tried adding the plotbonds by calculating the difference between the dates and comparing it to the tickInterval but no luck so far,
here is an example of gaps set with gapsize
plotOptions: {
series: {
gapSize: 1
}
}
https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/stock/plotoptions/series-gapsize
Is there a simpler way of doing this ?
thanks

Highcharts internally adds null points to create gaps. You can get the calculated null points and based on their values, create plot-bands.
For example:
let plotBands = [];
let allowChartUpdate = true;
(function(H) {
H.wrap(H.seriesTypes.area.prototype, 'getGraphPath', function(proceed, points) {
const xAxis = this.xAxis;
plotBands = [];
points.forEach((p, index) => {
if (p.isNull) {
plotBands.push({
from: points[index - 1] ? points[index-1].x : xAxis.min,
to: points[index + 1] ? points[index+1].x : xAxis.max,
color: 'red'
});
}
});
return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
});
}(Highcharts));
Highcharts.stockChart('container', {
chart: {
type: 'area',
events: {
render: function() {
// prevent infinity loop
if (allowChartUpdate) {
allowChartUpdate = false;
this.xAxis[0].update({plotBands});
allowChartUpdate = true;
}
}
}
},
...
});
Live demo: https://jsfiddle.net/BlackLabel/jz0n28om/
API Reference: https://api.highcharts.com/highcharts/xAxis.plotBands
Docs: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts

Related

Chart JS Custom Labels don't work

I am trying to truncate the labels on my horizontal bar chart but can't seem to get the callback to actually work.
yAxes: [{
maxBarThickness: 50,
gridLines: false,
ticks: {
padding: 10,
callback: value => {
let new_label = null;
if (value.length > 15) {
new_label = value.substring(0, 15) + '...';
} else {
new_label = value;
}
return new_label;
},
},
}],
To achieve expected result, use below option of changing value to string using toString() and then just return value bases on length
callback: value => {
if (value.toString().length > 15) {
return value.toString().substr(0, 15) + '...'; //truncate
} else {
return value
}
}
code example for reference - https://codepen.io/nagasai/pen/zaLVeO
Note: Check the padding values in the options, check this link for more details - Chart.js y axis labels are truncated incase of missing truncated values due to padding

How to set multiple colors in one series in highchart

Can we set multiple color for a series in highchart's columnrange chart based on value. For e.g. if a series is starting it should have green and if its ending after a threshold limit color should be in red in same series.
sample columnrange chart
I was trying below code to change the color but its not setting the different color from bottom to top: jsfiddle
{
linearGradient: merge(perShapeGradient),
stops: [
[0, 'green'],
[1, 'red']
]
}
can anybody pls help me.
Coloring by using gradient is rather hard task to do in this case.
Workaround:
You can split the point if it crosses the value that defines a color change:
{
var series = this.series[0],
points = series.points,
newPoints = [];
points.forEach((point) => {
// add x value to options
point.options.x = point.x;
if (point.low < yThreshold && point.high > yThreshold) {
// split the point
newPoints.push($.extend({}, point.options, {
low: point.low,
high: yThreshold
}), $.extend({}, point.options, {
low: yThreshold,
high: point.high
}));
} else {
newPoints.push(point.options);
}
});
// color the points
newPoints.forEach(function(pointOptions) {
if (pointOptions.high <= yThreshold) {
pointOptions.color = '#C0FFEE';
} else {
pointOptions.color = '#BADA55';
}
});
series.setData(newPoints);
}
Demo: http://jsfiddle.net/BlackLabel/jfguhget/

Highcharts grouped column labels

I have a highcharts grouped column chart with two columns for each value on the x axis. i would like to be able to add a label above each group with difference between the two in percent. I cant seem to find any way to reference the two columns in the formatter-option.
This is the section I'm having trouble with:
column: {
dataLabels: {
formatter: function()
{
return this.y;
}
}
}
Where this.y should be the difference.
This is how it is at this time http://jsfiddle.net/LLExL/4548/
All i want changed from this is a label above each of the two columns with a percent difference.
Inside the formatter callback you can use the series.chart.series[1].yData property to get the y values of the second column/series. yData is an array of all the y values. Then you can use the point.index property to get the corresponding point of the second column/series.
column: {
dataLabels: {
formatter: function()
{
var firstColumnValue = this.y;
var secondColumnValue = this.series.chart.series[1].yData[this.point.index];
var yourCalculation = (firstColumnValue - secondColumnValue) / firstColumnValue * 100;
return yourCalculation.toFixed(2) + '%';
}
}
}
Updated JSFiddle
One possibility is to pre-calculate all the differences, and simply reference them in your formatter. For example, define your series in a variable, and loop over it to create a separate diffs array of the differences, like this:
var series = [{
name: 'Omsetning',
data: [
// ...
]
}
// ...
];
var diffs = [];
for(i = 0; i < series[0].data.length; i++) {
var v1 = series[0].data[i].y;
var v2 = series[1].data[i].y;
diffs.push( (Math.abs(v1-v2) / ((v1+v2) / 2)) * 100 );
}
$('#container').highcharts({
plotOptions: {
column: {
dataLabels: {
formatter: function()
{
return Highcharts.numberFormat(diffs[this.x])+"%";
}
}
}
}
series: series
// ...
});
See this JSFiddle demonstration of how it looks.

How to access the value of a custom attribute in data from highcharts

I have this in my code
series: [{
name: 'Velocidad',
turboThreshold: 5000,
data: (function() {
// generate an array of random data
var data = [],
i;
for (i = 0; i < valor; i++) {
data.push({
x: dataUtc[i],
y: dataVel[i],
id: i
});
}
return data;
})(),
tooltip: {
valueDecimals: 0,
valueSuffix: 'Kms/H'
}
}]
When I try to get the maximum value I only get the x or y value.
I need to get the id value though.
What can I do?
I tried the following:
var chart = $('#containerVelocidad').highcharts();
min = chart.xAxis[0].min;
max = chart.xAxis[0].max;
Unfortunately that didn't help.
First of all, use yAxis.dataMax not yAxis.max. The second one is returning actual extremes, when sometimes you may have different extremes, than just from one series (zooming, setting extremes, multiple series etc.).
Demo: http://jsfiddle.net/ez4hjazk/1/
And code:
var max = chart.yAxis[0].dataMax,
maxIndex = chart.series[0].yData.indexOf(max), //get index from yData, read more about .indexOf() !
data = chart.series[0].data;
// make sure point is within actual extremes
if(maxIndex > -1) {
console.log("max = " + max, 'id = ' + data[maxIndex].id);
}
Do you need to get the maximum/minimum of id?
If so, try chart.series[0].data[i].id. Here's an example: http://jsfiddle.net/ez4hjazk/

Long array of small data points is rendered as a jagged line

The Goal
I'm attempting to render a long series of data (around 200 ticks, from small float values like 1.3223) into a line chart.
The Issue
When I use a series of data that changes only a small amount (around 0.0001 every tick), the chart is rendered as very jagged (scissor like). I would like to somehow fix it to have a "saner" radius between each point on the graph.
A Good Example
On the other hand, when rendering higher values (around 1382.21) with bigger difference between ticks (from 0.01 to 0.05 +/-) the graph is rendered more smooth and aesthetically pleasing.
Edit: As user Arie Shaw pointed out, the actual low or high values don't make a difference and it remains an issue of representing small "monotonous" changes is a less jagged form.
The Code
var initChart = function(data, container) {
new Highcharts.Chart({
chart: {
type: "area",
renderTo: container,
zoomType: 'x'
},
title: {
text: ''
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
title: {
text: ''
}
},
legend: {
enabled: false
},
color: '#A3D8FF',
plotOptions: {
area: {
fillColor: '#C6E5F4',
lineWidth: 1,
marker: {
enabled: false
},
shadow: false,
states: {
hover: {
lineWidth: 1
}
},
threshold: null
}
},
exporting: {
enabled: false
},
series: [{
name: "TEST",
data: data
}]
});
};
Both graphs, and sample data sets are presented in the following fiddle:
http://jsfiddle.net/YKbxy/2/
The problem you're experiencing is unavoidable: If you have a lot of small variations over time, the graph is going to appear jagged provided that you show each data point.
The key point is that last phrase.
One way to 'smooth out' the rough parts would be to average the data. For example:
var myData = []; //... Some array of data; assuming just numbers
var averageData = function (data, factor) {
var i, j, results = [], sum = 0, length = data.length, avgWindow;
if (!factor || factor <= 0) {
factor = 1;
}
// Create a sliding window of averages
for(i = 0; i < length; i+= factor) {
// Slice from i to factor
avgWindow = data.slice(i, i+factor);
for (j = 0; j < avgWindow.length; j++) {
sum += avgWindow[j];
}
results.push(sum / avgWindow.length)
sum = 0;
}
return results;
};
var var initChart = function(data, container) {
new Highcharts.Chart({
series: [{
name: "TEST",
data: averageData(myData, 2)
}]
});
});
This method also has the advantage that you could (potentially) reuse the function to compare the averaged data to the regular data, or even toggle between how much to average the data.
You can always use areaspline instead of area, see: http://jsfiddle.net/YKbxy/3/
why dont you treat you .00001 data as 1, so times 10000, and then write it in your legend like that.
You should even do that as a test, since if the chart looks fine then, it means there is a problem in the dataset numbers when you return it to normal, since high charts takes the difference between high and low...
Either you must approximate your data by only using a few decimal places or you must average out the values using something like:
var data = new Array(200);
var smallArray = new Array(5);
var averagedData = new Array(20);
for (var index=0; index<=averagedData.length; index++){
for(var i = 0; i<=smallArray.length; i++){
smallArray[i] = data[i + index * 5];
}
averagedData[index] = (smallArray[1] + smallArray[2] + smallArray[3] + smallArray[4] + smallArray[5])/smallArray.length;
}
Then you will only need to plot 20 averaged points on an array of 200 data points. You can change the values for what you need.
In the end the issue is in the frequency of the points or their plotting on yAxis.
When I provide more realistic positioning (e.g timestamp) it will look good.
Meaning that jaggedness is a result of the small changes over constant yAxis progression, which is most similar to nt3rp's answer

Categories

Resources