google line chart date formatting - javascript

I'd like to draw google line chart with trending however type mismatch occurred because of date format.
The below is my code.gs which to return the date value to string from spreadsheet in the first column.
I'd tried to put new Date() in JS to draw the line chart with trending however i don't know how to put this date value in datatable.
In the JS, the columns can be dynamically added which it works. But i could not solve the date problem so please help.
Code.gs
function getSpreadsheetData() {
var ssID = "1994YM4uwB1mQORl-HLNk6o10-0ADLNQPgUxKGW6iW_8",
data = SpreadsheetApp.openById(ssID).getSheets()[0].getDataRange().getValues();
for(var i=1; i<data.length; i++){
var date = new Date(data[i][0]);
data[i][0] = Utilities.formatDate(date, "GMT+9", "M/dd");
}
return data;
}
JS
google.charts.load('current', {'packages':['corechart','controls']});
google.charts.setOnLoadCallback(getSpreadsheetData);
function getSpreadsheetData() {
google.script.run.withSuccessHandler(drawChart).getSpreadsheetData();
}
function drawChart(rows) {
var data = google.visualization.arrayToDataTable(rows, false);
var columnsTable = new google.visualization.DataTable();
columnsTable.addColumn('number', 'colIndex'); // numbrer to date then error
columnsTable.addColumn('string', 'colLabel');
var initState= {selectedValues: []}
for (var i = 1; i < data.getNumberOfColumns(); i++) {
columnsTable.addRow([i, data.getColumnLabel(i)]);
}
var chart = new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'chart_div',
dataTable: data,
options: {
explorer: { axis: 'horizontal' },
pointSize: 3,
vAxis : { format: '#.#',
viewWindow:{
max:0.6,
min:0
},
},
hAxis: {format: 'M/dd'},
legend: 'none',
chartArea: {width: '90%'},
crosshair: { trigger: 'both', orientation: 'both' },
trendlines: {
0: {
type: 'polynomial',
lineWidth: 5,
color: 'orange',
labelInLegend: 'Trend',
degree: 5,
visibleInLegend: true,
},
}
}
});
var columnFilter = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'colFilter_div',
dataTable: columnsTable,
options: {
filterColumnLabel: 'colLabel',
filterColumnIndex: 1,
useFormattedValue: true,
ui: {
allowTyping: false,
allowMultiple: false, // when true then filters stacked
caption : 'Choose your values',
allowNone: true,
selectedValuesLayout: 'belowStacked'
}
},
state: initState
});
function setChartView () {
var state = columnFilter.getState();
var row;
var view = {
columns: [0]
};
for (var i = 0; i < state.selectedValues.length; i++) {
row = columnsTable.getFilteredRows([{column: 1, value: state.selectedValues[i]}])[0];
view.columns.push(columnsTable.getValue(row, 0));
}
// sort the indices into their original order
view.columns.sort(function (a, b) {
return (a - b);
});
if (state.selectedValues.length > 0) {
chart.setView(view);
} else {
chart.setView(null);
}
chart.draw();
}
google.visualization.events.addListener(columnFilter, 'statechange', setChartView);
setChartView();
columnFilter.draw();
}

