Need to access data in JSON.stringify object - javascript

The background for this question is I'm trying to access the selected cell from addListener in google visualization calendar. I could print the selected cell using JSON.stringify(chart.getSelection());. It prints as [{"date":1468195200000,"row":0}].
My problem is to access this date object. I tried to access it as
var obj=JSON.stringify(chart.getSelection());
console.log('selected value '+obj.date);
But it displays as Undefined. When I print the obj it displays as [object, object]
If you need more information please let me know. Any suggestion would be appreciated.

JSON.stringify() serializes a data object into a string. Just access the object directly.
var data = chart.getSelection()[0]; // assuming there is only ever one item in the selection array.
console.log(data.date)

Try this:
var data = [{"date":1468195200000,"row":0}]
var rw = data[0].row;
var dt = new Date(data[0].date);
console.log(rw);
console.log(dt);

careful when accessing the first array element directly when listening for the 'select' event
chart.getSelection()[0]
the 'select' event is fired, both when a selection is made, AND removed
so the above line will fail when the selection is removed
check the length before accessing...
selection = chart.getSelection();
// check selection length
if (selection.length > 0) {
console.log(selection[0].date);
} else {
console.log('selection removed');
}
see following working snippet, select a date, then select again to remove the selection...
google.charts.load('current', {
callback: function () {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'date', id: 'Date' });
dataTable.addColumn({ type: 'number', id :'Score' });
dataTable.addRows([
[ new Date(2016, 3, 13), 101 ],
[ new Date(2016, 3, 14), 102 ],
[ new Date(2016, 3, 15), 103 ],
[ new Date(2016, 3, 16), 104 ],
[ new Date(2016, 3, 17), 105 ]
]);
var chart = new google.visualization.Calendar(document.getElementById('chart_div'));
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getSelection();
// check selection length
if (selection.length > 0) {
console.log(selection[0].date);
} else {
console.log('selection removed');
}
});
chart.draw(dataTable);
},
packages:["calendar"]
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

This is an array of objects however there is only one object in this array (or so I think) so what you should do is console.log(obj[0].date); instead!

Related

GoogleCharts - Data column(s) for axis #0 cannot be of type string

I'm building a web app using ExtJS, and I have a Google Chart that displays the number of days it takes for a task to be completed, along with the count for those days. The aim is to easily see if the tasks are being done within a reasonable amount of time, or if a lot of the task are completed at a much longer time period.
I can fetch the data with no problems, and I convert the raw data to something that Google Charts can process using a function:
var output_data= "";
var output_data_array = [];
var data_count = data.length;
google.charts.load('current', {'packages':['corechart', 'bar']});
var header = "[\"Days\", \"Count\", { role: \"style\" } ],";
output_data_array.push(["Days, type: 'string'", "Count, type: 'number'", "{role: \"style\"}"]);
for(var i = 0 ; i < data_count ; i++){
var data_entry = data[i];
var number_of_days = data_entry.days;
var count = parseFloat(data_entry.count);
var color;
if(number_of_days < limit){
color = 'green';
}
else{
color = 'red';
}
output_data_array.push([number_of_days, count, color]);
}
var output_data_table = google.visualization.arrayToDataTable([
output_data_array
], false);
return output_data_table;
The function above generates my data array, which includes a data header before the actual data. I call this function in this function below:
var graph_data = this.convertData_forGoogleCharts(analytics_data_array, 15);
google.charts.load('current', {'packages':['corechart', 'bar']});
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var view = new google.visualization.DataView(graph_data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2]);
var options = {
title: "Test Chart",
width: width,
height: height,
bar: {groupWidth: "95%"},
legend: { position: "none" },
};
var chart = new google.visualization.ColumnChart(document.getElementById("myChartPanel"));
chart.draw(view, options);
}
However, after I ran this, I got the following error:
Data column(s) for axis #0 cannot be of type string
Which is odd because I added in the a type field in the column header. I'm also not sure if I can do addColumn in my arrayToDataTable like how it would go for DataTable.
I think the problem is with the following statement...
var output_data_table = google.visualization.arrayToDataTable([
output_data_array
], false);
output_data_array is already defined as an array,
so no need to wrap in another array.
try as follows...
var output_data_table = google.visualization.arrayToDataTable(output_data_array, false);
UPDATE
the new error resulted from the column headings.
here, object notation should be used to define the type.
instead, strings are being passed in the following statement.
output_data_array.push(["Days, type: 'string'", "Count, type: 'number'", "{role: \"style\"}"]);
and since object notation is not used,
the method does not recognize the style role,
and tries to use a string value for series data,
which results in error.
using the data table constructor is fine,
but if you want to correct arrayToDataTable,
change to the following...
output_data_array.push(["Days", "Count", {role: "style", type: "string"}]);
or...
output_data_array.push([
{label: "Days", type: "string"},
{label: "Count", type: "number"},
{role: "style", type: "string"}
]);
I followed WhiteHat's answer above, but I got a new error:
All series on a given axis must be of the same data type.
Not sure if there's anything wrong with my data, I did a log of my array and I had:
The data looks uniform to me. I'm not sure how to go about this, so I tried a DataTable instead, as I saw a DataTable with a style header. I re-wrote my data converter function as such:
var data_table = new google.visualization.DataTable();
data_table.addColumn({type: 'string', label: 'Number of Days'});
data_table.addColumn({type: 'number', label: 'Count'});
data_table.addColumn({type: 'string', role: 'style'});
for(var i = 0 ; i < data_count ; i++){
var data_entry = data[i];
var number_of_days = data_entry.days;
var count = parseFloat(data_entry.count);
var color;
if(number_of_days < tat_limit){
color = 'green';
}
else{
color = 'red';
}
data_table.addRow([number_of_days, count, color]);
}
output_data = header + output_data;
return data_table;
And then in the main function, it's being used as:
function drawChart() {
var graph_data = this.convertData_forGoogleCharts(analytics_data_array, 15);
var view = new google.visualization.DataView(graph_data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2]);
var options = {
title: "Test Chart",
width: width,
height: height,
bar: {groupWidth: "95%"},
legend: { position: "none" },
};
var chart = new google.visualization.ColumnChart(document.getElementById("myChartPanel"));
chart.draw(view, options);
}
This one worked like a charm, but I'm still open to revisiting the arrayToDataTable solution.

