I have multiple collections of data I want to display in a single google chart. Each series is a collection of CPM's with a date:
for instance:
series A[
'2016-09-01' => 2.08023,
'2016-09-04' => 2.01123
];
series B[
'2016-09-01' => 1.99324,
'2016-09-02' => 2.00112
];
Note that the dates in the two series are not the same. I want to draw these two graphs in a single google graph. How should I format the data rows (if this is possible at all).
I have made a JSFiddle with what I thought would be a way to go, but adding a null in the data table doesn't work, I get two dots for the first series where I'm expecting a line. How can I make google chart draw the line instead of the dots?
in the fiddle, the data is setup correctly
however, since there is a null value is Series A due to the different dates
need to use configuration option interpolateNulls: true
from the documentation...
interpolateNulls
Whether to guess the value of missing points. If true, it will guess the value of any missing data based on neighboring points. If false, it will leave a break in the line at the unknown point.
see following working snippet...
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'X');
data.addColumn('number', 'series a');
data.addColumn('number', 'series b')
data.addRows([
[new Date( 1472688000000 ), 2.08023, 1.99324],
[new Date( 1472774400000 ), null, 2.00112],
[new Date( 1472947200000 ), 2.01123, null]
]);
var options = {
interpolateNulls: true
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.LineChart(container);
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
Related
Basically my JavaScript receives data like this: year = {month1, ...., month12}. Each month stores data for 3 graphs. month1 = {graph1_data,..., graph3_data}
I wish to draw charts for all of them using Google Charts. So that makes it 12 * 3 = 36 charts. I have written the following code logic. But it fails to work.
for ( month in year )
{
google.charts.setOnLoadCallback(function(){
// draw graph1
var data = new google.visualization.DataTable();
// code
// code
// data.addColumn()
// data.addColumn()
data.addRows(data_table);
var options = {title: month, height:100};
var chart = new google.visualization.ColumnChart(
document.querySelector('#'+month+' .graph1'));
chart.draw(data, options);
});
google.charts.setOnLoadCallback(function(){
// draw graph2
google.charts.setOnLoadCallback(function(){
var data = new google.visualization.DataTable();
// code
// code
// data.addColumn()
// data.addColumn()
data.addRows(data_table);
var options = {title: month, height:100};
var chart = new google.visualization.ColumnChart(
document.querySelector('#'+month+' .graph2'));
chart.draw(data, options);
});
google.charts.setOnLoadCallback(function(){
// draw graph3
google.charts.setOnLoadCallback(function(){
var data = new google.visualization.DataTable();
// code
// code
// data.addColumn()
// data.addColumn()
data.addRows(data_table);
var options = {title: month, height:100};
var chart = new google.visualization.ColumnChart(
document.querySelector('#'+month+' .graph3));
chart.draw(data, options);
});
}
It draws 3 charts for month12. Now why does this happen? Does this mean I must call setOnLoadCallback 36 times? Isn't there any alternative way?
Edit
It looks like once Google Chart API is loaded, the callbacks in all the setOnLoadCallbacks is called once. Which probably explains why I get only one graph, since at the time of execution of the function, the loop would have stopped at month12.
So I finally figured out what is going wrong here.
You are only registering a callback with the Google Charts API, not actually calling it in your for(month in year) loop. The callback is called (as you can guess) when relevant resources have finished loading and the Charts API can start drawing. Unfortunately your globally defined var month is now equal to month12. This is the state after your for loop completes:
month = year.month12;
callback_for_graph_1 = <anonymous function 1>
callback_for_graph_2 = <anonymous function 2>
callback_for_graph_3 = <anonymous function 3>
As you can imagine, now when the callbacks, they are each called only once, with month = year.month12. Hence the three graphs, all with month12 data.
So how do you fix this? Here's how:
Initialise three callbacks only once. No need to keep them anonymous.
google.charts.setOnLoadCallback(callbackForGraph1);
google.charts.setOnLoadCallback(callbackForGraph2);
google.charts.setOnLoadCallback(callbackForGraph3);
function callbackForGraph1 {
// do your thing
}
function callbackForGraph2 {
// do your thing
}
function callbackForGraph3 {
// do your thing
}
Iterate over all the months inside each callback, and create a new Chart instance for each month. Also draw it.
function callbackForGraph1() {
for(month in year) {
// draw graph1
var data = new google.visualization.DataTable();
// code
// code
// data.addColumn()
// data.addColumn()
data.addRows(data_table);
var options = {title: month, height:100};
// this is your Chart instance ->
var chart = new google.visualization.ColumnChart(document.querySelector('#'+month+' .graph1'));
// draw it!
chart.draw(data, options);
}
}
Profit?
You might also want to store each Chart instance in a array or dictionary style object. That way you can later make changes to your plots, instead of having to regenerate and replace them.
OLD ANSWER: This happens because you draw the chart for graph_1 in the same HTML element for each month. So the chart for graph_1[month2] overwrites the chart for graph_1[month1]. Since graph_1[month12] is the last data to be processed, you get the chart for month12. Likewise occurs for graph_2 and graph_3.
What you can try is appending a new svg or vml element to your HTML document every time the plotting callback is called. This can be done from within the callback itself. That way you get a new chart for every month for every graph.
I have a simple Google chart:
google.setOnLoadCallback(drawVisualization);
function drawVisualization() {
var data = [
[new Date("Month"), "Shipments"],
[new Date("2015-05-01T04:00:00.000Z"), 51666],
[new Date("2014-11-01T04:00:00.000Z"), 53783],
[new Date("2015-02-01T05:00:00.000Z"), 63454],
[new Date("2014-12-01T05:00:00.000Z"), 63722],
[new Date("2015-03-01T05:00:00.000Z"), 63836],
[new Date("2015-09-01T04:00:00.000Z"), 63884],
[new Date("2015-04-01T04:00:00.000Z"), 68869],
[new Date("2015-08-01T04:00:00.000Z"), 68954],
[new Date("2015-01-01T05:00:00.000Z"), 72110],
[new Date("2015-06-01T04:00:00.000Z"), 77942],
[new Date("2015-07-01T04:00:00.000Z"), 86856],
[new Date("2014-10-01T04:00:00.000Z"), 92168]
];
// Some raw data (not necessarily accurate)
var data = google.visualization.arrayToDataTable(data);
var chart = new google.visualization.ColumnChart(
document.getElementById('chart_div')
);
chart.draw(data);
}
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['corechart']}]}"></script>
<div id="chart_div" style="width: 900px; height: 500px;"></div>
You can also see this in action at http://codepen.io/chug187/pen/GpQzNg.
Why does it automatically sort by the dates in the data? I want to have the chart's columns appear in ascending order of the number of shipments, yet Google Charts is sorting the data by date. There doesn't appear to be any options for either the DataTable, DataView or ComboChart classes to ensure that the data appears as it exists in the data array.
Since the values on X-axis are date, it does not consider it discrete (like strings) and treat as continuous data and hence sorts them.
You can make them string, and apply sort them based on the numerical data by
[String(new Date("2015-05-01T04:00:00.000Z")), 51666],
data.sort([{column: 1}, {column: 0}]);
You can find the codepen working as per your need here
You can also refer google charts documentation here
How to create Google Histogram Chart [1] that works with dates?
I've placed sample code (with working number and non-working date examples): http://jsfiddle.net/Qquse/417/ and code below [2]
[1] https://developers.google.com/chart/interactive/docs/gallery/histogram
[2]
google.load("visualization", "1", {
packages: ["corechart"]
});
google.setOnLoadCallback(drawChart);
function str_to_utcdate(d) {
return new Date(d.substr(0, 4), d.substr(5, 2) - 1, d.substr(9, 2));
}
function drawChart() {
var data = google.visualization.arrayToDataTable([
['item', 'date'],
['a', str_to_utcdate('2001-07-01')],
['b', str_to_utcdate('2001-07-01')],
['c', str_to_utcdate('2001-07-01')], ]);
var chart = new google.visualization.Histogram(document.getElementById('chart_div1'));
chart.draw(data);
var data = google.visualization.arrayToDataTable([
['item', 'date'],
['a', 10],
['b', 20],
['c', 30], ]);
var chart = new google.visualization.Histogram(document.getElementById('chart_div2'));
chart.draw(data);
}
5 years now and Histograms still don't support dates. Since I ain't got time and I need my stuff done, I made a workaround (so ugly it hurts) but works.
First, I defined a format just to put a keyword at the start of each label. In my case, since I have only one chart in my page, I just used the keyword 'date'.
const keyword = 'date';
const options = {
// ...
hAxis: {
format: `'${keyword}'#`
},
}
If you have multiple charts in your page and you want them to behave differently, you might want to define different keyword to each one.
Now, using query selector, I selected all the label elements that are of my interest
let labels = Array.from(document.querySelectorAll('#chart svg g:nth-of-type(3) g:nth-of-type(3) g text'));
In my case, my chart was set in a DIV with id 'chart'. If you're using any other id, just replace #chart with your id;
Then I will filter only the labels which start with my keyword 'date'
labels = labels.filter(g => g.innerHTML.startsWith(keyword));
With that, I replace the innerHTML of each element to the date format I wish.
labels.forEach(g => {
const date = new Date(+g.substring(keyword.length));
// you can apply any format method you wish
// .toLocaleDateString()
g.innerHTML = date.toLocaleDateString();
// moment.js
g.innerHTML = moment(date).format('DD/MM/YYYY HH:MM');
});
Also, I'm using interactive charts, so the labels refresh on each user interaction. Therefore, I put everything inside an interval, and the final result is as follows:
const keyword = 'date';
const options = {
// ...
hAxis: {
format: `'${keyword}'#`
},
}
// ... chart setup
setInterval(() => {
let labels = Array.from(document.querySelectorAll('#chart svg g:nth-of-type(3) g:nth-of-type(3) g text'));
labels = labels.filter(g => g.innerHTML.startsWith(keyword));
labels.forEach(g => {
const date = new Date(+g.substring(keyword.length));
g.innerHTML = date.toLocaleDateString();
});
}, 100);
Use this answer with caution. Using query selectors to modify third party generated content is very unsafe because it relies on the hope that the third-party developers won't modify the way the content is generated.
Try out this column chart:
public histogramChart: GoogleChartInterface = {
chartType: 'ColumnChart',
dataTable: [
['Date', 'Number'],
[new Date(2015, 1, 1), 5],
[new Date(2015, 1, 2), 5.1],
[new Date(2015, 1, 3), 6.2],
[new Date(2015, 1, 4), 7]
];,
//opt_firstRowIsData: true,
options: {
title: 'Shooting history',
legend: { position: 'none' },
colors: ['#4285F4'],
},
};
I have a csv file that looks like that:
week,value1,value2
1,2,3
2,7,9
I would like to plot a stacked graph of it using google chart (week being my x (horizontal) values and values1 and values2 being the two set of y's). Unfortunately, I didn't find any easy way to do so. That probably relates to me being a complete noob in js.
Is there any simple way to do that?
The jquery-csv library provides the ability to translate a string of csv into an array to be used by google.visualization.arrayToDataTable() (their example here). To make this work, add jquery.csv.js to your server (in the example below I assume it is in the same folder as your HTML) and link to it in your <head>. The following is a simple script you can add to your <head> to get started. I assume a scatter chart, but this process works for any of the charts here. You will also need a <div> with id="chart" for this to work.
// load the visualization library from Google and set a listener
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
// this has to be a global function
function drawChart() {
// grab the CSV
$.get("example.csv", function(csvString) {
// transform the CSV string into a 2-dimensional array
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
// this new DataTable object holds all the data
var data = new google.visualization.arrayToDataTable(arrayData);
// this view can select a subset of the data at a time
var view = new google.visualization.DataView(data);
view.setColumns([0,1]);
// set chart options
var options = {
title: "A Chart from a CSV!",
hAxis: {title: data.getColumnLabel(0), minValue: data.getColumnRange(0).min, maxValue: data.getColumnRange(0).max},
vAxis: {title: data.getColumnLabel(1), minValue: data.getColumnRange(1).min, maxValue: data.getColumnRange(1).max},
legend: 'none'
};
// create the chart object and draw it
var chart = new google.visualization.ScatterChart(document.getElementById('chart'));
chart.draw(view, options);
});
}
I have been searching for a while, and found the solution on a Google group discussion.
https://groups.google.com/forum/#!topic/google-visualization-api/cnXYDr411tQ
I have tried it, and it works!
In this case, we have to specify the header types of our csv file.
var queryOptions = {
csvColumns: ['number', 'number', 'number' /* Or whatever the columns in the CSV file are */],
csvHasHeader: true /* This should be false if your CSV file doesn't have a header */
}
/* csvUrl is the path to your csv */
var query = new google.visualization.Query(csvUrl, queryOptions);
query.send(handleQueryResponse);
function handleQueryResponse(response) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var data = response.getDataTable();
var chart = new google.visualization.ColumnChart(document.getElementById('your div'));
// Draw your chart with the data table here.
// chart.draw(view, queryOptions);
}
What server side scripting language are you working in (php, asp)?
One option could be to import the data from a spreadsheet saved in Google Drive, see here for a PHP based example of saving and extracting data from Google Docs. This would then enable you to update the spreadsheet and the chart would automatically plot the new data.
I have taken a look at the other answers at SO, but none caters to my need.
Here is the documentation which tells how to plot dates on charts. Following is one of the sample json objects:
datetime: "2012-07-07"
hours: "0.6"
shop: "WalMart"
name: "Andrew"
__proto__: Object
I use the following code to add rows and columns:
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Hours');
$.each(hour_logs, function(key, value){// hour_logs is the collection of json objects, the sample is shown above.
ymd = value.datetime.split("-");
var dt = new Date(parseInt(ymd[0]), parseInt(ymd[1]), parseInt(ymd[2]));
data.addRow(dt, parseInt(value.hours));
});
console.log(data);
var options = {
title: 'Daily Logs',
displayAnnotations: true,
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
But i get an error, uncaught Error: Not an array. How to fix it.
You are not providing an array when adding a row.
Should be:
data.addRow([dt, parseInt(value.hours)]);
instead of:
data.addRow(dt, parseInt(value.hours));