you could use a data view, to convert the date string to an actual date.
here, create the data table as normal.
then create the data view, using a calculated column for the date column.
assuming the first data table column is the date string
function drawChart(rows) {
// create data table
var data = google.visualization.arrayToDataTable(rows, false);
// create data view
data = new google.visualization.DataView(data);
// create view columns with calculated column
var viewColumns = [{
calc: function (dt, row) {
return new Date(dt.getValue(row, 0));
},
label: data.getColumnLabel(0),
type: 'date'
}];
// add remaining columns
for (var = 1; i < data.getNumberOfColumns(); i++) {
viewColumns.push(i);
}
// set view columns
data.setColumns(viewColumns);
...

Related

Google category picker defined dynamically

I can define each category picker using a for loop. However, each picker variable ends up hard coded for the Google API to work:
var categoryPickerArray = [];
for (var i = 0; i < categoryPickers.length; i++) {
categoryPickerArray.push(
new google.visualization.ControlWrapper(categoryPicker_default(categoryPickers[i])),
);
//eval(`var categoryPicker${i} = categoryPickerArray[i];`);//works but uses eval
}
var categoryPicker0 = categoryPickerArray[0];
var categoryPicker1 = categoryPickerArray[1];
I can of use eval() but would prefer not to for all the security concerns.
My goal is to define the picker variables dynamically based on what I've pushed into categoryPickerArray. I'm trying to avoid the need for hard coding each var categoryPicker0 = categoryPickerArray[0] #1, #2, etc.
Hoping someone has an idea about how this can be accomplished. Thanks as always!
Here is my working code:
// Load the Visualization API and the corechart package.
google.charts.load('current', {
'packages': ['corechart', 'table', 'gauge', 'controls']
});
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(gChart0);
function gChart0() {
drawChart();
}
function drawChart() {
var result = [{
"calendarWeek": "2017-W30",
"partId": '1234567890xxx',
"someNumber": 0
}, {
"calendarWeek": "2017-W30",
"partId": '1234567890yyy',
"someNumber": 0
}, {
"calendarWeek": "2017-W30",
"partId": '1234567890111',
"someNumber": 0
}];
//Create DataTable
var data = new google.visualization.DataTable();
data.addColumn('string', 'Calendar Week');
data.addColumn('string', 'Part Id');
data.addColumn('number', 'Some Number');
var dataArray = [];
$.each(result, function(i, obj) {
dataArray.push([
obj.calendarWeek,
obj.partId,
obj.someNumber
]);
});
data.addRows(dataArray);
//Options
var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'));
const categoryPicker_default = (categoryPicker) => {
var id = categoryPicker.id;
var controlType = categoryPicker.controlType;
var filterColumnIndex = categoryPicker.filterColumnIndex;
const picker_options = `
{
"controlType": "${controlType}",
"containerId": "categoryPicker${id}",
"options": {
"filterColumnIndex": ${filterColumnIndex},
"matchType": "any",
"ui":{
"labelStacking": "vertical",
"allowTyping": false,
"allowMultiple": false,
"allowNone": true
}
}
}
`;
return JSON.parse(picker_options);
};
const categoryPickers = [{
"id": 0,
"controlType": "StringFilter",
"filterColumnIndex": 0
},
{
"id": 1,
"controlType": "StringFilter",
"filterColumnIndex": 1
}
];
var categoryPickerArray = [];
for (var i = 0; i < categoryPickers.length; i++) {
categoryPickerArray.push(
new google.visualization.ControlWrapper(categoryPicker_default(categoryPickers[i])),
);
//eval(`var categoryPicker${i} = categoryPickerArray[i];`);//works but uses eval
}
// Commented out per suggestion from WhiteHat - See bind below
//var categoryPicker0 = categoryPickerArray[0];
//var categoryPicker1 = categoryPickerArray[1];
var table = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'table',
options: {
width: '100%',
height: 'auto',
page: 'enable',
pageSize: '15',
sort: 'enable',
allowHtml: true
}
});
// Picker reset
google.visualization.events.addOneTimeListener(dashboard, 'ready', function() {
var reset = document.getElementById('categoryPicker_resetBtn');
reset.addEventListener('click', function() {
for (var i = 0; i < categoryPickerArray.length; ++i) {
categoryPickerArray[i].setState({
selectedValues: []
});
categoryPickerArray[i].draw();
}
});
});
//dashboard.bind([categoryPicker0, categoryPicker1], [table]); //Old call using hard coded values
dashboard.bind(categoryPickerArray, [table]);//New call using array
dashboard.draw(data);
} //END function drawChart()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard"></div>
<div id="categoryPicker0"></div>
<div id="categoryPicker1"></div><br>
<button id="categoryPicker_resetBtn">Reset</button>
<div id="table"></div>
UPDATE:
Made changes in snippet per suggestion from Mr. WhiteHat to use categoryPickerArray in place of hard coded values in the dashboard binding.
dashboard.bind(categoryPickerArray, [table]);
if you're hard coding for the bind method,
you can simply pass the array of pickers directly...
dashboard.bind(categoryPickerArray, [table]);

