I would like to display difference between 2 points on my Highcharts graph. Only when it's a major "peak" difference.
Here's a "static" example :
$(function () {
$('#container').highcharts({
chart: {
type: 'areaspline'
},
series: [{
data: [560,500,476,453,356,{
y: 590,
dataLabels: {
enabled: true,
formatter: function () {return '+243';}
}
},497,478,465,465,465,410,398]
}]
});
});
http://jsfiddle.net/vr1a61wy/
How can I compare all point values with the previous ?
For example, something like that (not "real code)
if(prevValue > 200) {
displayDataLabel();
}
function displayDataLabel() {
peak = this.datalabel - prev.datalabel;
return peak;
}
The goal is to have a clean json file only with values and peaks calculated by javascript.
Is it possible ?
You can use the plotOptions.series.dataLabels.formatter to do this comparison. To do the comparison you will utilize this.x, this.y and this.series to look up the previous point.
An example formatter function would be (JSFiddle):
formatter: function() {
if(this.x > 0 && this.y - this.series.data[this.x-1].y >= PEAKDIFF) {
return "+" + (this.y - this.series.data[this.x-1].y);
}
return null;
}
Where PEAKDIFF is the value you want the difference to be before showing the label. If you want large negative drops to show as well you'd do the same with Math.abs.
Related
I generate graph code for a graph with a logarithmic scale with negative values. The result is in the fiddle below.
I made the function required to handle the negative values like here and it worked perfectly. But since some days it does not function anymore. So I adjusted the code according to this article but it still does not work. See my JSFidddle:
(function (H) {
H.addEvent(H.Axis, 'afterInit', function () {
const logarithmic = this.logarithmic;
if (logarithmic && this.options.custom.allowNegativeLog) {
// Avoid errors on negative numbers on a log axis
this.positiveValuesOnly = false;
// Override the converter functions
logarithmic.log2lin = num => {
const isNegative = num < 0;
let adjustedNum = Math.abs(num);
if (adjustedNum < 10) {
adjustedNum += (10 - adjustedNum) / 10;
}
const result = Math.log(adjustedNum) / Math.LN10;
return isNegative ? -result : result;
};
logarithmic.lin2log = num => {
const isNegative = num < 0;
let result = Math.pow(10, Math.abs(num));
if (result < 10) {
result = (10 * (result - 1)) / (10 - 1);
}
return isNegative ? -result : result;
};
}
});
}(Highcharts));
I get an error 10 but the examples in that description don't go anywhere.
What is going on and how do I repair?
Apparently Highcharts made a change to the Axis definition.
The Y-axis was defined as:
yAxis:
{
type: 'logarithmic',
allowNegativeLog: true,
title:
{
text: 'Regen Spreiding ( mm)'
},
min: 0.0,
max: 25.40
},
And it is now required to be (at least it is working with this modification):
type: 'logarithmic',
custom:
{
allowNegativeLog: true,
},
NOTE: this is together with the modified function H which now starts with :
H.addEvent(H.Axis, 'afterInit', function () {
If you landed here like I did, checkout this JSFiddle by Highcharts with working demo.
I tried some solution on other answers but I couldn't get the result what I want.. please help me.
I want to show first x axis label and last one in highcharts.
I tried {endOnTick: true, showLastLabel: true} from this answer(Force Highcharts to show last x-axis label) but it shows just some number on the last.. not the actual last label.
This is my x axis option
xAxis: {
type: 'Month',
// tickInterval is 5 this time
tickInterval: <?php echo number_format($num_results/5, 0);?>,
endOnTick: true, // it shows "25" at the end of the label. not "2019-06"
showLastLabel: true, // Default is true though..
labels: {
autoRotation: 0
},
//I get those categories from server
//so it could be different every time
//but this time I just write the result of it.
categories: ["2017-07","2017-08","2017-09","2017-10","2017-11","2017-12","2018-01","2018-02","2018-03","2018-04","2018-05","2018-06","2018-07","2018-08","2018-09","2018-10","2018-11","2018-12","2019-01","2019-02","2019-03","2019-04","2019-05","2019-06"]
}
expected x axis labels are
"2017-07 2017-12 2018-05 2018-10 2019-03 2019-06"
the actual result is
"2017-07 2017-12 2018-05 2018-10 2019-03 25"
Ahh I used tickPositioner and solved it!
xAxis: {
type: 'Linear',
tickmarkPlacement: 'on',
tickPositioner: function() {
var positions = [],
ext = this.getExtremes(),
xMax = Math.round(ext.max),
xMin = Math.round(ext.min);
for (var i = xMin; i < xMax; i++) {
if (i % <?php echo number_format($num_results/3,0);?> == 0) {
positions.push(i);
}
}
positions.push(xMax);
return positions;
},
labels: {
autoRotation: 0,
},
categories: ["2017-07","2017-08","2017-09","2017-10","2017-11","2017-12","2018-01","2018-02","2018-03","2018-04","2018-05","2018-06","2018-07","2018-08","2018-09","2018-10","2018-11","2018-12","2019-01","2019-02","2019-03","2019-04","2019-05","2019-06"]
}
You are missing 2 categories to show 2019-06
...
categories: ["2017-07","2017-08","2017-09","2017-10","2017-11",
"2017-12","2018-01","2018-02","2018-03","2018-04",
"2018-05","2018-06","2018-07","2018-08","2018-09",
"2018-10","2018-11","2018-12","2019-01","2019-02",
"2019-03","2019-04","2019-05","2019-06","24th","the 25th"]
},
Fiddle
I'm making a simple line chart for a client using Chart.js, but the values shown are all above millions, making the labels take up a lot of space in the chart, as below:
I would like to shorten the labels to show an M instead of six 0s, for instance.
I've looked into the documentation and and have not found anything of such.
You could override the ticks.callback method as documented here: https://www.chartjs.org/docs/latest/axes/labelling.html#creating-custom-tick-formats
For example, to abbreviate the y-axis zeros to simply 'M':
var chart = new Chart(ctx, {
type: 'line',
data: data,
options: {
scales: {
yAxes: [{
ticks: {
// Abbreviate the millions
callback: function(value, index, values) {
return value / 1e6 + 'M';
}
}
}]
}
}
});
My fiddle: https://jsfiddle.net/robhirstio/hsvxbjkg/17/
Adding commarize feature for k, M, B and T
function commarize(min) {
min = min || 1e3;
// Alter numbers larger than 1k
if (this >= min) {
var units = ["k", "M", "B", "T"];
var order = Math.floor(Math.log(this) / Math.log(1000));
var unitname = units[(order - 1)];
var num = Math.floor(this / 1000 ** order);
// output number remainder + unitname
return num + unitname
}
// return formatted original number
return this.toLocaleString()
}
In chart JS you could use config property ticks into yAxes
var chart = new Chart(ctx, {
type: 'line',
data: data,
options: {
scales: {
yAxes: [{
ticks: {
// Include a dollar sign in the ticks
callback: function(value, index, values) {
return String(value).commarize();
}
}
}]
}
}
});
Chart JS Reference https://www.chartjs.org/docs/latest/axes/labelling.html
Commarize reference https://gist.github.com/MartinMuzatko/1060fe584d17c7b9ca6e
Support 'K', 'M', 'B':
This is my solution, to be generic when you use the same options object for multiple charts, that possibly contain lower numbers or negative numbers.
formatNumbers(value) {
if (value >= 1000000000 || value <= -1000000000 ) {
return value / 1e9 + 'B';
} else if (value >= 1000000 || value <= -1000000) {
return value / 1e6 + 'M';
} else if (value >= 1000 || value <= -1000) {
return value / 1e3 + 'K';
}
return value;
}
My fiddle:
https://jsfiddle.net/epsilontal/v0qnsbwk/45/
Example:
Percentage share is used to depict the part-to-whole relationship in a chart.
Observe the point.percentage property used in Pie chart series data labels to show the percentage share with respect to the whole chart :
http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/pie-basic/
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
}
I would like to achieve the following:
Reference of this example : https://www.grapecity.com/en/blogs/sunburst-chart-roadmap-what-would-you-like-to-see
I know that the above percentage share with respect to parent and with respect to whole chart, can be achieved by manually setting the respective values. But that involves manual calculations.
I want to know if Highcharts supports point.percentage for Sunburst charts. Its not given in the API reference and I also did not get it on debugging an example in JS Fiddle.Is there any other way to achieve it?
No, point.percentage is only for stacked series or pies: https://api.highcharts.com/class-reference/Highcharts.Point#.percentage
However, if you use a dataLabels.formatter, it's easy to calculate the percentage for each slice. In the formatter function, you'll have access to the current slice (point) and all the rest of the chart data:
Example (change series.custom.percentage to select percentage calculation)
series: [{
type: 'sunburst',
data: ...,
//https://api.highcharts.com/highcharts/series.sunburst.custom
custom: {
percentage: 'whole', //'whole' or 'parent'
},
dataLabels: {
formatter: function() {
const point = this.point,
series = this.series,
mode = series.options.custom && series.options.custom.percentage;
const chartTotal = series.__myTotal || (series.__myTotal = series.data.map(p => p.options.value || 0).reduce((a, b) => a + b));
let percentage;
switch(mode) {
case 'whole':
percentage = point.value/chartTotal;
break;
case 'parent':
const group = point.parent && series.chart.get(point.parent),
total = group ? group.value : chartTotal;
percentage = point.value/total;
break;
}
const val = (percentage === undefined) ? point.value : (percentage * 100).toFixed(1) + '%';
return point.name + '<br>' + val;
},
},
...
https://jsfiddle.net/pntjgqby/
The jsfiddle link is here http://jsfiddle.net/MzQE8/110/
The problem here I feel is in my JavaScript.
I input values to the series object in a HighChart from an array. On the array I am trying to find index and the value of the maximum element and then I am saving the maximum array element back with this modification
yArr[index] = {
y: value,
color: '#aaff99'
};
So that It appears as a diferent color from the rest of the points on the graph which is a dynamic one. That is its sliding one.
Here is my code
$(function () {
$(document).ready(function () {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var chart;
$('#container').highcharts({
chart: {
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function () {
// set up the updating of the chart each second
var series = this.series[0];
//As this graph is generated due to random values. I am creating an Array with random values.
var yArr = [];
yArr[0] = Math.random();
yArr[1] = Math.random();
yArr[2] = Math.random();
yArr[3] = Math.random();
setInterval(function () {
console.log(yArr.length);
var x = (new Date()).getTime(), // current time
y = Math.random();
var index = findIndexOfGreatest(yArr);
var value = yArr[index];
yArr[index] = {
y: value,
color: '#aaff99'
};
series.addPoint([x, yArr.shift()], true, true);
yArr.push(Math.random());
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 450
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
plotOptions: {
series: {
lineWidth: 1
}
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' + Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random Data',
data: (function () {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: yArr.shift()
});
}
return data;
})(),
color: 'red'
}]
});
});
function findIndexOfGreatest(array) {
var greatest;
var indexOfGreatest;
for (var i = 0; i < array.length; i++) {
if (!greatest || array[i] > greatest) {
greatest = array[i];
indexOfGreatest = i;
}
}
return indexOfGreatest;
}
});
I feel my idea is correct but there are big holes in my implementation. I guess.
Thanks
See demo: http://jsfiddle.net/MzQE8/350/
All y-values are stored in series.yData, so you don't have to create another array for that. Now just update point which is the highest one, and add new points. Something like above demo, code:
events: {
load: function () {
// set up the updating of the chart each second
var series = this.series[0],
index = series.yData.indexOf(series.yData.max());
// mark first max points
this.series[0].prevMax = this.series[0].data[index];
this.series[0].prevMax.update({
color: '#aaff99'
});
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random(),
color = null,
index, max;
if (series.prevMax && series.prevMax.update) {
// remove previously colored point
if (y > series.prevMax.y) {
series.prevMax.update({
color: null
}, false);
color = '#aaff99';
// store max, which is last point
series.prevMax = series.data[series.yData.length];
}
} else {
max = series.yData.max();
index = series.yData.indexOf(max);
if(y > max) {
color = '#aaff99';
series.prevMax = series.data[series.yData.length];
} else {
series.prevMax = series.data[index];
series.prevMax.update({
color: '#aaff99'
}, false)
}
}
// add new point
series.addPoint({
x: x,
y: y,
color: color
}, true, true);
}, 1000);
}
}
im not to sure what your seeking but if i understand correctly you want the bullet marks to be a different color to differentiate from the others. i wont include source code because what you have included in your js fiddle is pretty advanced stuff and you will be able to figure this out no problem.
calculate (all total values added together / 256 + i) * 255 (or something similar)
the i represents the bullet increment in a loop. please for give the algorithm i haven't slept in 32 hours and i know its def. suggested you check it.
Oh.. kay here is the updated solution working out on paper
http://i966.photobucket.com/albums/ae147/Richard_Grant/Untitled-1_zps7766a939.png
I PUT A LOT OF WORK INTO THIS! so please!!! use it well -.-'
What is happening here is i drew out a graph with values going from 0 - 200 and i labeled the graph results 1 - 4, i also made this the x coordinates cause im lazy.
In the workflow RES = means results or X, Val = Value or Y
These are used to calculate RGB values and i solved the first 3 results. the first result tangent should always be 0 because any number divisible by 0 is 0, and any number multiplied by 0 is 0.
When i say tangent i mean the angle of the point by the 200, 0 value (invisible point). in this formula the angle would not be perfected because the x and y on the graph are not equal, one is 200 max and the other is 4 max. if i wanted this to be accurate i would have turned the tangent into a percent and multiplied it by 255. but i didn't.
I feel i have given you the necessary tools to complete your request on your own now :) if you do not understand how i did this or found this algorithm, just fall back to random colors.
Thanks John doe, your question helped me. This is the function i used to change the color of the maximum value of my y axis:
function () {
var maximum = chart.yAxis[0].dataMax;
var index = series.yData.indexOf(maximum);
chart.series[0].data[index].update({ color: '#aaff99' });
}
It may help other people too.