Google charts LineGraph switching datatables and maintaining state - javascript

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]);

Related

User memory limit exceeded in GEE

I started using GEE recently. I wanted to apply the non-parametric Mann-Kendall method to a collection of Sentinel-1 images. However there is a memory error in the code and this is my problem. Link code:https://code.earthengine.google.com/4bf1dbbcd116c8e3f5c584fbb45e8c19
var quadricula = ee.Geometry.Polygon([[-51.20732599322313,-15.60026586116677],[-51.20732599322313,-15.455379154650098],[-51.262600956602036,-15.455379154650098],[-51.262600956602036,-15.60026586116677]]);
//Map.addLayer(quadricula);
// Filter collection to dates of interest.
var Sentinel1 = ee.ImageCollection('COPERNICUS/S1_GRD')
.filterDate('2015-01-01', '2022-01-01')
.filterBounds(quadricula);
print('Quantidade de imagens no intervalo definido:',Sentinel1.size());
//===========================================================================//
var wrapper = require('users/adugnagirma/gee_s1_ard:wrapper');
var helper = require('users/adugnagirma/gee_s1_ard:utilities');
//---------------------------------------------------------------------------//
// DEFINE PARAMETERS
//---------------------------------------------------------------------------//
//var geometry = ee.Geometry.Polygon([[-51.20732599322313,-15.60026586116677],[-51.20732599322313,-15.455379154650098],[-51.262600956602036,-15.455379154650098],[-51.262600956602036,-15.60026586116677]]);
//Map.addLayer(geometry);
var parameter = {//1. Data Selection
START_DATE: "2015-01-01",
STOP_DATE: "2022-01-01",
POLARIZATION:'VVVH',
ORBIT : 'BOTH',
GEOMETRY: quadricula, //uncomment if interactively selecting a region of interest
//GEOMETRY: ee.Geometry.Polygon([[[104.80, 11.61],[104.80, 11.36],[105.16, 11.36],[105.16, 11.61]]], null, false), //Uncomment if providing coordinates
//GEOMETRY: ee.Geometry.Polygon([[[112.05, -0.25],[112.05, -0.45],[112.25, -0.45],[112.25, -0.25]]], null, false),
//2. Additional Border noise correction
APPLY_ADDITIONAL_BORDER_NOISE_CORRECTION: true,
//3.Speckle filter
APPLY_SPECKLE_FILTERING: true,
SPECKLE_FILTER_FRAMEWORK: 'MULTI',
SPECKLE_FILTER: 'REFINED LEE',
SPECKLE_FILTER_KERNEL_SIZE: 5,
SPECKLE_FILTER_NR_OF_IMAGES: 10,
//4. Radiometric terrain normalization
APPLY_TERRAIN_FLATTENING: true,
DEM: ee.Image('NASA/NASADEM_HGT/001'),
TERRAIN_FLATTENING_MODEL: 'VOLUME',
TERRAIN_FLATTENING_ADDITIONAL_LAYOVER_SHADOW_BUFFER: 0,
//5. Output
FORMAT : 'DB',
CLIP_TO_ROI: true,
SAVE_ASSETS: false
};
//---------------------------------------------------------------------------//
// DO THE JOB
//---------------------------------------------------------------------------//
//Preprocess the S1 collection
var s1_preprocces = wrapper.s1_preproc(parameter);
var s1 = s1_preprocces[0];
s1_preprocces = s1_preprocces[1];
//---------------------------------------------------------------------------//
// VISUALIZE
//---------------------------------------------------------------------------//
//Visulaization of the first image in the collection in RGB for VV, VH, images
var visparam = {};
if (parameter.POLARIZATION=='VVVH'){
if (parameter.FORMAT=='DB'){
var s1_preprocces_view = s1_preprocces.map(helper.add_ratio_lin).map(helper.lin_to_db2);
var s1_view = s1.map(helper.add_ratio_lin).map(helper.lin_to_db2);
visparam = {bands:['VV','VH','VVVH_ratio'],min: [-20, -25, 1],max: [0, -5, 15]};
}
else {
var s1_preprocces_view = s1_preprocces.map(helper.add_ratio_lin);
var s1_view = s1.map(helper.add_ratio_lin);
visparam = {bands:['VV','VH','VVVH_ratio'], min: [0.01, 0.0032, 1.25],max: [1, 0.31, 31.62]};
}
}
else {
if (parameter.FORMAT=='DB') {
s1_preprocces_view = s1_preprocces.map(helper.lin_to_db);
s1_view = s1.map(helper.lin_to_db);
visparam = {bands:[parameter.POLARIZATION],min: -25,max: 0} ;
}
else {
s1_preprocces_view = s1_preprocces;
s1_view = s1;
visparam = {bands:[parameter.POLARIZATION],min: 0,max: 0.2};
}
}
// Calcula o MRFDI
var MRFDI = s1_preprocces.map(function(image) {
return image.normalizedDifference(['VV', 'VH']).rename('MRFDI');
});
var addMRFDI = function (image) {
var MRFDI = image.expression('(VV - VH)/(VV + VH)', {
'VV' : image.select('VV'),
'VH' : image.select('VH'),
}).float();
return image.addBands(MRFDI.rename('MRFDI'));
};
var MRFDI = s1_preprocces.map(addMRFDI)
.select('MRFDI');
// Calcula o RVI
var RVI = s1_preprocces.map(function(image) {
return image.normalizedDifference(['VV', 'VH']).rename('RVI');
});
var addRVI = function (image) {
var RVI = image.expression('(4*VH)/(VV + VH)', {
'VV' : image.select('VV'),
'VH' : image.select('VH'),
}).float();
return image.addBands(RVI.rename('RVI'));
};
var RVI = s1_preprocces.map(addRVI)
.select('RVI');
Map.centerObject(parameter.GEOMETRY, 12);
Map.addLayer(s1_view.first(), visparam, 'First image in the input S1 collection', true);
Map.addLayer(s1_preprocces_view.first(), visparam, 'First image in the processed S1 collection', true);
//---------------------------------------------------------------------------//
// EXPORT
//---------------------------------------------------------------------------//
//Convert format for export
if (parameter.FORMAT=='DB'){
s1_preprocces = s1_preprocces.map(helper.lin_to_db);
}
//Save processed collection to asset
if(parameter.SAVE_ASSETS) {
helper.Download.ImageCollection.toAsset(s1_preprocces, '',
{scale: 10,
region: s1_preprocces.geometry(),
type: 'float'});
}
print('Quantidade de imagens s1_preprocces:',s1_preprocces.size());
// Define an image collection time series to chart, MODIS vegetation indices
// in this case.
var imgCol = s1_preprocces
.select(['VV', 'VH']);
//=================================================================================//
//mann-kendall
var coll = s1_preprocces.map(function(image) {
return image.select().addBands(image.normalizedDifference(['VH', 'VV']));
})
.filter(ee.Filter.calendarRange(8, 9, 'month'));
Map.addLayer(coll, {}, 'coll');
var afterFilter = ee.Filter.lessThan({
leftField: 'system:time_start',
rightField: 'system:time_start'
});
var joined = ee.ImageCollection(ee.Join.saveAll('after').apply({
primary: coll,
secondary: coll,
condition: afterFilter
}));
var sign = function(i, j) { // i and j are images
return ee.Image(j).neq(i) // Zero case
.multiply(ee.Image(j).subtract(i).clamp(-1, 1)).int();
};
var kendall = ee.ImageCollection(joined.map(function(current) {
var afterCollection = ee.ImageCollection.fromImages(current.get('after'));
return afterCollection.map(function(image) {
// The unmask is to prevent accumulation of masked pixels that
// result from the undefined case of when either current or image
// is masked. It won't affect the sum, since it's unmasked to zero.
return ee.Image(sign(current, image)).unmask(0);
});
// Set parallelScale to avoid User memory limit exceeded.
}).flatten()).reduce('sum', 2);
var palette_sens = {min: -0.001, max: 0.001, palette: [
'red', 'white', 'green']};
var palette = ['red', 'white', 'green'];
// Stretch this as necessary.g
Map.addLayer(kendall, {palette: palette}, 'kendall');
var slope = function(i, j) { // i and j are images
return ee.Image(j).subtract(i)
.divide(ee.Image(j).date().difference(ee.Image(i).date(), 'days'))
.rename('slope')
.float();
};
var slopes = ee.ImageCollection(joined.map(function(current) {
var afterCollection = ee.ImageCollection.fromImages(current.get('after'));
return afterCollection.map(function(image) {
return ee.Image(slope(current, image));
});
}).flatten());
var sensSlope = slopes.reduce(ee.Reducer.median(), 2); // Set parallelScale.
Map.addLayer(sensSlope, palette_sens, 'sensSlope');
var epochDate = ee.Date('1970-01-01');
var sensIntercept = coll.map(function(image) {
var epochDays = image.date().difference(epochDate, 'days').float();
return image.subtract(sensSlope.multiply(epochDays)).float();
}).reduce(ee.Reducer.median(), 2);
Map.addLayer(sensIntercept, {}, 'sensIntercept');
Map.addLayer(table, {color: 'blue'});
I hope to resolve this impasse without changing the adopted time interval and reducing the size of the study area.

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?