Google Visualization Referencing Defined Pickers Dynamically

My target is to build a event listener that loops through the visualization's defined pickers to call setState() and draw() for each one.
My initial thought was something like this:
for (var i = 0; i < 2; i++) { // 2 is hard coded for simplicity
categoryPicker[i].setState({selectedValues: []});
categoryPicker[i].draw();
}
I've tried following to access the picker via it's method getState() as a test but can't seem get results unless I hard code it:
//This works when hard coded
console.log(categoryPicker1.getState());
//ERROR temp.picker.getState is not a function
temp = { picker: "categoryPicker" + i };
//console.log(temp.picker.getState());
//ERROR temp.picker.getState is not a function
temp2 = ["categoryPicker" + i];
//console.log(temp2[i].getState());
I need some guidance in figuring out how to call the pickers dynamically? I don't want to resort to using eval() for security reasons.
Your assistance is appreciated.
Full working example:
// Load the Visualization API and the corechart package.
google.charts.load('current', {
'packages': ['corechart', 'table', 'gauge', 'controls']
});
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(gChart0);
function gChart0() {
drawChart();
}
function drawChart() {
var result = [{
"calendarWeek": "2017-W30",
"partId": '1234567890xxx',
"someNumber": 0
}, {
"calendarWeek": "2017-W30",
"partId": '1234567890yyy',
"someNumber": 0
}, {
"calendarWeek": "2017-W30",
"partId": '1234567890111',
"someNumber": 0
}];
//Create DataTable
var data = new google.visualization.DataTable();
data.addColumn('string', 'Calendar Week');
data.addColumn('string', 'Part Id');
data.addColumn('number', 'Some Number');
var dataArray = [];
$.each(result, function(i, obj) {
dataArray.push([
obj.calendarWeek,
obj.partId,
obj.someNumber
]);
});
data.addRows(dataArray);
//Options
var dashboard = new google.visualization.Dashboard(document.getElementById('div_dashboard'));
var categoryPicker0 = new google.visualization.ControlWrapper({
controlType: 'StringFilter',
containerId: 'div_categoryPicker1',
options: {
filterColumnIndex: 0,
matchType: 'any',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false,
allowNone: true
}
}
});
var categoryPicker1 = new google.visualization.ControlWrapper({
controlType: 'StringFilter',
containerId: 'div_categoryPicker2',
options: {
filterColumnIndex: 1,
matchType: 'any',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false,
allowNone: true
}
}
});
//ADDED THIS after suggestion from WhiteHat
var pickerArr = [categoryPicker0 , categoryPicker1 ];
var table = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'div_table',
options: {
width: '100%',
height: 'auto',
page: 'enable',
pageSize: '15',
sort: 'enable',
allowHtml: true
}
});
google.visualization.events.addOneTimeListener(dashboard, 'ready', function() {
// reset the category picker when clicked.
var reset = document.getElementById('categoryPicker_resetBtn');
reset.addEventListener('click', function() {
//categoryPicker0.setState({
//selectedValues: []
//});
//categoryPicker0.draw();
//categoryPicker1.setState({
//selectedValues: []
//});
//categoryPicker1.draw();
//ADDED THIS after suggestion from WhiteHat
for (var i = 0; i < pickerArr.length; ++i) {
pickerArr[i].setState({selectedValues: []}); //This resets pickers dynamically
pickerArr [i].draw();
}
});
});
dashboard.bind([categoryPicker0, categoryPicker1], [table]);
dashboard.draw(data);
} //END function drawChart()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="div_dashboard"></div>
<div id="div_categoryPicker1"></div>
<div id="div_categoryPicker2"></div><br>
<button id="categoryPicker_resetBtn">Reset</button><div id="div_table"></div>
UPDATE:
I was able to update my snippet above by adding the following code as suggested by WhiteHat.
This is set just after the pickers are defined:
//ADDED THIS after suggestion from WhiteHat
var pickerArr = [categoryPicker0 , categoryPicker1 ];
This replaces code I had in the event listener for the reset button:
//ADDED THIS after suggestion from WhiteHat
for (var i = 0; i < pickerArr.length; ++i) {
pickerArr[i].setState({selectedValues: []}); //This resets pickers dynamically
pickerArr [i].draw();
}
you could store them in an array...
var pickers = [];
pickers.push(new google.visualization.ControlWrapper({
controlType: 'StringFilter',
containerId: 'div_categoryPicker1',
options: {
filterColumnIndex: 0,
matchType: 'any',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false,
allowNone: true
}
}
}));
pickers.push(new google.visualization.ControlWrapper({
controlType: 'StringFilter',
containerId: 'div_categoryPicker2',
options: {
filterColumnIndex: 1,
matchType: 'any',
ui: {
labelStacking: 'vertical',
allowTyping: false,
allowMultiple: false,
allowNone: true
}
}
}));
then loop through the array...
pickers.forEach(function (picker) {
console.log(picker.getState());
});

