Related
I have a multi-chart Google Visualization script (1 column chart and 2 line charts). The charts are working/displaying correctly except for the var Options code. The most important part of the Options section is being able to change the column/line color. So I tried changing it using the role: 'style'} alternative, but it didn't work either.
Please see below code for the 3 charts. I'm new to Google Visualization, so any feedback/help is much appreciated!
google.charts.load('current', {
packages: ['corechart', 'controls']
}).then(function () {
// Chart data
var data = [];
data[0] = google.visualization.arrayToDataTable ([["Date","Sessions", {role: 'style'}],
<?php
for($a = 0; $a < 7; $a++)
{
echo "['".$date[$a]."', ".$sessions[$a].", 'fill-color: #76A7FA'],";
}
?>
]);
data[1] = google.visualization.arrayToDataTable ([["Date","Sessions"],
<?php
for($a = 0; $a < 31; $a++)
{
echo "['".$date[$a]."', ".$sessions[$a]."],";
}
?>
]);
data[2] = google.visualization.arrayToDataTable ([["Date","Sessions"],
<?php
for($a = 0; $a < count($query); $a++)
{
echo "['".$date[$a]."', ".$sessions[$a]."],";
}
?>
]);
var current = 0;
var current_chart = 0;
// Create and draw the visualization
var chart = [];
chart[0] = new google.visualization.ColumnChart(document.getElementById('sessions_chart'));
chart[1] = new google.visualization.LineChart(document.getElementById('sessions_chart'));
function drawChart() {
// Disabling the buttons while the chart is drawing.
document.getElementById('week_btn').disabled = true;
document.getElementById('month_btn').disabled = true;
document.getElementById('all_btn').disabled = true;
google.visualization.events.addListener(chart, 'ready', function() {
// Enable the buttons after the chart has been drawn
document.getElementById('week_btn').disabled = false;
document.getElementById('month_btn').disabled = false;
document.getElementById('all_btn').disabled = false;
});
var view = new google.visualization.DataView(data[current]);
var options = {
title: 'Number of Sessions',
vAxis: {title: "# of Sessions", minValue:0},
hAxis: {format: 'MMM d, y'},
colors: 'lightgreen'
};
// Convert first column to date format
view.setColumns([{
calc: function (dt, row) {
return new Date(dt.getValue(row, 0));
},
label: data[current].getColumnLabel(0),
type: 'date'
}, 1]);
chart[current_chart].draw(view, data[current], options);
}
drawChart();
// google.charts.setOnLoadCallback(drawChart);
document.getElementById('week_btn').addEventListener("click", displayWeek);
function displayWeek() {
current = 0;
current_chart = 0;
drawChart();
}
document.getElementById('month_btn').addEventListener("click", displayMonth);
function displayMonth() {
current = 1;
current_chart = 1;
drawChart();
}
document.getElementById('all_btn').addEventListener("click", displayAll);
function displayAll() {
current = 2;
current_chart = 1;
drawChart();
}
});
the colors option should be an array...
colors: ['lightgreen']
as for the style role, try providing only the color...
echo "['".$date[$a]."', ".$sessions[$a].", '#76A7FA'],";
AND
highly recommend NOT building json manually in php from a string.
instead, separate the php from the html in two different files.
build the data in php and return the encoded json to the page.
then use ajax to call the php page and get the encoded json.
then draw the chart.
here are some examples...
How to automatically update Google Gauge
JSON $ajax problems
I am using google charts timeline to plot the data below using google charts timeline.
[{"id":59291,"idJob":2,"idOperation":3,"start":0,"end":3,"machine":1}, {"id":59292,"idJob":2,"idOperation":2,"start":3,"end":7,"machine":1},{"id":59293,"idJob":1,"idOperation":1,"start":7,"end":8,"machine":1},{"id":59294,"idJob":2,"idOperation":1,"start":8,"end":11,"machine":1},{"id":59295,"idJob":1,"idOperation":2,"start":0,"end":1,"machine":2},{"id":59296,"idJob":2,"idOperation":5,"start":7,"end":14,"machine":3},{"id":59297,"idJob":1,"idOperation":4,"start":1,"end":10,"machine":4},{"id":59298,"idJob":1,"idOperation":3,"start":8,"end":21,"machine":5},{"id":59299,"idJob":2,"idOperation":6,"start":3,"end":10,"machine":6},{"id":59300,"idJob":2,"idOperation":4,"start":11,"end":14,"machine":6},{"id":59301,"idJob":2,"idOperation":9,"start":10,"end":13,"machine":7},{"id":59302,"idJob":1,"idOperation":6,"start":13,"end":14,"machine":7},{"id":59303,"idJob":2,"idOperation":8,"start":14,"end":16,"machine":7},{"id":59304,"idJob":2,"idOperation":7,"start":16,"end":21,"machine":7},{"id":59305,"idJob":1,"idOperation":5,"start":21,"end":23,"machine":7},{"id":59306,"idJob":1,"idOperation":9,"start":14,"end":17,"machine":8},{"id":59307,"idJob":2,"idOperation":12,"start":18,"end":21,"machine":8},{"id":59308,"idJob":2,"idOperation":10,"start":21,"end":26,"machine":8},{"id":59309,"idJob":1,"idOperation":8,"start":26,"end":28,"machine":8},{"id":59310,"idJob":2,"idOperation":11,"start":18,"end":24,"machine":9},{"id":59311,"idJob":1,"idOperation":7,"start":24,"end":27,"machine":9},{"id":59312,"idJob":2,"idOperation":14,"start":21,"end":25,"machine":10},{"id":59313,"idJob":2,"idOperation":13,"start":26,"end":28,"machine":10},{"id":59314,"idJob":2,"idOperation":15,"start":28,"end":28,"machine":10},{"id":59315,"idJob":1,"idOperation":10,"start":28,"end":29,"machine":10}]
I have n jobs and n_i operations. The operation name should be "id_job,id_operation" e.g., the operation 1 of job 1 equals "1,1".
Google chart timeline defines the color of the operation based on the name of the operation, so for all operations with the same name it will choose the same color. What I am trying to do to is to create the chart exactly (same colors for the same job) as Fig. 1, however, with the text anchor of each operation with its respective name. If I try to define the respective name for each operation I end up with the graph shown in Fig. 2.
Figure 1.
Figure 2.
My javascript code.
function timelineChart() {
$.ajax({
url : "operations",
dataType : "json",
success : function(result) {
google.charts.load('current', {
'packages' : [ 'timeline' ]
});
google.charts.setOnLoadCallback(function() {
drawChart2(result);
});
}
});
function drawChart2(result) {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Machine');
data.addColumn('string', 'Job');
data.addColumn('date', 'Start Date');
data.addColumn('date', 'End Date');
var dataArray = [];
$.each(result, function(i, obj) {
dataArray.push([ 'M' + obj.machine, getIdJob(obj) + "," + getIdOp(obj), new Date(obj.start * 1000), new Date(obj.end * 1000) ])
});
data.addRows(dataArray);
var options = {
timeline : {
groupByRowLabel : true,
showRowLabels : true,
showBarLabels : true
}
};
var chart = new google.visualization.Timeline(document.getElementById('chart_timeline'));
chart.draw(data, options);
}
}
function getIdJob(obj) {
if (obj.idJob == 0) {
return 'Unavailability';
} else {
return obj.idJob;
}
}
function getIdOp(obj) {
return obj.idOperation;
}
The code bellow may work for your case. You can define a map of colors and then use it to draw your operations. You have to use DataView and remove the category before drawing.
function drawChart2(result) {
var container = document.getElementById('chart_timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({type : 'string',id : 'Machine'});
dataTable.addColumn({type : 'string',id : 'Category'});
dataTable.addColumn({type : 'string',id : 'ID'});
dataTable.addColumn({type : 'date', id : 'Start'});
dataTable.addColumn({type : 'date', id : 'End'});
var colorMap = {};
var dataArray = [];
$.each(result, function(i, obj) {
colorMap['Category' + getIdJob(obj)] = randomColor();
dataArray.push(
[ 'M' + obj.machine, 'Category'+getIdJob(obj), getIdJob(obj) + "," + getIdOp(obj), new Date(obj.start * 1000), new Date(obj.end * 1000) ])
});
dataTable.addRows(dataArray);
var colors = [];
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
colors.push(colorMap[dataTable.getValue(i, 1).toString()]);
}
var options = {
timeline : {
groupByRowLabel : true,
showRowLabels : true,
showBarLabels : true
},
colors : colors
};
console.log(dataTable);
// use a DataView to hide the category column from the Timeline
var view = new google.visualization.DataView(dataTable);
view.setColumns([ 0, 2, 3, 4 ]);
chart.draw(view, options);
}
We can define an extra column 'Category' and define a map with a color for each category. You can use the colors at the options and to avoid the error of extra column you can use DataView to hide the category column.
I have a problem to change number format in my google chart.
I checked stackoverflow topic and I found it : http://jsfiddle.net/h5ea6xqu/
My problem is simple, I want exactly the same thing, but it doesn't working.
I have "," instead space for my grouping symbol... If someone have the solution, it would be awesome.
my problem
My code :
function drawChart($id) {
var id=$id;
var kwexist = (id + "_kw_exist");
var kwexistvariable = $("#"+kwexist).html();
var kwled = (id + "_kw_led");
var kwledvariable = $("#"+kwled).html();
var data = google.visualization.arrayToDataTable([
['Element', 'Density', { role: 'style' }, { role: 'annotation' } ],
['Existant kWh', parseFloat(kwexistvariable), '#3B7CC9', parseFloat(kwexistvariable)],
['LED kWh', parseFloat(kwledvariable), '#3B7CC9' , parseFloat(kwledvariable)]
]);
var options = {
};
var numberFormat = new google.visualization.NumberFormat({
groupingSymbol: ' '
})
numberFormat.format(data, 1);
var chart_div = document.getElementById('chart_div_kw');
var chart = new google.visualization.ColumnChart(chart_div);
// Wait for the chart to finish drawing before calling the getImageURI() method.
google.visualization.events.addListener(chart, 'ready', function () {
chart_div.innerHTML = chart.getImageURI();
var testokok = chart.getImageURI();
console.log(chart_div.innerHTML);
});
chart.draw(data, options);
}
not sure i follow the question exactly
but if you want to format the number shown on the bar (annotation)
also format that column...
numberFormat.format(data, 3);
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart($id) {
var data = google.visualization.arrayToDataTable([
['Element', 'Density', { role: 'style' }, { role: 'annotation' } ],
['Existant kWh', parseFloat(10000), '#3B7CC9', parseFloat(10000)],
['LED kWh', parseFloat(15000), '#3B7CC9' , parseFloat(15000)]
]);
var options = {
};
var numberFormat = new google.visualization.NumberFormat({
groupingSymbol: ' '
});
numberFormat.format(data, 1);
numberFormat.format(data, 3);
var chart_div = document.getElementById('chart_div');
var chart = new google.visualization.ColumnChart(chart_div);
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
I'm trying to draw two charts using the Google Charts API. I set up my HTML like this:
<div id="page_views" data-title="{{ report['page_views']['title'] }}" data-labels="{{ report['page_views']['labels'] }}" data-rows="{{ report['page_views']['rows'] }}"></div>
<div id="event_views" data-title="{{ report['event_views']['title'] }}" data-labels="{{ report['event_views']['labels'] }}" data-rows="{{ report['event_views']['rows'] }}"></div>
where the data attributes are filled during template rendering. I then use the following javascript to attempt to draw my charts:
google.load('visualization', '1.0', {packages: ['line']});
google.setOnLoadCallback(drawCharts);
function drawPageViews() {
var data = new google.visualization.DataTable();
var page_views = document.getElementById("page_views");
var labels = eval(page_views.dataset.labels);
data.addColumn('number', "Day");
for(var i = 0; i < labels.length; i++) {
data.addColumn('number', labels[i]);
}
var rows = eval(page_views.dataset.rows);
data.addRows(rows);
var options = {
chart: {
title: page_views.dataset.title
},
width: 900,
height: 500
};
var chart = new google.charts.Line(document.getElementById('page_views'));
chart.draw(data, options);
}
function drawEventViews() {
var data = new google.visualization.DataTable();
var event_views = document.getElementById("event_views");
var labels = eval(event_views.dataset.labels);
data.addColumn('number', "Day");
for(var i = 0; i < labels.length; i++) {
data.addColumn('number', labels[i]);
}
var rows = eval(event_views.dataset.rows);
data.addRows(rows);
var options = {
chart: {
title: event_views.dataset.title
},
width: 900,
height: 500
};
var chart = new google.charts.Line(document.getElementById('event_views'));
chart.draw(data, options);
}
function drawCharts() {
drawPageViews();
drawEventViews();
}
The result that I get is that one of the charts is drawn while the other contains an SVG with an empty tag and nothing else inside. Which chart gets drawn is random. Commenting out either draw function makes the other single chart draw as expected.
It seems like there must be some sort of shared global state or variable but it looks to me like everything is defined in the different draw functions. When I look up similar questions people offer solutions which look very much like what I'm doing. What am I missing?
It seems this behavior is related with draw function, in particular it occurs once multiple charts is rendered on the page.
According to the documentation:
The draw() method is asynchronous: that is, it returns immediately,
but the instance that it returns might not be immediately available.
For rendering multiple charts on the page you could consider the following approach: render the next chart once the previous one is rendered, this is where ready event comes to the rescue.
Having said that the solution would be to replace:
function drawCharts() {
drawPageViews();
drawEventViews();
}
with
function drawCharts() {
drawPageViews(function(){
drawEventViews();
});
}
where
function drawPageViews(chartReady) {
//...
var chart = new google.charts.Line(document.getElementById('page_views'));
if (typeof chartReady !== 'undefined') google.visualization.events.addOneTimeListener(chart, 'ready', chartReady);
chart.draw(data, options);
}
and
function drawEventViews(chartReady) {
//...
var chart = new google.charts.Line(document.getElementById('event_views'));
if (typeof chartReady !== 'undefined') google.visualization.events.addOneTimeListener(chart, 'ready', chartReady);
chart.draw(data, options);
}
Working example
google.load('visualization', '1.0', { packages: ['line'] });
google.setOnLoadCallback(drawCharts);
function drawPageViews(chartReady) {
var data = new google.visualization.DataTable();
var page_views = document.getElementById("page_views");
var labels = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
data.addColumn('string', 'Day');
data.addColumn('number', 'PageViews');
var rows = new Array();
for (var i = 0; i < labels.length; i++) {
rows.push([labels[i], getRandomInt(0, 100)]);
}
data.addRows(rows);
var options = {
chart: {
title: 'Page views'
},
width: 900,
height: 500
};
var chart = new google.charts.Line(document.getElementById('page_views'));
if(typeof chartReady !== 'undefined') google.visualization.events.addOneTimeListener(chart, 'ready', chartReady);
chart.draw(data, options);
}
function drawEventViews(chartReady) {
var data = new google.visualization.DataTable();
var event_views = document.getElementById("event_views");
var labels = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
data.addColumn('string', 'Day');
data.addColumn('number', 'EventViews');
var rows = new Array();
for (var i = 0; i < labels.length; i++) {
rows.push([labels[i], getRandomInt(0, 100)]);
}
data.addRows(rows);
var options = {
chart: {
title: 'Event views'
},
width: 900,
height: 500
};
var chart = new google.charts.Line(document.getElementById('event_views'));
if(typeof chartReady !== 'undefined') google.visualization.events.addOneTimeListener(chart, 'ready', chartReady);
chart.draw(data, options);
}
function drawCharts() {
drawPageViews(function(){
drawEventViews();
});
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<div id="page_views"></div>
<div id="event_views"></div>
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});