Google Visualisation - column chart interval issue (duplicate intervals) - javascript

I'm using the following code to generate the above google chart:
var data = google.visualization.arrayToDataTable([
['Date', 'Tickets'],
['11/05/15',1],
['10/05/15',0],
['09/05/15',0],
['08/05/15',0],
['07/05/15',0],
['06/05/15',0],
['05/05/15',0],
['04/05/15',0],
]);
var columnChartOptions = {
title: "",
legend: { position: 'none' },
width: '100%',
height: '100%',
colors: ["#27ae60", "#2980b9", "#e67e22", "#e74c3c", "#e74c3c"],
chartArea: { left: '8%', top: '8%', width: "85%", height: "70%" },
vAxis: {
minValue: 1,
format:'#'
},
new google.visualization.ColumnChart(document.getElementById('ticket-history-graph')).
draw(data,columnChartOptions);
However it produces the following wrong interval counts:
What changes do I need to make to the vAxis definition to correct this? I've tried varying min and max values to no avail. I must also add that when higher numbers are used this is not a problem, it's only with lower counts.

Your problem is the format:'#', which is the reason why you get two zeros and three ones (as you round to zero decimals, and the graph tries to present the values [0, 0.25, 0.5, 0.75, 1] which are rounded to [0, 0, 1, 1, 1], therefore duplicates them).
My suggestion is that you check out the property vAxis.gridlines.count documentation.
I made a fiddle, where I check if the maxValue in the graph is 1 or 2, if so I specify the gridlines to either the count of 2 or 3, and if it's neither 1 or 2, it uses googles own automatic generation.
Check and see if you follow how I've done: jsfiddle
Remember to try and change some values to higher/lower to see how it works.
//Get all distinct ticketsales, sorted ascending by default, so you have to get the last value to get the highest one.
var maxValue = data.getDistinctValues(1)[data.getDistinctValues(1).length - 1]
// Specify gridCount to null, so if it doesn't enter any of the if's below, it will still be null
var gridCount = null
//check if the highest value is 1 or 2 else leave gridCount to null
if (maxValue == 1) {
gridCount = 2
}
if (maxValue == 2) {
gridCount = 3
}
Aswell as the addition to the columnChartOptions:
vAxis: {
gridlines: {
//specify the amount of gridlines to var gridCount, if it's still specified as null, it will use googles automatic generation.
count: gridCount
},

Related

Reversed bullet chart in Highcharts

I started working with highcharts. Now a problem I am facing is that the bulletcharts can’t be used for a dataset that is in descending order.
For example say we want to plot the ranking of a few companies. In this case the ranking is better the lower it gets. So a Rank 10 is better than a Rank 15 and so on.
In this case I want my graph to get reversed. The target would be lets say 10. The min value would start from say 100 to 0. So you can see how this isnt possible.
P.S: I know the
reverse: true/false
property. But that simply flips the graph and I don’t want that/need that.
Thanks world.
You can add a second y-axis with the same extremes as the first one, but reversed. Next, hide the first y-axis, calculate mocked y and target values and finally, set a custom formatter function for tooltip to show original values.
const MAX = 300;
const TARGET = 50;
const Y = 25;
Highcharts.chart('container1', {
chart: {
inverted: true,
type: 'bullet',
},
yAxis: [{
visible: false,
min: 0,
max: MAX
}, {
min: 0,
max: MAX,
reversed: true,
...
}],
tooltip: {
formatter: function(tooltip) {
const point = this.point;
return `<span style='color: ${this.color}'>●</span> ${this.series.name}: <b>${point.originalY}</b>. Target: <b>${point.originalTarget}</b><br/>`
}
},
series: [{
data: [{
y: MAX - Y,
target: MAX - TARGET,
originalY: Y,
originalTarget: TARGET
}]
}]
});
Live demo: https://jsfiddle.net/BlackLabel/ve8hosd3/
API Reference: https://api.highcharts.com/highcharts/tooltip.formatter

How to count prediction (forecasting) in highchart only with data behind the last plotline?

I have a code for standard area-spline highchart where I made a function for prediction based on previous data. Prediction / forecasting is showing next 4 values in a trendline where the first prediction point is counting with real data, second point with real data plus first prediction point and the next two points about the same plus previous predictions. Otherwise it would be only a line with same values. But my data are increasing so the forecasting must be about the same.
Data in highchart are connected to Microsoft SQL Server.
Prediction is based on this code, just with few changes:
Forecast formula from Excel in Javascript
The highchart is now showing increasing data (values of resistance) as a decimal in yAxis and datetime in xAxis. Prediction is working as well but the thing is that not all data are relevant.There is always a point which is very different (lower than previous) and thats the place from where I need to count new prediction. The plotline is generated in the last high value, then starting the new (low) - and that is from where I need to count.
So here is what I do have:
-the function 'average' is counting average from values
-second function 'forecast' as you can expect is counting the forecasting (based on the code from link above)
-third function 'test' is already putting all together
-the 'results' (2,3,4) are the counted points of prediction
-'vlastnidata' are the data from mssql
-'datumek' is for the date
Now the condition for plotline (as you can see there) is that the previous point in chart must be 20 higher and then the plotline is generated - this is also working, just need to find a way how to count only with new data behind the plotline.
And here you can reach the connection function to mssql in php - if needed
Is there a way how to dynamically create a plotline in highchart when the value is lower than previous one?
As I said everything is working, plotlines and the prediction. But to see clear prediction I need to count only with relevant data.
Hope everything is clear. Thank you in advance for any recommendations.
function average(ar)
{
var r=0;
for (i=0;i<ar.length;i++)
{
r = r+ar[i];
}
return r/ar.length;
}
function forecast(x, ky, kx)
{
var i=0, nr=0, dr=0,ax=0,ay=0,a=0,b=0, result=0;
ax=average(kx);
ay=average(ky);
for (i=0;i<kx.length;i++)
{
nr = nr + ((kx[i]-ax) * (ky[i]-ay));
dr = dr + ((kx[i]-ax)*(kx[i]-ax))
}
b=nr/dr;
a=ay-b*ax;
result = (a+b*x);
return result;
}
function test(container,nazev,rtop,vlastnidata,colorSeries)
{
var result = 0, result2 = 0, result3 = 0, result4 = 0, datumek=[],hodnoty=[];
for (a=0;a<vlastnidata.length;a++)
{
datumek[a]=vlastnidata[a][0];
hodnoty[a]=vlastnidata[a][1];
}
kalkulace=(datumek[vlastnidata.length-1]-datumek[vlastnidata.length-2]);
hodnoty_nove=hodnoty;
datumek_nove=datumek;
result = forecast((datumek[vlastnidata.length-1]+kalkulace), hodnoty, datumek);
hodnoty_nove[hodnoty_nove.length]=result;
datumek_nove[datumek_nove.length]=(datumek[vlastnidata.length-1]+kalkulace);
result2 = forecast((datumek[vlastnidata.length-1]+2*kalkulace), hodnoty_nove, datumek_nove);
hodnoty_nove[hodnoty_nove.length]=result2;
datumek_nove[datumek_nove.length]=(datumek[vlastnidata.length-1]+2*kalkulace);
result3 = forecast((datumek[vlastnidata.length-1]+3*kalkulace), hodnoty_nove, datumek_nove);
hodnoty_nove[hodnoty_nove.length]=result3;
datumek_nove[datumek_nove.length]=(datumek[vlastnidata.length-1]+3*kalkulace);
result4 = forecast((datumek[vlastnidata.length-1]+4*kalkulace), hodnoty_nove, datumek_nove);
Highcharts.chart(container, {chart: {type: 'areaspline',
events: {
load:function(){
let points = this.series[0].points;
let plotLines = [];
console.log(this)
let previousPoint = points[0];
points.forEach(function(point) {
if(point.y < previousPoint.y/100*80) {
plotLines.push({
value: previousPoint.x,
color: 'red',
width: 3
});
}
previousPoint = point;
});
this.xAxis[0].update({
plotLines: plotLines
})
}
}
},
title: {text: 'Average of resistance per month, '+rtop},
legend: {layout: 'vertical',
align: 'left',
verticalAlign: 'top',
x: 150,
y: 100,
floating: true,
borderWidth: 1,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'},
xAxis: { type: 'datetime'},
yAxis: {title: {text: 'Resistance: in ohms'}},
tooltip: {shared: true,valueSuffix: ' ohms',valueDecimals: 2},
credits: {enabled: false},
plotOptions: {areaspline: {fillOpacity: 0.5}},
series: [{ name: nazev,
color: colorSeries,
data: vlastnidata},
{name: 'Prediction',
color: '#001a33',
data: [[(datumek[vlastnidata.length-1]+kalkulace),result], [(datumek[vlastnidata.length-1]+2*kalkulace),result2], [(datumek[vlastnidata.length-1]+3*kalkulace),result3], [(datumek[vlastnidata.length-1]+4*kalkulace),result4]]
}]
});
}

how to make the vAxis and hAxis number in integer

Here is my code:
var rawdata='".$performances."';
var mydata=jQuery.parseJSON(rawdata);
if(mydata){
var realData=[];
realData=[
['Activities', 'Performance'],
];
for (x in mydata)
{
var a=parseFloat(mydata[x]['activities']);
var b=parseFloat(mydata[x]['performance']);
realData[x]=[a,b];
}
var data = google.visualization.arrayToDataTable(realData);
var options = {
title: 'Overall Performance',
legend: { position: 'top', maxLines: 3 },
hAxis: {title: 'Activities'},
vAxis: {title: 'Performance'}
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div_line'));
chart.draw(data, options);
And the output is:
I want to change the current x axis value to be integer: 1,2,3,4,...., how can I do it?
Thanks in advance.
There are a couple different approaches you can take to fix this. The first is to set the axis range and gridline count so that the chart defaults to showing integer values, eg:
vAxis: {
viewWindow: {
min: 0,
max: 2
},
gridlines: {
count: 3
}
}
Generally, if min and max are integers and (max - min) / (count - 1) is an integer, then the gridlines (and hence axis labels) will fall on integer values. This approach works best with the y-axis when you know the range of valid values for your chart; you can use it for the x-axis too, but I don't see it used very often.
The other approach is to use the h/vAxis.ticks option to specify the locations of gridlines and labels. The ticks option takes an array of values or objects. Values specify the location of a gridline. Objects have v and f properties; the v property specifies the location of the gridline and the f property specifies the label to use. Any values or objects without a specified f property will generate an axis label according to the axis format option.
hAxis: {
ticks: [1, 2, 3, 4]
}
or:
hAxis: {
ticks: [{v: 1, f: 'one'}, {v: 2, f: 'two'}, {v: 3, f: 'three'}, {v: 4, f: 'four'}]
}
You can mix and match objects and values in the array however you like. This approach works equally well with both the x and y axes.
You can take one approach with one axis and the other approach with the other axis, but if you mix them on the same axis, be aware that the ticks option overrides gridlines.count, and if you place a tick mark outside the range of the viewWindow settings, you will not see it.
Try:
var a=parseFloat(mydata[x]['activities'].toFixed());
var b=parseFloat(mydata[x]['performance'].toFixed());
toFixed() will convert your number to a string; you are using parseFloat(), so the string would be converted back to a number.

Interpolate Nulls in google graph

I use google's chart javascript api to show some data. The data contains "0" / "null" values.
//...
totalpt1.setValue(154, 2, 1310799);
totalpt1.setValue(155, 2, 1313905);
totalpt1.setValue(156, 2, null);
totalpt1.setValue(157, 2, 1320264);
totalpt1.setValue(158, 2, 1323102);
//...
var chart11 = new google.visualization.LineChart(document.getElementById('chart_totalpostthreads'));
chart11.draw(totalpt, {width: 600, height: 340, interpolateNulls:true, legend: 'bottom', title: 'Total Posts'});
The result is this:
I have set interpolateNulls to true. But the graph is still not "smoothed". How can I prevent those single drop outs? I thought this is what the interpolate option was for...
Null and 0 are different values.
You should use:
totalpt1.setValueNull(156, 2);

How to show only integers (no decimals) in chart API x/y-axis labels

I'm using a column chart with the Google Chart JS Api. I'm displaying some values (total orders by day) that can only be represented as integers.
Everything is working great, except that when one of the charts I'm displaying has values that are too low, like 1 or 2, it starts to show decimals on the y-axis. The decimals look silly b/c it's impossible to have "half" an order (which is what I'm counting), and I'd like to hide this if possible.
use the option
vAxis: {format: '0'}
as in
chart.draw(data, {
width: 800,
height: 480,
orientation: 'horizontal',
vAxis: {format: '0'}
}
);
I don't have enough rep to reply to Ian Hunter's post directly, but what that does is format the label, but doesn't set the grid lines to the same value as the label, which can have undesirable results. So let's say you have these grid lines:
10
7.5
5
2.5
0
When you format the label to only show integers it shows this:
10
8
5
3
0
But then your data on the graph doesn't tie-in with the y-scale labels. E.g If you have a value of 3 it actually shows above the '3' labels because the '3' label is actually 2.5
Unfortunately, the only solution I could think of was to monitor the min/max ranges of the data shown in the graph, and then apply some logic to set the min/max according to how many y-scale labels I have, such that they would divide with no remainders.
So in the case above, I'd set it to
vAxis: {
viewWindow:{
max:12,
min:0
}
}
This would give grid lines of
12
8
6
4
0
No decimals, and no problems with the data not correlating with the labels on the graph.
Adding {format : 0} converts the float ticks to integers but the actual values on the bars appear incorrectly.
The main issue is Google Charts API assumes you want 5 gridlines mostly which may not work out to give you integer tick values.
Adding this gave me nice round tick values -
gridlines: { count: -1}
source - https://groups.google.com/forum/#!topic/google-visualization-api/4qCeUgE-OmU
if you want only the integer values to be shown, you should take to account that google charts wants to show you at least 5 gridlines. Presuming all of them should be integer give the graph following:
vAxis: { title: 'Orders Count',
minValue: 4,
viewWindow:{min:0}, /*this also makes 0 = min value*/
format: '0',
},
The easiest way is to edit the left vertical axis, with Min as 0, and Max as a multiple of 5 (5, 10, 15 etc) as appropriate to your expected maximum.
This issue will be resolved if you use vAxis: {gridlines: { count: 4}}
In my case I have values ranging from 0 to 600.
if $value is smaller than 12: use the max value for vAxis.gridlines.count
if $value is greater than 12: use the default nr of gridlines (4)
In this way you only display 'whole numbers'.
You'll need to dynamically generate the javascript off course.
Code Example:
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Fase', 'Closed', 'Open'],
<?php
$max = 0; // needed to determine the number of gridlines?
$data = array();
foreach($projectExecutions as $key => $pe){
$totals = countOpenIssuesInProjectExecution($pe);
$open = $totals['open'];
$closed = $totals['closed'];
$data[] = "['". $FASE[$pe['fase_id']] . "', " . $closed . ", ". $open . "]\r\n";
// What are the Max values vor Open & Closed Defects
if($open > $max ){ $max = $open; }
if($closed > $max ){ $max = $closed; }
}
$nrOfGridLines = ($max >= 12 ? 4 : $max+1); // Calculate the number of gridlines
echo implode(",",$data);
?>
]);
var options = {
legend: { position: 'bottom' }
,title: "Evolution Defects: Open -VS- Closed"
,colors:['#00a160','red']
,isStacked: true
,vAxis: {textPosition: 'in', minValue:0,viewWindow: { min: 0 }, gridlines: {count: <?php echo $nrOfGridLines; ?>} }
};
var chart = new google.visualization.AreaChart(document.getElementById('chart_defects'));
chart.draw(data, options);
}
I'm using the following code:
google.charts.setOnLoadCallback(function(){
var data = new google.visualization.DataTable();
data.addColumn('string', 'Y');
data.addColumn('number', 'X');
var max = 0; //Or something like Int.MinValue
for (var i = 0;i< arr.length;i++) {
max = (arr[i]>max)? arr[i]:max; //calculate max value
data.addRow("<<some calculation>>");
}
var options = {
height: 300,
vAxis: {
gridlines: { count: max+1}, //+1 is importent for the origingridline
viewWindow:{
min: 0,
max: max
},
}
};
var chart = new google.visualization.ColumnChart(document.getElementById("<< div_id >>"));
chart.draw(data, options);
}
Just calculate your maximum value and then set gridlines.count to this value
I'm using the Guava Multiset as my data. Cagy79's trick is the only one that I was able to get working. I also tried generating my own lines using an IntStream, but still had fractional numbers for some of the graphs. As mentioned above, just setting the format will create a graph where the hover over value and the gridline differ.
Multiset items = TreeMultiset.create();
Items added using .add and .addAll
Make sure the items are sorted:
occurrences = Multisets.copyHighestCountFirst(items);
String option = "hAxis : { title : 'Count', gridlines : { count:" +
((max >=12) ? 4 : max+1)
+ } }")
I prefer the gridlines: { count: -1 } option, but you can always explicitly specify the values you want with ticks. Cool thing about this is they don't even have to be evenly spaced - you could do [1, 10, 100, 200, 500, 1000] if you wanted:
options: { vAxis: { ticks: [1,2,3,4,5,6,7,8,9,10] } }
Depending upon your data you may want to hardcode this or use thresholds.
For anyone that are also searching for the answer, you can see the answer to this question here, which use options format.
Can't get Google Charts Axis to format in decimal

Categories

Resources