Google Bar Chart with Percentage of Total and with Category Filters

I am fairly new to Google Charts and was trying to create a bar chart with % of total, along with the ability to filter the data by using Google Dashboard Controls... I followed this (thanks to #asgallant for this!) google.visualization.ChartWrapper Group Columns View and was able to get a bar chart which picks up data from a google sheet, and draws the chart with counts and also have the ability to filter the data using Google Category filters.
However, this is where I am stuck - when I try to add another columns (dataview) for calculating the total (so that I can draw the chart using the percentage and also show the percentage in the bar labels) - my chart is still drawing using the counts.. Can anyone please let me know what am I going wrong here:
function drawVisualization() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1LBoS8Q7qdpWVjks3FytQAefThzY3VbAHllf04nE6qO8/edit?gid=1629614877&range=A:D');
query.send(handleQueryResponse);
function handleQueryResponse(response) {
if (response.isError()) {return; }
var data = response.getDataTable();
// Define category pickers for All Filters
var CardTier = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'CardTier Filter',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var Campaign = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnLabel': 'Campaign Filter',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
// Define a bar chart to show 'Population' data
var barChart = new google.visualization.ChartWrapper({
'chartType': 'BarChart',
'containerId': 'chart1',
'options': {
'width': 400,
'height': 300,
'chartArea': {top: 0, right: 0, bottom: 0}
},
// Configure the barchart to use columns 0 (Card Tier) and 1 (Campaign Filter) (Basically the filters)
'view': {'columns': [0, 1]}
});
var proxyTable = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'proxyTable',
options: {
// minimize the footprint of the table in HTML
page: 'enable',
pageSize: 1
},
view: {
columns: [0]
}
});
// create a "ready" event handler for proxyTable the handles data aggregation and drawing barChart
// Add The question's column index here. We want to draw Status so we Group 2 with dt and also its count...
google.visualization.events.addListener(proxyTable, 'ready', function () {
var dt = proxyTable.getDataTable();
var groupedData = google.visualization.data.group(dt, [2], [{
column: 3,
type: 'number',
label: dt.getColumnLabel(2),
aggregation: google.visualization.data.count
}]);
var view = new google.visualization.DataView(groupedData);
view.setColumns([0, 1, {
calc: function (dt, row) {
var amount = formatShort.formatValue(dt.getValue(row, 1));
var percent = formatPercent.formatValue(dt.getValue(row, 1) / groupedData.getValue(0, 1));
return amount + ' (' + percent + ')';
},
type: 'string',
role: 'annotation'
}]);
// after grouping, the data will be sorted by column 0, then 1, then 2
// if you want a different order, you have to re-sort
barChart.setDataTable(view);
barChart.draw();
});
// Create the dashboard.
new google.visualization.Dashboard(document.getElementById('dashboard')).
// Configure the controls :
bind(CardTier, Campaign).
bind(Campaign, proxyTable).
// Draw the dashboard
draw(data);
}
}
google.load('visualization', '1', {packages:['corechart', 'controls', 'table'], callback: drawVisualization});
</script>
</head>
<body>
<div id="dashboard">
<table>
<tr style='vertical-align: top'>
<td style='width: 300px; font-size: 0.9em;'>
<div id="control1"></div>
<div id="control2"></div>
</td>
<td style='width: 600px'>
<div style="float: left;" id="chart1"></div>
<div style="float: left;" id="chart2"></div>
</td>
</tr>
</table>
<div id="proxyTable" style="display: none;"></div>
</div>
</body>
</html>
for starters, recommend using the newer library loader.js
<script src="https://www.gstatic.com/charts/loader.js"></script>
instead of jsapi, according to the release notes...
The version of Google Charts that remains available via the jsapi loader is no longer being updated consistently. Please use the new gstatic loader from now on.
this will only change the load statement, see following working snippet...
next, didn't see the definitions for the number formatters
formatShort and formatPercent
need to add those
groupedData will give you the total for each status
to get the the total for all the rows,
need to use the modifier function
this will change the value to 'Total' for the first column of all rows
allowing the group method to aggregate all rows
var totalData = google.visualization.data.group(
dataTable,
[{column: 0, type: 'string', modifier: function () {return 'Total';}}],
[{
column: 3,
type: 'number',
label: dataTable.getColumnLabel(2),
aggregation: google.visualization.data.count
}]
);
finally, remove the view option from barChart
since we're providing the view we want drawn
see following working snippet...
google.charts.load('current', {
callback: drawVisualization,
packages: ['corechart', 'controls', 'table']
});
function drawVisualization() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1LBoS8Q7qdpWVjks3FytQAefThzY3VbAHllf04nE6qO8/edit?gid=1629614877&range=A:D');
query.send(handleQueryResponse);
function handleQueryResponse(response) {
if (response.isError()) {return; }
var data = response.getDataTable();
// Define category pickers for All Filters
var CardTier = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'CardTier Filter',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var Campaign = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnLabel': 'Campaign Filter',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
// Define a bar chart to show 'Population' data
var barChart = new google.visualization.ChartWrapper({
'chartType': 'BarChart',
'containerId': 'chart1',
'options': {
'width': 400,
'height': 300,
'chartArea': {top: 0, right: 0, bottom: 0}
}
});
var proxyTable = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'proxyTable',
options: {
// minimize the footprint of the table in HTML
page: 'enable',
pageSize: 1
},
view: {
columns: [0]
}
});
// create a "ready" event handler for proxyTable the handles data aggregation and drawing barChart
// Add The question's column index here. We want to draw Status so we Group 2 with dt and also its count...
google.visualization.events.addListener(proxyTable, 'ready', function () {
var formatShort = new google.visualization.NumberFormat({
pattern: 'short'
});
var formatPercent = new google.visualization.NumberFormat({
pattern: '0.0%'
});
var dataTable = proxyTable.getDataTable();
// group by status
var groupedData = google.visualization.data.group(
dataTable,
[2],
[{
column: 3,
type: 'number',
label: dataTable.getColumnLabel(2),
aggregation: google.visualization.data.count
}]
);
// status total
var totalData = google.visualization.data.group(
dataTable,
[{column: 0, type: 'string', modifier: function () {return 'Total';}}],
[{
column: 3,
type: 'number',
label: dataTable.getColumnLabel(2),
aggregation: google.visualization.data.count
}]
);
var view = new google.visualization.DataView(groupedData);
view.setColumns([0, 1, {
calc: function (dt, row) {
var amount = dt.getValue(row, 1);
var total = totalData.getValue(0, 1);
var percent = 0;
if (total > 0) {
percent = amount / total;
}
return formatShort.formatValue(amount) + ' (' + formatPercent.formatValue(percent) + ')';
},
type: 'string',
role: 'annotation'
}]);
// after grouping, the data will be sorted by column 0, then 1, then 2
// if you want a different order, you have to re-sort
barChart.setDataTable(view);
barChart.draw();
});
// Create the dashboard.
new google.visualization.Dashboard(document.getElementById('dashboard')).
// Configure the controls :
bind(CardTier, Campaign).
bind(Campaign, proxyTable).
// Draw the dashboard
draw(data);
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="control1"></div>
<div id="control2"></div>
<div id="chart1"></div>
<div id="proxyTable"></div>
UPDATE
to draw the percentages instead of counts,
just need to add another calculated column to the view
as for showing zero values,
use the original data table to get a distinct list of status values
check if the status exists in groupedData
if not, add a row for the status
// add back missing status
var statusValues = data.getDistinctValues(2);
statusValues.forEach(function (status) {
var statusRow = groupedData.getFilteredRows([{
column: 0,
value: status
}]);
if (statusRow.length === 0) {
groupedData.addRow([
status,
0
]);
}
});
groupedData.sort([{column: 0}]);
see following working snippet...
google.charts.load('current', {
callback: drawVisualization,
packages: ['corechart', 'controls', 'table']
});
function drawVisualization() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1LBoS8Q7qdpWVjks3FytQAefThzY3VbAHllf04nE6qO8/edit?gid=1629614877&range=A:D');
query.send(handleQueryResponse);
function handleQueryResponse(response) {
if (response.isError()) {return; }
var data = response.getDataTable();
// Define category pickers for All Filters
var CardTier = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'CardTier Filter',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
var Campaign = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'control2',
'options': {
'filterColumnLabel': 'Campaign Filter',
'ui': {
'labelStacking': 'vertical',
'allowTyping': false,
'allowMultiple': false
}
}
});
// Define a bar chart to show 'Population' data
var barChart = new google.visualization.ChartWrapper({
'chartType': 'BarChart',
'containerId': 'chart1',
'options': {
'width': 400,
'height': 300,
'chartArea': {top: 0, right: 0, bottom: 0}
}
});
var proxyTable = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'proxyTable',
options: {
// minimize the footprint of the table in HTML
page: 'enable',
pageSize: 1
},
view: {
columns: [0]
}
});
// create a "ready" event handler for proxyTable the handles data aggregation and drawing barChart
// Add The question's column index here. We want to draw Status so we Group 2 with dt and also its count...
google.visualization.events.addListener(proxyTable, 'ready', function () {
var formatShort = new google.visualization.NumberFormat({
pattern: 'short'
});
var formatPercent = new google.visualization.NumberFormat({
pattern: '0.0%'
});
var dataTable = proxyTable.getDataTable();
// group by status
var groupedData = google.visualization.data.group(
dataTable,
[2],
[{
column: 3,
type: 'number',
label: dataTable.getColumnLabel(2),
aggregation: google.visualization.data.count
}]
);
// add back missing status
var statusValues = data.getDistinctValues(2);
statusValues.forEach(function (status) {
var statusRow = groupedData.getFilteredRows([{
column: 0,
value: status
}]);
if (statusRow.length === 0) {
groupedData.addRow([
status,
0
]);
}
});
groupedData.sort([{column: 0}]);
// status total
var totalData = google.visualization.data.group(
dataTable,
[{column: 0, type: 'string', modifier: function () {return 'Total';}}],
[{
column: 3,
type: 'number',
label: dataTable.getColumnLabel(2),
aggregation: google.visualization.data.count
}]
);
var view = new google.visualization.DataView(groupedData);
view.setColumns([0, {
calc: function (dt, row) {
var amount = dt.getValue(row, 1);
var total = totalData.getValue(0, 1);
var percent = 0;
if (total > 0) {
percent = amount / total;
}
return {
v: percent,
f: formatPercent.formatValue(percent)
};
},
type: 'number',
label: 'Percent'
}, {
calc: function (dt, row) {
var amount = dt.getValue(row, 1);
var total = totalData.getValue(0, 1);
var percent = 0;
if (total > 0) {
percent = amount / total;
}
return formatPercent.formatValue(percent) + ' (' + formatShort.formatValue(amount) + ')';
},
type: 'string',
role: 'annotation'
}]);
// after grouping, the data will be sorted by column 0, then 1, then 2
// if you want a different order, you have to re-sort
barChart.setDataTable(view);
barChart.draw();
});
// Create the dashboard.
new google.visualization.Dashboard(document.getElementById('dashboard')).
// Configure the controls :
bind(CardTier, Campaign).
bind(Campaign, proxyTable).
// Draw the dashboard
draw(data);
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="control1"></div>
<div id="control2"></div>
<div id="chart1"></div>
<div id="proxyTable"></div>
UPDATE 2
to find the total of a multiple choice question,
create a view with a calculated column
the new column should test that all question columns are not blank
then total the view on the calculated column
see following working snippet...
google.charts.load('current', {
callback: drawVisualization,
packages: ['corechart', 'controls', 'table']
});
function drawVisualization() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/19VWNZkHG5GEuYCibDmtOlKblKiOWcx94Wi9jyuhvEUo/edit#gid=0');
query.setQuery('select A,B,C,D,E,F,G');
query.send(handleQueryResponse);
function handleQueryResponse(response) {
if (response.isError()) {return;}
var data = response.getDataTable();
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, 2, 3, 4, 5, 6, {
calc: function (dt, row) {
var answered = 0;
var q1_1 = dt.getValue(row, 3) || '';
var q1_2 = dt.getValue(row, 4) || '';
var q1_3 = dt.getValue(row, 5) || '';
var q1_4 = dt.getValue(row, 6) || '';
if ((q1_1 !== '') || (q1_2 !== '') || (q1_3 !== '') || (q1_4 !== '')) {
answered = 1;
}
return answered;
},
label: 'Answered',
type: 'number'
}]);
var totalAnswered = google.visualization.data.group(
view,
[{column: 0, type: 'string', modifier: function () {return 'Total';}}],
[{
column: view.getNumberOfColumns() - 1,
type: 'number',
label: view.getColumnLabel(view.getNumberOfColumns() - 1),
aggregation: google.visualization.data.sum
}]
);
var proxyTable = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'proxyTable',
dataTable: view
});
proxyTable.draw();
document.getElementById('proxyTableTotal').innerHTML = 'Total Answered = ' + totalAnswered.getValue(0, 1);
}
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="proxyTable"></div>
<div id="proxyTableTotal"></div>