google chart with multiple dates

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>

Create date histogram chart with google histogram

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'],
},
};

enable lables for each cell in bar chart

I am trying to set each bar chart cell with lables of A, B and C for all my data to be shown on chart. I tried with data.addColumn('string', 'Alphabets'); but it is not working out.
It shall be easy but i am missing something.
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
// Create the data table.
var data = new google.visualization.DataTable();
var raw_data = [
['A', 40],
['B', 17],
['C', 7]
];
data.addColumn('string', 'Columns');
for (var i = 0; i < raw_data.length; ++i) {
data.addColumn('number', raw_data[i][0]);
}
data.addRows(1);
data.setValue(0, 0, 'row');
for (var i = 0; i < raw_data.length; ++i) {
data.setValue(0, i + 1, raw_data[i][1]);
}
// Set chart options
var options = {'title':'Megafon 27/10 2011',
'width':1300,
'height':600,
'colors' : ['red', 'blue', 'green']
};
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
You are not formatting your data correctly.
Series names are in separate columns (each column will add a new color to the chart, and a new item to the legend).
Value labels (the names of the X-axis categories) are in the first column of each row. You are doing them backwards, therefore there are no axis labels.
For instance, this code:
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['Label', 'Data'],
['A', 10],
['B', 20],
['C', 40],
['D', 80]
]);
// Create and draw the visualization.
new google.visualization.ColumnChart(document.getElementById('visualization')).
draw(data,{});
}
Creates this graph:
However, you want to have a different color for each series (which is bad visualization practice). To do that you need to have 4 different columns to get 4 different colors.
To do this you need to reformat your data as follows:
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['Label', 'Color 1', 'Color 2', 'Color 3', 'Color 4'],
['A', 10, null, null, null],
['B', null, 20, null, null],
['C', null, null, 40, null],
['D', null, null, null, 80]
]);
// Create and draw the visualization.
new google.visualization.ColumnChart(document.getElementById('visualization')).
draw(data,{series: [{color: 'red'},{color: 'orange'},{color: 'yellow'},{color: 'green'}]});
}
This comes out like this:
The issue then is that you have 4 different series in the legend, although they only represent one type of data (and this is why it is bad visualization practice!).
You also get a bit of an ugly looking graph, but that can be fixed with setting the options to isStacked: true.
At any rate, I'd just keep the data as it is in your array, and not fiddle with color. But your mileage may vary.

Annotated Timeline Flickers and Re-Zooms

I have an Annotated Timeline that I would like to update in realtime (similar to how Google Finance does it). However, I am having trouble getting the chart to not flicker and not re-zoom when data is added.
I couldn't get the code to work in JSFiddle (I think because annotated timeline is flash based?) but here is some basic code that you can plug in to Google's Visualization Playground. You can see a saved example here but unfortunately can't modify the code, you'll have to go to the playground to do that.
function drawVisualization() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'My Data');
data.addRows([
[new Date(2009, 1 ,1), 30000],
[new Date(2009, 1 ,2), 14045],
[new Date(2009, 1 ,3), 55022],
[new Date(2009, 1 ,4), 75284],
[new Date(2009, 1 ,5), 41476],
[new Date(2009, 1 ,6), 33322]
]);
var annotatedtimeline = new google.visualization.AnnotatedTimeLine(
document.getElementById('visualization'));
var options = {
'allowRedraw' : true ,
'displayAnnotations' : true,
'zoomStartTime': new Date(2009, 1 ,2),
'zoomEndTime': new Date(2009, 1 ,10)
};
annotatedtimeline.draw(data, options);
// let's add some more data in 3 seconds
setTimeout(function() {
again(annotatedtimeline, data, options);
}, 3000);
}
function again(timeline, data, options) {
data.addRow([new Date(2009, 1 ,7), 30000]);
timeline.draw(data, options);
}
google.setOnLoadCallback(drawVisualization);​
What's weird is that I get pretty different flicker behavior depending on how I set displayAnnotations
displayAnnotations = true : Chart flickers but does not re-zoom
displayAnnotations = false : No chart flicker but it re-zooms to the new data (try it on the playground to see)
Setting allowRedraw = false causes the chart to flicker regardless. Any idea how to get no flicker and no re-zoom?
From the docs:
allowRedraw must be true
displayAnnotations must be false (that is, you cannot show annotations)
That's your problem.

Categories