How may I explicitly define the datatype of a Google Charts DataTable column after it has been created? - google-visualization

I am using jquery-csv toArrays function to populate a google visualization DataTable like this:
function drawChart() {
// Load the CSV file into a string
$.get("Book1.csv", function(csvString) {
// transform the CSV string into a 2-dimensional array
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
// Create new DataTable object from 2D array
var data = new google.visualization.arrayToDataTable(arrayData);
// Set which columns we will be using
var view = new google.visualization.DataView(data);
view.setColumns([0,1,5,9,13,17,21,25,29]);
...
The first column in the CSV file contains a list of times which are used as the horizontal axis for the chart.
Google visualization's arrayToDataTable function attempts to automatically determine the appropriate data type for each column but it fails with the first column assigning it the String type instead of the required TimeOfDay type.
I know I can determine a columns datatype when populating it manually like so:
var dt = new google.visualization.DataTable({
cols: [{id: 'time', label: 'Time', type: 'timeofday'},
{id: 'temp', label: 'Temperature', type: 'number'}],
...
But can I change a column's data type after it has already been populated by the arrayToDataTable function?
EDIT:
Here is a CSV file similar to those which I'm currently using.
When I change the column heading to object notation before creating the DataTable as suggested below and force it to TimeOfDay, the first column gets converted to a series of NaN:NaN:NaN.NaN. Here is a simplified example similar to the one in the suggested answer.
google.load('visualization', '1', {packages: ['controls', 'charteditor']});
google.setOnLoadCallback(drawChart);
function drawChart() {
// Load the CSV file into a string
$.get("Book1.csv", function(csvString) {
// transform the CSV string into a 2-dimensional array
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
// Create new DataTable object from 2D array
var data = new google.visualization.arrayToDataTable(arrayData);
// Show datatable in grid to see what is happening before the data type change
var chart1 = new google.visualization.Table(document.getElementById('chart_div0'));
chart1.draw(data);
// Here we explicitly define type of first column in table
arrayData[0][0] = {type: 'timeofday', label: arrayData[0][0]};
// Create new DataTable object from 2D array
var data = new google.visualization.arrayToDataTable(arrayData);
// Show datatable in grid to see what is happening after the data type change
var chart2 = new google.visualization.Table(document.getElementById('chart_div1'));
chart2.draw(data);
});
}
Thanks!

change the column heading to object notation before creating the DataTable
and use a DataView to convert the first column to 'timeofday'
google.charts.load('current', {
callback: function () {
csvString = 'TIME,TEMP0,HUM0\n12:00:04 AM,24.7,50\n12:01:05 AM,24.7,50';
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
var data = new google.visualization.arrayToDataTable(arrayData);
var columns = [];
for (var i = 0; i < data.getNumberOfColumns(); i++) {
columns.push(i);
}
var view = new google.visualization.DataView(data);
columns[0] = {
calc: function(dt, row) {
var thisDate = new Date('1/1/2016 ' + dt.getValue(row, 0));
return [thisDate.getHours(), thisDate.getMinutes(), thisDate.getSeconds(), thisDate.getMilliseconds()];
},
label: arrayData[0][0],
type: 'timeofday'
};
view.setColumns(columns);
var chart = new google.visualization.Table(document.getElementById('chart_div'));
chart.draw(view);
},
packages: ['corechart', 'table']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-csv/0.71/jquery.csv-0.71.min.js"></script>
<div id="chart_div"></div>

Related

Google charts error:every row given must be either null or an array

I am working on a website that is intended to show some basic Google charts. The data comes from a text file that i retrieve through Ajax. It's got a x, y value and an annotation field. The data looks like this:
[[-0.8, -0.47, "100-005-10"],
[-0.7, -0.46, "100-005-9"],
[-0.6, -0.45, "100-005-8"],
[-0.5, -0.44, "100-005-7"]]
Here's my code:
<script >
var xmlhttp = new XMLHttpRequest();
var array;
xmlhttp.onreadystatechange = function() {
array = this.responseText;
};
xmlhttp.open("GET", "array.array", true);
xmlhttp.send();
google.charts.load("current", {packages:["corechart"]});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable($.parseJSON(array), true)
data.addColumn('number', 'x');
data.addColumn('number', 'y');
data.addColumn({type: 'string', role: 'annotation'});
data.addRow(array);
var options = {
legend: 'none',
colors: ['#087037'],
selectionMode: 'single',
tooltip: {trigger: 'selection'},
pointSize: 12,
animation: {
duration: 200,
easing: 'inAndOut',
}
};
var chart = new google.visualization.ScatterChart(document.getElementById('animatedshapes_div'));
chart.draw(data, options);
}
</script>
When i run the code, i get this error message:
Error: If argument is given to addRow, it must be an array, or null
I just don't know how to transform the plain text from the ajax response to an array.
try using JSON.parse to convert the string to an actual array...
data.addRows(JSON.parse(array));
In one of the case, need to add Square brackets []
self.tableValues.forEach((row: any) => {
if(row) {
dataTable.addRows([row]); // <-- row is array; so try [row]
}
});

Google Charts - Table has no columns when it has columns

I'm attempting to create a Google Charts Line Chart. The Json I'm returning from a C# MVC controller method looks as follows:
My JS code looks as follows:
function drawChart() {
var jsonData = $.ajax({
url: "/Misc/GetWeeklySalesData/",
dataType: "json",
async: false
}).responseText;
// Create our data table out of JSON data loaded from server.
var data = new google.visualization.DataTable(jsonData);
alert(data);
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.LineChart(document.getElementById('chartDiv'));
chart.draw(data, { width: 400, height: 240 });
I'm getting the message 'Table has no columns' when clearly it does.
To create the data table directly from JSON, it must be in a specific format:
Format of the Constructor's JavaScript Literal data Parameter
Otherwise, you can create a blank data table and load the rows manually:
$.ajax({
url: "/Misc/GetWeeklySalesData/",
dataType: "json",
}).done(function (jsonData) {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Week');
data.addColumn('number', 'Retail');
data.addColumn('number', 'Wholesale');
jsonData.forEach(function (row) {
data.addRow([
row.Week,
row.Retail,
row.Wholesale
]);
});
var chart = new google.visualization.LineChart(document.getElementById('chartDiv'));
chart.draw(data, {
width: 400,
height: 240
});
}).fail(function (jq, text, err) {
console.log(text + ' - ' + err);
});
Note: highly recommend not using --> async: false. Use the done callback instead...

Chart.js: Dynamic Changing of Chart Type (Line to Bar as Example)

I am trying to hot swap chart types based on select box changes. If data needs to be updated, it changes.
So for example, on page load I create a chart like this:
var config = {
type: 'line',
data: {
labels: this.labels,
datasets: [{
label: 'Some Label',
data: this.values
}]
},
options: {
responsive: true
}
}
var context = document.getElementById('canvas').getContext('2d');
window.mychart = new Chart(context, config);
But then I change the combo box to a bar chart. I have tested the data with bar chart on page load, and it worked great.
Here's how I am trying to change the chart.
window.mychart.destroy();
// chartType = 'bar'
config.type = chartType;
var context = document.getElementById('canvas').getContext('2d');
window.mychart = new Chart(context, config);
window.mychart.update();
window.mychart.render();
But nothing happens. The line chart remains. How can I dynamically change the chart type? (Even if it means destroying & re-creating the chart canvas).
UPDATE
Note it looks like it is actually destroying the chart, but keeps redrawing a line chart, even though I do console.log(config.type); and it returns bar, not line
The Fix
Destroy the old chart (to remove event listeners and clear the canvas)
Make a deep copy of the config object
Change the type of the copy
Pass the copy instead of the original object.
Here is a working jsfiddle example
Example Overview:
var temp = jQuery.extend(true, {}, config);
temp.type = 'bar'; // The new chart type
myChart = new Chart(ctx, temp);
NOTE: Using version 2.0.1 of Chart.js
Why this works
Chart.js modifies the config object you pass in. Because of that you can not just change 'config.type'. You could go into the modified object and change everything to the type you want, but it is much easier to just save the original config object.
Just to follow up that this is now fixed in v.2.1.3, as followed through by https://stackoverflow.com/users/239375/nathan
document.getElementById('changeToLine').onclick = function() {
myChart.destroy();
myChart = new Chart(ctx, {
type: 'line',
data: chartData
});
};
Confirmed fixed in latest version. Check out http://codepen.io/anon/pen/ezJGPB and press the button under the chart to change it from a bar to a line chart.
No need to destroy and re-create, you just have to change the type from the chart's config variable then update the chart.
var chartCfg = {
type: 'pie',
data: data
};
var myChart = new Chart(ctx, chartCfg );
function changeToBar() {
chartCfg.type = "bar";
myChart.update();
}
In chart.js 3.8.0 you can do it like this:
let chart = new Chart(ctx, {
type: "line",
data: {
// ...
},
options: {
// ...
}
});
chart.config.type = "bar";
chart.update();
you can also change data and options this way
chart.js docs on updating:
https://www.chartjs.org/docs/latest/developers/updates.html
codepen example: https://codepen.io/3zbumban/pen/yLKMMJx
The alternate solution can be as simple as creating both the charts in separate Div elements. Then as per your condition just make one visible and hide other in the javascript. This should serve the purpose you may have for changing the chart type for your requirement.
In ChartJS, the chart type can also be changed easily like chart data. Following example might be helpful
my_chart.type = 'bar';
my_chart.update();
In ChartJS 3, :
var options = // your options.
var data = { ...myChart.data }; // deep copy of the data
var ctx = document.getElementById('myChart_id').getContext('2d');
myChart.destroy()
/// Modify ctx or data if you need to.
myChart = new Chart(ctx, {
type: chart_type,
data: data
});
Chart.options = options;
myChart.update();

google chart api material date month

I have a google bar chart with multiple series and a date hAxis.
My problem is that i want to show months only, but i get the label multiple times.
Here's an example
google.charts.load('current', {'packages': ['bar'], 'language': 'de'});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var chart;
var chartDiv = document.getElementById('test');
var data = new google.visualization.DataTable('{"cols":[{"type":"date","pattern":""},{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"}],"rows":[{"c":[{"v":"Date(2016,2,1)"},{"v":2030,"f":"2030 km"},{"v":2098,"f":"2098 km"},{"v":1352,"f":"1352 km"},{"v":4412,"f":"4412 km"},{"v":132,"f":"132 km"},{"v":2435,"f":"2435 km"},{"v":3952,"f":"3952 km"}]},{"c":[{"v":"Date(2016,3,1)"},{"v":3177,"f":"3177 km"},{"v":2901,"f":"2901 km"},{"v":2491,"f":"2491 km"},{"v":1480,"f":"1480 km"},{"v":2272,"f":"2272 km"},{"v":400,"f":"400 km"},{"v":1096,"f":"1096 km"}]}]}');
var options = {
legend: { position: 'none' },
hAxis: {
type: 'category',
format: 'MMMM'
}
};
chart = new google.charts.Bar(chartDiv);
chart.draw(data, google.charts.Bar.convertOptions(options));
}
https://jsfiddle.net/1Lusd06n/3/
If i shrink the width of the fiddle, the month names are grouped and displayed once but this does not happen if there is more space.

"Table has no rows" Error in Google Charts Histogram

I am working with Google Histogram chart. It working fine with some data sets but not for other data sets. And it raise an error "Table has no rows" even my input is correct.
Here i am reading a csv file column wise and pass to visualization page.
for eg: I am reading 2 csv column here and passing to visualization page. Here my input to Google histogram is
var inputdata1 = [["val","d"],["val","2"],["val","2"],["val","1"],["val","2"],["val","2"],["val","1"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","1"],["val","2"]];
and this working fine and gives histogram for me.
while I am passing other 2 columns.Here my input to Google histogram is
var inputdata2 = [["val","b"],["val","3"],["val","3"],["val","3"],["val","5"],["val","1"],["val","12"],["val","7"],["val","11"],["val","1"],["val","7"],["val","6"],["val","16"],["val","11"],["val","21"],["val","12"],["val","1"],["val","22"],["val","16"],["val","1"],["val","21"],["val","11"],["val","6"],["val","11"],["val","15"],["val","12"],["val","12"]];
while executing this, it raise an error that "Table has no rows" . Please check my fiddle.
Any help would be greatly appreciated.
Thank you in Advance.
In fact neither inputdata1 nor inputdata2 contain JSON data that are supported by histogram chart.
According to the documentation the following formats are supported:
Data Format
There are two ways to populate a histogram datatable. When there's
only one series:
var data = google.visualization.arrayToDataTable([
['Name', 'Number'],
['Name 1', number1],
['Name 2', number2],
['Name 3', number3],
...
]);
...and when there are multiple series:
var data = google.visualization.arrayToDataTable([
['Series Name 1', 'Series Name 2', 'Series Name 3', ...],
[series1_number1, series2_number1, series3_number1, ...],
[series1_number2, series2_number2, series3_number2, ...],
[series1_number3, series2_number3, series3_number3, ...],
...
]);
Having said that you might want to convert the second column into number format:
var inputJson = [["val","b"],["val","3"],["val","3"],["val","3"],["val","5"],["val","1"],["val","12"],["val","7"],["val","11"],["val","1"],["val","7"],["val","6"],["val","16"],["val","11"],["val","21"],["val","12"],["val","1"],["val","22"],["val","16"],["val","1"],["val","21"],["val","11"],["val","6"],["val","11"],["val","15"],["val","12"],["val","12"]];
var chartJson = inputJson.map(function(item,i){
if(i == 0)
return item;
else {
return [item[0],parseInt(item[1])];
}
});
var data = google.visualization.arrayToDataTable(chartJson);
Once the data is converted the chart will be rendered properly.
Working example
google.load('visualization', '1.1', {
'packages': ['corechart']
});
google.setOnLoadCallback(drawStuff);
function drawStuff() {
var inputJson = [["val","b"],["val","3"],["val","3"],["val","3"],["val","5"],["val","1"],["val","12"],["val","7"],["val","11"],["val","1"],["val","7"],["val","6"],["val","16"],["val","11"],["val","21"],["val","12"],["val","1"],["val","22"],["val","16"],["val","1"],["val","21"],["val","11"],["val","6"],["val","11"],["val","15"],["val","12"],["val","12"]];
var chartJson = inputJson.map(function(item,i){
if(i == 0)
return item;
else {
return [item[0],parseInt(item[1])];
}
});
var data = google.visualization.arrayToDataTable(chartJson);
//The below input data works fine.
//var data = google.visualization.arrayToDataTable([["val","d"],["val","2"],["val","2"],["val","1"],["val","2"],["val","2"],["val","1"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","2"],["val","1"],["val","2"]]);
// Set chart options
var options = {
width: 400,
height: 300,
histogram: {
bucketSize: 0.1
}
};
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.Histogram(document.getElementById('chart_div'));
chart.draw(data, options);
};
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script src="chart.js"></script>
<div id="chart_div"></div>