Stacked Column Annotations Google Charts

While creating a stacked column chart using google charts, the annotations are getting overlapped due to large amount data. Is there anyway to get it adjusted. Like displaying only for every 3rd column. I know this concept works fine with highcharts but I was looking for free charts.
Annotation function call is :--
function drawVisualization() {
var json;
$.getJSON('end.json', function (json) {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Time');
data.addColumn('number', 'Run 3');
data.addColumn({ type: 'number', role: 'annotation' });
data.addColumn('number', 'Run 2');
data.addColumn({ type: 'number', role: 'annotation' });
data.addColumn('number', 'Run 1');
data.addColumn({ type: 'number', role: 'annotation' });
for (var i = 0; i< json[0].data.length; i++){
data.addRow([json[0].data[i], json[3].data[i],json[3].data[i],json[2].data[i],json[2].data[i],json[1].data[i], json[1].data[i]]);
}
var options = {
title: "End to End Processing",
tooltip: {isHtml: true},
legend:{position:"right"},
isStacked:true,
height:window.innerHeight,
width: window.innerWidth,
bar: {groupWidth: '3'},
focusTarget: 'category',
vAxis: {
viewWindowMode:'explicit',
viewWindow: {
max:60,
min:0
},
gridlines :{count:6},
title:'Time in mins',
format: 'short'
},
hAxis: {
format: 'd/m/y',
textStyle : {
fontSize: 9
},
slantedText: true,
slantedTextAngle: 270
},
annotations: {
textStyle: {
color: 'black',
fontSize: 11,
fontStyle: 'bold'
},
 stemLength: 20,
displayAnnotationsFilter: true,
legendPosition: 'newRow'
},
series: {
0:{color:'lightgreen'},
1:{color:'black'},
2:{color:'#1E90FF',},
3:{ type: 'line', lineWidth: 0, visibleInLegend:false, pointSize: 0}
}
}
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(data, options);
});
$(window).resize(function(){
drawVisualization();
});
}
Regards.
there isn't a standard option, but you can use null for blank annotations
when loading, try the following to show annotations for every third row...
for (var i = 0; i< json[0].data.length; i++){
var annotation1 = null;
var annotation2 = null;
var annotation3 = null;
if ((i % 3) === 0) {
var annotation3 = json[3].data[i];
var annotation2 = json[2].data[i];
var annotation1 = json[1].data[i];
}
data.addRow([
json[0].data[i],
json[3].data[i],
annotation3,
json[2].data[i],
annotation2,
json[1].data[i],
annotation1
]);
}