How do I update data in a SmoothieChart without spamming the the second value in TimeSeries?

I want to build some kind of stock trading website using JSON
function getJSON(_url, _type) {
var request = new XMLHttpRequest();
request.open("GET", _url, true);
request.onload = function () {
if (request.status == 200 && request.readyState == 4) {
Callback(JSON.parse(request.responseText), _type);
} else
error("reach");
};
request.send(null);
}
and a callback function to get data.
function Callback(_data, _type) {
switch (_type) {
case 1.1:
initAktien(_data);
break;
case 1.2:
updateAktien(_data);
break;
}
}
In order to visualize the stocks I'm using SmoothieChart.
var lines = [];
var smoothie = new SmoothieChart({
tooltip: true, millisPerPixel: 50, minValueScale: 0,
grid: {fillStyle: '#99d6ff', strokeStyle: '#6c7d82', verticalSections: 8, borderVisible: false},
labels: {disabled: true, fontSize: 9}, minValue: 0, horizontalLines: [{color: '#000000', lineWidth: 1, value: 0}, {color: '#4d0f00', lineWidth: 2, value: 100}]
});
smoothie.streamTo(document.getElementById("aktien-grafik"), 500);
A little heads up in case you're wondering: "Aktien" means stocks, "preis" means price, and "anzahlVerfügbar" means available amount. I got this code from someone else and I'm supposed to "fix" it. That's why it's partially in German.
function initAktien(_data) {
var stocks = document.getElementById("aktien");
var amount = document.getElementById("amount");
for (var i = 0; i <= _data.length - 1; i++) {
var stockoption = document.createElement("option");
stockoption.innerHTML = _data[i].name;
stocks.appendChild(stockoption);
}
for (var j = 1; j <= 5; j++) {
var amountoption = document.createElement("option");
amountoption.innerHTML = j;
amount.appendChild(amountoption);
}
}
function updateAktien(_data) {
var select = document.getElementById("aktien").selectedIndex;
document.getElementById("kurs").innerHTML = _data[select].preis;
document.getElementById("anz").innerHTML = _data[select].anzahlVerfuegbar;
//spam is because of here
lines.push(new TimeSeries());
lines[select].append(new Date().getTime(), _data[select].preis);
smoothie.addTimeSeries(lines[select], {lineWidth: 2, strokeStyle: "#000000"});
}
I can render the graph just fine and I even get an overlay displaying the timestamp and the and the price and the time. Unfortunately it spams the price in the overlay which slows the site down quite fast. Removing the overlay doesn't solve the problem since the price is appended nonstop
somewhere at the point I marked. I don't know how to keep the data updating and the chart drawing without spamming that value.
I don't think it's the best solution, but it works. It's somewhat redundant code.
function initAktien(_data) {
var stocks = getID("aktien");
var amount = getID("amount");
for (var i = 0; i <= _data.length - 1; i++) {
var stockoption = document.createElement("option");
stockoption.innerHTML = _data[i].name;
stocks.appendChild(stockoption);
lines.push(new TimeSeries());
lines[i].append(new Date().getTime(), _data[i].preis.toFixed(2));
smoothie.addTimeSeries(lines[i], {lineWidth: 2, strokeStyle: "#000000"});
}
}
function updateAktien(_data) {
var select = getID("aktien").selectedIndex;
getID("kurs").innerHTML = _data[select].preis.toFixed(2);
getID("anz").innerHTML = _data[select].anzahlVerfuegbar;
//Grafik update
lines[select].append(new Date().getTime(), _data[select].preis.toFixed(2));
}

Using array index/variables in Animated Google Barchart Labels

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});

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