Using array index/variables in Animated Google Barchart Labels - javascript

I have a series of tables in my database, and want to use google charts to show this data. I'd also like it to animate nicely, and I found a good code snippet from somewhere that helps out with this, and I'm modifying it.
As the tables in my database are different I don't know how many columns each table will have, and therefore don't know how many bars the chart should have, until the query is made via ajax (up to a maximum of 5).
I'm going to get the data via ajax request and return an array, I'll then count the number of items in the array to get the number of columns. At the moment I'm simulating this bit, but the data will look like this:
var Columns = ['Tracker', '1', '2', '3'];
var Information = ['A', 475, 450, 190];
However, when I try to use the identifier to get the column label the chart breaks.
I've included the code below and also a link to a jsfiddle that will show you the problem. What is going wrong?
Also, if any of you can think of a better way to achieve this without the repeated code and rubbish if clause - for some reason can't find a better way to this myself.
Jsfiddle here
Code:
function drawVisualization() {
// Create and populate the data table.
var Columns = ['Tracker', '1', '2', '3'];
var Information = ['A', 475, 450, 190];
//var Columns1 = Columns[1]; //uncomment this and comment out the line below to see the problem
var Columns1 = 1;
var NumColumns = Columns.length -1;
//alert(Columns1); // to see what Columns1 is
for (index = 1; index < Columns.length; ++index) {
var ColumnName = Columns[index];
var CorrespondingData = Information[index];
}
var data = google.visualization.arrayToDataTable([
Columns,
Information
]);
// use a DataView to 0-out all the values in the data set for the initial draw
var view = new google.visualization.DataView(data);
if(NumColumns == 1){
view.setColumns([0, {
type: 'number',
label: data.getColumnLabel(Columns[1]),
calc: function () {return 0;}
}]);
}else if(NumColumns == 2) {
view.setColumns([0, {
type: 'number',
label: data.getColumnLabel(Columns[1]),
calc: function () {return 0;}
}, {
type: 'number',
label: data.getColumnLabel(Columns[2]),
calc: function () {return 0;}
}]);
}else if(NumColumns == 3){
view.setColumns([0, {
type: 'number',
label: data.getColumnLabel(Columns1), //this does not work if the variable Columns1 is set to Columns[1]
calc: function () {return 0;}
}, {
type: 'number',
label: data.getColumnLabel(2),
calc: function () {return 0;}
}, {
type: 'number',
label: data.getColumnLabel(3),
calc: function () {return 0;}
}]);
}
// Create and draw the visualization.
var chart = new google.visualization.ColumnChart(document.getElementById('visualization'));
var options = {
title:"Sub-Region vs Region vs Budget",
legend: 'bottom',
hAxis: {
title: ""
},
animation: {
duration: 1000
},
vAxis: {
// set these values to make the initial animation smoother
minValue: 0,
maxValue: 600
}
};
var runOnce = google.visualization.events.addListener(chart, 'ready', function () {
google.visualization.events.removeListener(runOnce);
chart.draw(data, options);
});
chart.draw(view, options);
// you can handle the resizing here - no need to recreate your data and charts from scratch
$(window).resize(function() {
chart.draw(data, options);
});
}
google.load('visualization', '1', {packages: ['corechart'], callback: drawVisualization});