Google column chart - set selected column color

I have simple column chart and I need to change color of selected (clicked) column. By default it adds white line around the column.
var options = {
title: 'Motivation and Energy Level Throughout the Day',
hAxis: {
title: 'Time of Day',
format: 'h:mm a',
viewWindow: {
min: [7, 30, 0],
max: [17, 30, 0]
}
},
vAxis: {
title: 'Rating (scale of 1-10)'
}
};
Here is simple example on jSFiddle
So if I click any column how to change its color to black?
I can't use Material Charts.
Thanks
Finally I found an answer here
Frankly I thought that there is simpler option, like setting configuration option e.g. hAxis.selected.color: '#000000'.
var chart = new google.visualization.ChartWrapper({
chartType: 'ColumnChart',
containerId: 'chart_div',
dataTable: data,
options: {
// setting the "isStacked" option to true fixes the spacing problem
isStacked: true,
height: 300,
width: 600,
series: {
1: {
// set the color to change to
color: '00A0D0',
// don't show this in the legend
visibleInLegend: false
}
}
}
});
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getChart().getSelection();
if (selection.length > 0) {
var newSelection = [];
// if row is undefined, we selected the entire series
// otherwise, just a single element
if (typeof(selection[0].row) == 'undefined') {
newSelection.push({
column: 2
});
chart.setView({
columns: [0, {
type: 'number',
label: data.getColumnLabel(1),
calc: function () {
// this series is just a placeholder
return 0;
}
}, 1]
});
}
else {
var rows = [];
for (var i = 0; i < selection.length; i++) {
rows.push(selection[i].row);
// move the selected elements to column 2
newSelection.push({
row: selection[i].row,
column: 2
});
}
// set the view to remove the selected elements from the first series and add them to the second series
chart.setView({
columns: [0, {
type: 'number',
label: data.getColumnLabel(1),
calc: function (dt, row) {
return (rows.indexOf(row) >= 0) ? null : {v: dt.getValue(row, 1), f: dt.getFormattedValue(row, 1)};
}
}, {
type: 'number',
label: data.getColumnLabel(1),
calc: function (dt, row) {
return (rows.indexOf(row) >= 0) ? {v: dt.getValue(row, 1), f: dt.getFormattedValue(row, 1)} : null;
}
}]
});
}
// re-set the selection when the chart is done drawing
var runOnce = google.visualization.events.addListener(chart, 'ready', function () {
google.visualization.events.removeListener(runOnce);
chart.getChart().setSelection(newSelection);
});
}
else {
// if nothing is selected, clear the view to draw the base chart
chart.setView();
}
chart.draw();
});
chart.draw();
}
UPDATE:
Above solution works only if you are using a ChartWrapper.
I actually needed solution just for chart.
Finally I solved this by adding style.color to the data row. If my selected index = rowIndex then I change the color. Simple and works like a charm.
I hope it will help others.
var data = new google.visualization.DataTable();
data.addColumn({ id: 'name', type: 'string' });
data.addColumn({ id: 'm1', type: 'number' });
data.addColumn({type: 'string', role:'tooltip', 'p': {'html': true}});
data.addColumn({type: 'string', role:'style'});
$.each(scatterData.data, function (index, value) {
if (index == chartSelectedIndex) {
data.addRow([ {v:value.park}, {v:value.m1}, {v:getColumnChartHTMLTooltip(value.park,value.name,value.m1)}, 'color: #32CCFF' ]);
} else{
data.addRow([ {v:value.park}, {v:value.m1}, {v:getColumnChartHTMLTooltip(value.park,value.name,value.m1)}, null ]);
};
});
This worked for me
.my-div svg>g>g>g>g>rect {
fill: #79baeb;
}

Categories

Resources