So I worked this out and am posting the answer to anyone who might be trying to do the same thing. The problem I encountered was due to a misunderstanding referring this line:
label: data.getColumnLabel(1),
I thought that this was referring to the column that was labelled (1) in the original column names. Instead, (1) actually refers to the column number (i.e. if the first column in the data series was called "A", getColumnLabel(1) would return "A".
Therefore if you want to achieve what I was trying to achieve, simply do the following:
function drawVisualization() {
// Create and populate the data table.
var Columns = ['Tracker', 'A', 'B', 'C'];
var Information = ['A', 475, 450, 190];
var NumColumns = Columns.length -1;
/*for (index = 1; index < Columns.length; ++index) {
var ColumnName = Columns[index];
var CorrespondingData = Information[index];
}*/
var data = google.visualization.arrayToDataTable([
Columns,
Information
]);
// use a DataView to 0-out all the values in the data set for the initial draw
var view = new google.visualization.DataView(data);
if(NumColumns == 1){
view.setColumns([0, {
type: 'number',
label: data.getColumnLabel(1),
calc: function () {return 0;}
}]);
}else if(NumColumns == 2) {
view.setColumns([0, {
type: 'number',
label: data.getColumnLabel(1),
calc: function () {return 0;}
}, {
type: 'number',
label: data.getColumnLabel(2),
calc: function () {return 0;}
}]);
}else if(NumColumns == 3){
view.setColumns([0, {
type: 'number',
label: data.getColumnLabel(1),
calc: function () {return 0;}
}, {
type: 'number',
label: data.getColumnLabel(2),
calc: function () {return 0;}
}, {
type: 'number',
label: data.getColumnLabel(3),
calc: function () {return 0;}
}]);
}
// Create and draw the visualization.
var chart = new google.visualization.ColumnChart(document.getElementById('visualization'));
var options = {
title:"Sub-Region vs Region vs Budget",
legend: 'bottom',
hAxis: {
title: ""
},
animation: {
duration: 1000
},
vAxis: {
// set these values to make the initial animation smoother
minValue: 0,
maxValue: 600
}
};
var runOnce = google.visualization.events.addListener(chart, 'ready', function () {
google.visualization.events.removeListener(runOnce);
chart.draw(data, options);
});
chart.draw(view, options);
// you can handle the resizing here - no need to recreate your data and charts from scratch
$(window).resize(function() {
chart.draw(data, options);
});
}
google.load('visualization', '1', {packages: ['corechart'], callback: drawVisualization});

Related

Google Chart How can I pass variables to a DataView calculated column function?

According to Google a DataView can be used to calculated column values on the fly.
(see documentation)
var myValue = 100;
var view = new google.visualization.DataView(data);
view.setColumns([
data.getColumnIndex('PART'),
data.getColumnIndex('VALUE'),
{ calc: exampleFromGoogle, type: 'number'},
{ calc: customWithExternalValues, type: 'number'},
]);
The google calc example does not do not use any outside values and is self contained.
function exampleFromGoogle(dataTable, rowNum) {
return Math.floor(dataTable.getValue(rowNum, 1) / 2.54);
}
I would like to pass the calc function a variable myValue but I do not know the syntax where the calculation function is called. { calc: customWithExternalValues, type: 'number'}
This is the function I wish to use.
function customWithExternalValues(dataTable, rowNum, myValue) {
return (Math.floor(dataTable.getValue(rowNum, 1) / 2.54))* myValue;
}
How can I accomplish this?
Any ideas are greatly appreciated...Thanks!
use the custom function within the example function...
var myValue = 100;
var view = new google.visualization.DataView(data);
view.setColumns([
data.getColumnIndex('PART'),
data.getColumnIndex('VALUE'),
{ calc: exampleFromGoogle, type: 'number'},
{ calc: exampleFromGoogle, type: 'number'},
]);
function exampleFromGoogle(dataTable, rowNum) {
return customWithExternalValues(dataTable, rowNum, myValue);
}
function customWithExternalValues(dataTable, rowNum, myValue) {
return (Math.floor(dataTable.getValue(rowNum, 1) / 2.54)) * myValue;
}

How to change line color based on the value [google charts]

I have a chart to represent some temperatures of a specific place, I am using Google Chart tools (area chart), and Im trying to put a diferent color (orange) if the temperature is greater than 25 degrees
Javascript code
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Data');
data.addColumn('number', 'Temperatura ÂșC');
data.addColumn({ type: 'number', role: 'annotation' });
var array = JSON.parse('<%=jsonStringTemp%>');
console.log(array);
for(var i=0; i<array.length;i++){
var array2=[];
for (j = 0; j < array[i].length; j++){
if (typeof array[i][j]==='string') {
if (j !== 0) {
array[i][j]=parseInt(array[i][j], 10)
}
}
array2.push(array[i][j])
}
data.addRow(array2)
}
console.log(data)
var options = {
title: 'Temperatura',
hAxis: {title: 'Data', titleTextStyle: {color: '#333'}},
vAxis: { minValue: 0 },
series: {
0: {
color: 'green'
},
},
pointSize: 6
};
;
var chart = new google.visualization.AreaChart(document.getElementById('linechart_material'));
chart.draw(data, options);
}
output
Is it possible to do it? And How?

Google charts LineGraph switching datatables and maintaining state

I have tweaked a few examples I found across the net that allow me to remove/greyout a series when it is clicked (legend or line itself).
I then wanted to add ability to switch between datatables and have what was hidden/greyedout to transfer to the new datatable.
I took the idea from switching data from https://developers.google.com/chart/interactive/docs/animation#value-changes
(my graphs are not animating correctly like the example)
My problem is I get very weird results when clicking on the "Switch" button and switching datatables, sometimes it will keep the correct selection but when you click on a different series one will magically appear or it will deselect a different series than the one clicked. I can't figure out to get it so both datatables maintain the same selection (selection meaning greyed out/removed series).
It's worth noting that
columns.push({
calc: 'stringify',
sourceColumn: i,
type: 'string',
role: 'annotation'
});
is adding hidden columns to aide in additional logic for the series. While I am not directly using it currently I want it to remain and work properly because I think I will use it in the future. These "hidden" columns add complexity where I think the bug lives.
The code is here:
var button = document.getElementById('b1');
var current = 0;
var data = [];
var chart;
var options;
var ms2 = [{
"LOCAL_ID": "W-133",
"Class1": 29,
"Class2": 3628,
"Class3": 159,
"Class4": 24,
"Class5": 65,
"Class6": 12,
"Class7": 0,
"Class8": 12,
"Class9": 110,
"Class10": 41,
"Class11": 0,
"Class12": 0,
"Class13": 0
}, {
"LOCAL_ID": "14-6A-060",
"Class1": 19,
"Class2": 290,
"Class3": 224,
"Class4": 0,
"Class5": 0,
"Class6": 0,
"Class7": 0,
"Class8": 2,
"Class9": 0,
"Class10": 0,
"Class11": 1,
"Class12": 0,
"Class13": 0
}, {
"LOCAL_ID": "45-5-006",
"Class1": 7,
"Class2": 191,
"Class3": 165,
"Class4": 0,
"Class5": 6,
"Class6": 3,
"Class7": 0,
"Class8": 4,
"Class9": 18,
"Class10": 11,
"Class11": 0,
"Class12": 0,
"Class13": 10
}];
google.charts.load('current', {
'packages': ['line']
});
google.charts.setOnLoadCallback(init);
button.onclick = function() {
current = 1 - current;
button.disabled = true;
options.chart['subtitle'] = (current ? 'View 1' : 'View 2');
chart.draw(data[current], options);
};
function getData() {
var data = new google.visualization.DataTable();
data.addColumn('number', 'Class');
ms2.forEach(function(masterLocation, index) {
data.addColumn('number', masterLocation.LOCAL_ID);
});
for (var i = 0; i < 13; i++) {
var arr = [i];
ms2.forEach(function(masterLocation, index) {
arr.push(masterLocation['Class' + i]);
});
data.addRow(arr);
}
return data;
}
function getRandomData(base) {
var data = new google.visualization.DataTable();
data.addColumn('number', 'Class');
data.addColumn('number', ms2[0].LOCAL_ID);
data.addColumn('number', ms2[1].LOCAL_ID);
data.addColumn('number', ms2[2].LOCAL_ID);
// add random data
var y1 = base,
y2 = base,
y3 = base;
for (var i = 0; i < 13; i++) {
y1 += Math.floor(Math.random() * 5) * Math.pow(-1, Math.floor(Math.random() * 2));
y2 += Math.floor(Math.random() * 5) * Math.pow(-1, Math.floor(Math.random() * 2));
y3 += Math.floor(Math.random() * 5) * Math.pow(-1, Math.floor(Math.random() * 2));
data.addRow([i, y1, y2, y3]);
}
return data;
}
function init() {
data = [];
data[0] = getData();
data[1] = getRandomData(1000);
chart = new google.charts.Line(document.getElementById('chart_div'));
options = {
chart: {
title: 'Box Office Earnings in First Two Weeks of Opening',
subtitle: 'in millions of dollars (USD)'
},
width: 500,
height: 300,
vAxis: {
gridlines: {
color: '#ccc'
}
},
hAxis: {
gridlines: {
color: '#ccc'
}
},
animation: {
duration: 1000,
easing: 'out'
}
};
drawChart();
}
function drawChart() {
var columns = [];
var defaultSeries = [1, 2, 3];
var series = {};
for (var i = 0; i < data[current].getNumberOfColumns(); i++) {
if (i === 0 || defaultSeries.indexOf(i) > -1) {
// if the column is the domain column or in the default list, display the series
columns.push(i);
} else {
// otherwise, hide it
columns.push({
label: data.getColumnLabel(i),
type: data.getColumnType(i),
sourceColumn: i,
calc: function() {
return null;
}
});
}
if (i > 0) {
columns.push({
calc: 'stringify',
sourceColumn: i,
type: 'string',
role: 'annotation'
});
// set the default series option
series[i - 1] = {};
if (defaultSeries.indexOf(i) == -1) {
// backup the default color (if set)
if (typeof(series[i - 1].color) !== 'undefined') {
series[i - 1].backupColor = series[i - 1].color;
}
series[i - 1].color = '#CCCCCC';
}
}
}
options['series'] = series;
function showHideSeries() {
var sel = chart.getSelection();
if (sel.length < 1 || sel[0].row) {
return;
}
var col = sel[0].column;
if (typeof(columns[col]) == 'number') {
var src = columns[col];
var calcFunc = null;
if (document.getElementById("removeSeriesOnSelect").checked) {
calcFunc = function() {
return null;
};
}
columns[col] = {
label: data[current].getColumnLabel(src),
type: data[current].getColumnType(src),
sourceColumn: src,
calc: calcFunc
};
// grey out the legend entry
series[src - 1].color = '#CCCCCC';
} else {
var src = columns[col].sourceColumn;
// show the data series
columns[col] = src;
series[src - 1].color = null;
}
var view = new google.visualization.DataView(data[current]);
view.setColumns(columns);
chart.draw(view, options);
}
google.visualization.events.addListener(chart, 'select', showHideSeries);
google.visualization.events.addListener(chart, 'ready', function() {
button.disabled = false;
});
var view = new google.visualization.DataView(data[current]);
view.setColumns(columns);
chart.draw(view, options);
}
Here is the jsFiddle: https://jsfiddle.net/sp7atw1L/
Edit: I started a bounty. Given the global variables and maybe the indirect way this is doing things. I am not opposed to a direct refactor/redo that accomplishes the same thing.
Indeed the bug is related to annotation columns. After drawChart() your columns array is [0,1,{a},2,{a},3,{a}].
> when column 1 clicked, everything is ok.
> when column 2 clicked, columns[2] is {a}, which in your code is replaced by 1, so, you get another copy of column 1
> when column 3 clicked, columns[3] is 2, so, the wrong row is selected
These are consequences, but the problem lies in chart.getSelection() not taking into account annotation columns and returning wrong indexes. I am not sure why this happens, but if you draw DataView (instead of DataTable) in onclick handler like this
//chart.draw(data[current], options); <-------remove this
var view = new google.visualization.DataView(data[current]);
view.setColumns(columns);// <---make columns global
chart.draw(view, options);
it solves the issue. A related problem with annotations is e.g. here
Additionally, in getData() the line
arr.push(masterLocation['Class' + i]);
should be
arr.push(masterLocation['Class' + i+1]);

Google chart - reformat variable not working

In Google chart- when i call the function to remove comma from variable from input , it wont work.
What i want is result from ldsalary(without comma) update in Google chart. ldsalary value is calculated and shown while onkeyup. It will be changing.
update : made a jsfiddle
onkeyup:
document.getElementById('cal').onkeyup=function(){
calculator();
drawChart();
reformat function:
function reformat(str) {
while (str.search(",") >= 0) {
str = (str + "").replace(',', '');
}
return str;
};
Calculator function, this updates ldsalary with new value:
function calculator(){
.........
var jldsalary = document.getElementById("ldsalary");
xm = a * Math.pow(1 + jasincrease / 100, b);
jldsalary.value = rounding(xm).toLocaleString();
}
Chart:
<script type="text/javascript">
var rage = 55 ;
var slry = 5000;
google.load('visualization', '1', {packages: ['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
rage =document.getElementById('rage').value *1;
var xxx = document.getElementById('ldsalary').value *1;
// if i add this google chart wont show.
slry.value =reformat(xxx); // without reformat, there will be ',' value.
var data = new google.visualization.DataTable();
data.addColumn('number', 'X');
data.addColumn('number', 'Amount');
data.addRows([
[0, 0], [rage,slry],
[100, 0]
]);
var options = {
curveType: 'function',
width: 500,
height: 200,
hAxis: {
title: 'Age'
},
vAxis: {
title: 'Amount'
}
};
var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));
chart.draw(data, options);
}
Its been a day doing all kinds of solutions. Advance thanks for helping me.
as per your code, you have defined slry as a variable, and trying to use spry.value, which is not valid at all, change:
...
slry.value =reformat(xxx); //its just a variable not input element
to
...
slry = reformat(xxx);
The problem was in reformat().
function reformat(str) {
return parseInt(str.replace(',', ''));
}
Now it works: as value in input box changes , google graph too changes.

setting google chart multiple axes from dynamically generated data

I'm trying to replicate the following code from a working example:
series: {0: {targetAxisIndex:0},
1: {targetAxisIndex:0},
2: {targetAxisIndex:1},
This is for setting which y-axis is used to plot different columns from a dataTable on a Google chart.
However I have a variable number of columns (based on user input), therefore am collecting an array of the required axis (the axisAssignment Array in the below example).
My code is below:
var series = {};
for (i=0;i<axisAssignment.length;i++)
{
series[i] = {targetAxisIndex: axisAssignment[i]};
}
return series;
However, all of my data is only being written to the left axis, despite the debugger suggesting that the object is correct. My option code is below:
var options =
{
hAxis: {title: xTitle},
vAxes: {0: {title: y1Type},
1: {title: y2Type}
},
series: calculateSeries(),
pointSize: 1,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
Any assistance would be greatly apreciated.
Thanks
Tom
edit: whole file for reference (it's a work in progress so a bit of a mess I'm afraid)
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart());
function drawChart()
{
var title = "Node: "+currentNode;
var xTitle = "Date";
var yTitle = titles[currentVariable];
if (totalData !== null)
{
var tempData = newData();
var tempData2 = totalData;
dataArray[dataCount] = tempData;
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],joinMark,[1]);
dataCount = dataCount+1;
}
else
{
totalData = newData();
dataArray[dataCount] = totalData;
dataCount = 1;
}
var options =
{
hAxis: {title: xTitle},
vAxes: {0: {title: y1Type},
1: {title: y2Type}
},
series: calculateSeries(),
pointSize: 0.5,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
var chart = new google.visualization.ScatterChart(document.getElementById('graph'));
console.log(calculateSeries());
chart.draw(totalData, options);
function countArray(count)
{
var arrayCount= new Array();
if (count===1)
{
arrayCount[0] = count;
}
else
{
for (var i=0;i<count;i++)
{
var temp = i+1;
arrayCount[i] = temp;
}
}
return arrayCount;
}
function calculateSeries()
{
var series = {};
for (i=0;i<axisAssignment.length;i++)
{
series[i] = {targetAxisIndex: axisAssignment[i]};
}
return series;
}
function newData()
{
var dataType = dataIn[0];
dataIn.shift();
var axis = dataSelect(dataType);
axisAssignment.push(axis);
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', "Node: "+currentNode+": "+titles[currentVariable]);
var num = (dataIn.length);
data.addRows(num/2);
var i = 0;
var j = 0;
while (i<num)
{
var d = (dataIn[i]);
if (i%2===0)
{
d = new Date(d);
data.setCell(j,0,d);
i++;
}
else
{
data.setCell(j,1,parseFloat(d));
i++;
j++;
}
}
return data;
}
function dataSelect(type)
{
var axisNumber;
if (y1Type === null || y1Type === type)
{
y1Type = type;
axisNumber = 0;
}
else if (y2Type === null || y2Type === type)
{
y2Type = type;
axisNumber = 1;
}
else
{
alert("You already have 2 axes assigned.\n\nPlease clear the graph \nor select more objects of \ntype"+y1Type+" or \ntype "+y2Type+" to continue.");
axisNumber = null;
}
return axisNumber;
}
}
Ok, it seems that it's an issue with my choice of ScatterChart,
var options =
{
hAxis: {title: xTitle},
series: calculateSeries(),
vAxes: {0: {title: y1Type },
1: {title: y2Type}
},
pointSize: 0.5,
legend: {position: 'top', textStyle: {fontSize: 10}}
};
var chart = new google.visualization.LineChart(document.getElementById('graph'));
chart.draw(totalData, options);
I've changed it to LineChart and it's working fine, by keeping the pointSize option, the appearance is almost completely unchanged. Thanks for your help juvian.

Categories