Google Chart: How do I sort by category filter with chronological order (by month)? - charts

I have a category filter that populates month name with alphabetical order. I would like to display the months by chronological order (January, February, March, etc.) and also I would like to set current month name as default in the dropdown. I can not tweak the SQL by ORDER BY field, instead, I would like to do it from category filter.
Code:
var filterFrequencyData = new google.visualization.ControlWrapper(
{
'controlType': 'CategoryFilter',
'containerId': 'filterFrequencyDataHtml',
'options':
{
'filterColumnIndex': '5',
'ui':
{
'label': '',
'labelSeparator': ':',
'labelStacking': 'vertical',
'allowTyping': false,
'allowNone': false,
'allowMultiple': false,
'sortValues': false
}
}
});

When using sortValues: false on a CategoryFilter, the values will be sorted as they appear in the data.
In order to get the month names to sort in chronological order (January, February, March, etc...), you need to use a column type other than 'string' and sort that column, 'number' or 'date', for instance.
Then set the formatted value of the cell to the month name. For example:
{v: 0, f: 'January'}
or
{v: new Date(2016, 0, 1), f: 'January'}
You can also use the setFormattedValue method, if the cell already has a value:
data.setFormattedValue(0, 0, 'January');
once in place, the table can be sorted according to the 'number' or 'date':
data.sort({column: 0});
See the following working snippet, a 'date' column is used to sort the month names:
google.charts.load('current', {
callback: function () {
var data = new google.visualization.DataTable({
cols: [{
label: 'Month',
type: 'date'
}]
});
// load months in reverse
var formatDate = new google.visualization.DateFormat({pattern: 'MMMM'});
var today = new Date();
var monthCount = 12;
var selectedRow;
var rowIndex;
while (monthCount--) {
// get row values
var monthDate = new Date(today.getFullYear(), monthCount, 1);
var monthName = formatDate.formatValue(monthDate);
// use object notation when setting value
rowIndex = data.addRow([{
// value
v: monthDate,
// formatted value
f: monthName
}]);
// set selected row
if (monthName === formatDate.formatValue(today)) {
selectedRow = rowIndex;
}
}
// sort data
data.sort({column: 0});
var dash = new google.visualization.Dashboard(document.getElementById('dashboard'));
var control = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'control_div',
options: {
filterColumnIndex: 0,
ui: {
allowMultiple: false,
allowNone: false,
allowTyping: false,
label: '',
labelStacking: 'vertical',
sortValues: false
},
// use month name
useFormattedValue: true
},
// state needs formatted value
state: {
selectedValues: [data.getFormattedValue(selectedRow, 0)]
}
});
// or set state here -- just need month name
control.setState({selectedValues: [formatDate.formatValue(today)]});
var chart = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'chart_div',
options:{
allowHtml: true
}
});
dash.bind(control, chart);
dash.draw(data);
},
packages: ['controls', 'corechart', 'table']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard">
<div id="control_div"></div>
<div id="chart_div"></div>
</div>

Related

ExtJS MultiSelect Edit - Not working for multi value selection

I have a GridEditPanel where the 1st column is a combobox with multiSelect. The values are being loaded correctly from the DB and is being written in the DB correctly as well. In the event where the the combobox has a single value, the drop-down highlights the value correctly as well.
The issue is when the combobox has multiple values, it displays the values correctly, however during edit the multiple values are not selected.
Model:
extend: 'Ext.data.Model',
idProperty: 'contactTypeID',
fields: [
{
name: 'contactTypeID',
type: 'string'
},
{
name: 'contactType',
type: 'string'
}
],
View GridEditPanel
emptyText: "There are no contacts.",
insertErrorText: 'Please finish editing the current contact before inserting a new record',
addButtonText: 'Add Contact',
itemId: 'contacts',
viewConfig: {
deferEmptyText: false
},
minHeight: 130,
initComponent: function () {
var me = this,
contactTypes;
// Creating store to be referenced by column renderer
contactTypes = Ext.create('Ext.data.Store', {
model: '********',
autoLoad: true,
listeners: {
load: function () {
me.getView().refresh();
}
}
});
this.columns = [
{
text: 'Contact Role',
dataIndex: 'contactRoleID',
flex: 1,
renderer: function (value) {
// Lookup contact type to get display value
//If a contact has multiple roles, use split by ',' to find display values.
if (value.includes(',')) {
var a = value.split(','), i, contTypeIds = [];
var contTypes = new Array();
for (i = 0; i < a.length; i++) {
contTypeIds.push(a[i]);
contTypes.push(contactTypes.findRecord('contactTypeID', a[i], 0, false, false, true).get('contactType'));
}
console.log('Multi Render Return Value: ' + contTypes);
return contTypes;
}
else {//if not a contact will only have one role.
var rec = contactTypes.findRecord('contactTypeID', value, 0, false, false, true); // exact match
console.log('Single Render Return Value: ' + rec.get('contactType'));
return rec ? rec.get('contactType') : '<span class="colselecttext">Required</span>';
}
},
align: 'center',
autoSizeColumn: true,
editor: {
xtype: 'combobox',
store: contactTypes,
multiSelect: true,
delimiter: ',',
forceSelection: true,
queryMode: 'local',
displayField: 'contactType',
valueField: 'contactTypeID',
allowBlank: false
}
},
I cannot see the model of GridEditPanel, but I assume you are using the wrong field type, string instead of array (Have a look at the converter function, maybe it will help you to fix the problem). I wrote a small post in my blog about multiSelect combobox editor in editable grid. The sample works with v4.2
Hope it will help you to fix the bug.

Line Chart Dashboard with Aggregated Data Points

I am working on a dashboard containing a line chart, Table chart, and two category filters, and I need to figure out how to aggregate multiple rows into points that can be plotted on the line chart.
Given a data set held in a google sheet such as the sample I list below, the line graph needs to display years across the X axis (2014 - 2017), and an average of all satisfaction rates among both companies, and all departments.
The first CategoryFilter allows a user to select one of the companies. When they select one, the line graph should show aggregate numbers of all Departments, combined.
The second CategoryFilter allows the user to select a department, and the line graph should show the satisfaction rates for that single company/department.
As it stands now, once I "drill down" to the single company/department, the graph displays properly. My task at this point is to get the aggregations to work until the two category filters are used to "drill down" to a single department.
Can anybody point me to a resource that describes how to accomplish this, or to a working example that I can see how to code it?
Company Department Year Satisfaction_Rate
CompA Personnel 2014 0.8542
CompA Personnel 2015 0.8680
CompA Personnel 2016 0.8712
CompA Personnel 2017 0.8832
CompA Sales 2014 0.7542
CompA Sales 2015 0.7680
CompA Sales 2016 0.7712
CompA Sales 2017 0.7832
CompA Labor 2014 0.6542
CompA Labor 2015 0.6680
CompA Labor 2016 0.6712
CompA Labor 2017 0.6832
CompB Personnel 2014 0.9242
CompB Personnel 2015 0.9280
CompB Personnel 2016 0.9312
CompB Personnel 2017 0.9132
CompB Sales 2014 0.8742
CompB Sales 2015 0.8880
CompB Sales 2016 0.8112
CompB Sales 2017 0.8632
CompB Labor 2014 0.7942
CompB Labor 2015 0.8080
CompB Labor 2016 0.8112
CompB Labor 2017 0.8232
Although this sample data accurately represents the concept of the type of data I'm working with, the actual data is quite different, as you'll notice in my code.
// Load the Visualization API and the corechart package.
google.charts.load('current', { 'packages': ['corechart', 'controls'] });
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawCharts);
//------------------------------------------------------------------------------
function GetDataFromSheet(URL, queryString, callback) {
var query = new google.visualization.Query(URL);
query.setQuery(queryString);
query.send(gotResponse);
function gotResponse(response) {
if (response.isError()) {
console.log(response.getReasons());
alert('Error in query: ' + response.getMessage() + " " + response.getDetailedMessage());
return;
}
if (response.hasWarning()) {
console.log(response.getReasons());
alert('Warning from query: ' + response.getMessage() + " " + response.getDetailedMessage());
return;
}
callback(response);
}
}
//------------------------------------------------------------------------------
function drawCharts() {
var URL, query;
// PREP DATA SOURCE
URL = 'https://docs.google.com/spreadsheets/d/1QygNPsYR041jat.../gviz/tq?gid=1339946796';
query = 'select A, C, D, H, J, M, P, S LABEL A "AEA", C "District", D "Class of", H "Graduation Rate", J "Post-Secondary Intention Rate", M "Enrollment Rate", P "Persistence Rate", S "Completion Rate"';
GetDataFromSheet(URL, query, handlePrep);
}
//------------------------------------------------------------------------------
// POST SECONDARY READINESS & EQUITY PARTNERSHIP
function handlePrep(response) {
var data = response.getDataTable();
// Attempting to aggregate... grouping on index 2, "class of". Example: 2015
// averaging column 3, Graduation Rate
var result = google.visualization.data.group(
data,
[2],
[{'column': 3, 'aggregation': google.visualization.data.avg, 'type': 'number'}]
);
var container = new google.visualization.Dashboard(document.getElementById('divPrep'));
var AEAControl = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'divAEAPicker',
options: {
filterColumnIndex: 0,
ui: {
selectedValuesLayout: 'belowStacked',
label: 'AEA Selector ->',
caption: 'Choose an AEA...',
allowNone: true,
allowMultiple: false
},
}
});
var DistrictControl = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'divDistrictPicker',
options: {
filterColumnIndex: 1,
ui: {
label: 'District Selector ->',
caption: 'Choose a District...',
allowNone: true,
allowMultiple: false
},
}
});
var chart = new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'divPrepChart',
options: {
height: 400,
width: 1200,
pointSize: 5,
title: 'Post-Secondary Readiness & Equity Partnership (PREP) Trendlines',
legend: { position: 'top', maxLines: 3 },
//chartArea: { left: '10%', width: '85%'},
tooltip:{textStyle: {color: '#000000'}, showColorCode: true},
hAxis:{
format: 'yyyy',
title: 'Graduating Class Year'
},
vAxis: {
format: 'percent',
maxValue: 1,
minValue: 0
}
},
view: {'columns': [2, 3, 4, 5, 6, 7]}
});
var table = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'divTable',
options: {
title: 'Post-Secondary Readiness & Equity Partnership ',
legend: { position: 'top', maxLines: 3 },
//chartArea: { left: '10%', width: '85%'},
page: 'enable',
pageSize: 10
}
});
// Create a formatter to display values as percent
var percentFormatter = new google.visualization.NumberFormat({pattern: '0.00%'});
percentFormatter.format(data, 3);
percentFormatter.format(data, 4);
percentFormatter.format(data, 5);
percentFormatter.format(data, 6);
percentFormatter.format(data, 7);
// Configure the controls so that:
// - the AEA selection drives the District one
// - both the AEA and Disctirct selections drive the linechart
// - both the AEA and Districts selections drive the table
container.bind(AEAControl, DistrictControl);
container.bind([AEAControl, DistrictControl], [chart, table]);
// Draw the dashboard named 'container'
container.draw(data);
// Until we figure out how to display aggregated values at the AEA and State levels,
// keep the line graph hidden until both an AEA and District are chosen from the category filters
google.visualization.events.addListener(container, 'ready', function() {
var aeaSelectedValues = AEAControl.getState()['selectedValues'];
var districtSelectedValues = DistrictControl.getState()['selectedValues'];
if (aeaSelectedValues.length == 0 || districtSelectedValues.length == 0) {
document.getElementById('divPrepChart').style.visibility = 'hidden';
} else {
document.getElementById('divPrepChart').style.visibility = 'visible';
}
});
}
This is how my data currently graphs prior to options selected with the category filters...
I need to make it look more like this...
you will need to draw the controls and charts independently, without using a dashboard.
then you can draw the charts when the control's 'statechage' event fires.
when the event fires, you can aggregate the data based on the selected values,
and re-draw the charts.
see following working snippet...
google.charts.load('current', { 'packages': ['corechart', 'controls'] });
google.charts.setOnLoadCallback(handlePrep);
function handlePrep(response) {
var data = google.visualization.arrayToDataTable([
['Company', 'Department', 'Year', 'Satisfaction_Rate'],
['CompA', 'Personnel', 2014, 0.8542],
['CompA', 'Personnel', 2015, 0.8680],
['CompA', 'Personnel', 2016, 0.8712],
['CompA', 'Personnel', 2017, 0.8832],
['CompA', 'Sales', 2014, 0.7542],
['CompA', 'Sales', 2015, 0.7680],
['CompA', 'Sales', 2016, 0.7712],
['CompA', 'Sales', 2017, 0.7832],
['CompA', 'Labor', 2014, 0.6542],
['CompA', 'Labor', 2015, 0.6680],
['CompA', 'Labor', 2016, 0.6712],
['CompA', 'Labor', 2017, 0.6832],
['CompB', 'Personnel', 2014, 0.9242],
['CompB', 'Personnel', 2015, 0.9280],
['CompB', 'Personnel', 2016, 0.9312],
['CompB', 'Personnel', 2017, 0.9132],
['CompB', 'Sales', 2014, 0.8742],
['CompB', 'Sales', 2015, 0.8880],
['CompB', 'Sales', 2016, 0.8112],
['CompB', 'Sales', 2017, 0.8632],
['CompB', 'Labor', 2014, 0.7942],
['CompB', 'Labor', 2015, 0.8080],
['CompB', 'Labor', 2016, 0.8112],
['CompB', 'Labor', 2017, 0.8232],
]);
var AEAControl = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'divAEAPicker',
dataTable: data,
options: {
filterColumnIndex: 0,
ui: {
selectedValuesLayout: 'belowStacked',
label: 'AEA Selector ->',
caption: 'Choose an AEA...',
allowNone: true,
allowMultiple: false
},
}
});
var DistrictControl = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'divDistrictPicker',
dataTable: data,
options: {
filterColumnIndex: 1,
ui: {
label: 'District Selector ->',
caption: 'Choose a District...',
allowNone: true,
allowMultiple: false
},
}
});
var chart = new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'divPrepChart',
options: {
height: 400,
width: 1200,
pointSize: 5,
title: 'Post-Secondary Readiness & Equity Partnership (PREP) Trendlines',
legend: { position: 'top', maxLines: 3 },
tooltip:{textStyle: {color: '#000000'}, showColorCode: true},
hAxis:{
format: '0',
title: 'Graduating Class Year'
},
vAxis: {
format: 'percent',
maxValue: 1,
minValue: 0
}
},
});
var table = new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'divTable',
options: {
title: 'Post-Secondary Readiness & Equity Partnership ',
legend: { position: 'top', maxLines: 3 },
page: 'enable',
pageSize: 10
}
});
google.visualization.events.addListener(AEAControl, 'statechange', drawDashboard);
google.visualization.events.addListener(DistrictControl, 'statechange', drawDashboard);
function drawDashboard() {
var view = new google.visualization.DataView(data);
var valuesAEA = AEAControl.getState();
var valuesDistrict = DistrictControl.getState();
var viewRows = [];
if (valuesAEA.selectedValues.length > 0) {
viewRows.push({
column: AEAControl.getOption('filterColumnIndex'),
test: function (value) {
return (valuesAEA.selectedValues.indexOf(value) > -1);
}
});
}
if (valuesDistrict.selectedValues.length > 0) {
viewRows.push({
column: DistrictControl.getOption('filterColumnIndex'),
test: function (value) {
return (valuesDistrict.selectedValues.indexOf(value) > -1);
}
});
}
if (viewRows.length > 0) {
view.setRows(data.getFilteredRows(viewRows));
}
result = google.visualization.data.group(
view,
[2],
[{'column': 3, 'aggregation': google.visualization.data.avg, 'type': 'number'}]
);
var percentFormatter = new google.visualization.NumberFormat({pattern: '0.00%'});
percentFormatter.format(result, 1);
chart.setDataTable(result);
chart.draw();
table.setDataTable(result);
table.draw();
}
AEAControl.draw();
DistrictControl.draw();
drawDashboard();
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="divPrep">
<div id="divAEAPicker"></div>
<div id="divDistrictPicker"></div>
<div id="divPrepChart"></div>
<div id="divTable"></div>
</div>

How do I bind google visualization category filter with all filters at any direction of selection?

I have three category filter which had a binding clockwise direction of dropdown selection. Now I need to bind it for any direction. It means, If I select any dropdown other 2 dropdown should be filter their values.
Code works for clockwise direction:
var cblAnalyst = new google.visualization.ControlWrapper(
{
'controlType': 'CategoryFilter',
'containerId': 'cblAnalyst',
'options': {
'filterColumnIndex': '0', 'ui': {
'label': '', 'labelSeparator': ':', 'labelStacking': 'horizontal', 'allowTyping': false, 'allowNone': true, 'allowMultiple': false
}
}
});
var cblAdvocate = new google.visualization.ControlWrapper(
{
'controlType': 'CategoryFilter',
'containerId': 'cblAdvocate',
'options': {
'filterColumnIndex': '1',
'ui': { 'label': '', 'labelSeparator': ':', 'labelStacking': 'horizontal', 'allowTyping': false, 'allowNone': true, 'allowMultiple': false }
}
});
var cblProductNames = new google.visualization.ControlWrapper(
{
'controlType': 'CategoryFilter',
'containerId': 'cblProductNames',
'options': {
'filterColumnIndex': '7',
'ui': { 'label': '', 'labelSeparator': ':', 'labelStacking': 'horizontal', 'allowTyping': false, 'allowNone': true, 'allowMultiple': false }
}
});
var tblSearchFilters = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'tblSearchFilters',
'options': {
'allowHtml': true, 'showRowNumber': true, 'page': 'enable', 'pageSize': 10,
width: '100%'
}
});
new google.visualization.Dashboard(document.getElementById('dashboard'))
.bind(cblAnalyst, cblAdvocate)
.bind(cblAdvocate, cblProductNames)
.bind(cblProductNames, tblSearchFilters)
.draw(dtSearchFilters);
Category filter drawn:
Solution looking for:
I should be able to filter the Analyst and Advocate when i chosen the product.
EDITED:
Sample Data:
Filter 1 Filter 2 Filter 3 (Apply filter here)
AN - 1 AD - 1 PD - 1
AN - 1 AD - 1 PD - 2
AN - 1 AD - 2 PD - 3
AN - 2 AD - 3 PD - 4
AN - 2 AD - 4 PD - 5
Copy this into excel spreadsheet and apply filter as specified..
the question is difficult to understand without a working example
typically, when binding multiple controls to the same chart(s),
only one bind call is needed
new google.visualization.Dashboard(document.getElementById('dashboard'))
.bind([cblAnalyst, cblAdvocate, cblProductNames], tblSearchFilters)
.draw(dtSearchFilters);
this will keep all the filters in sync with the table
for instance, if a Product is selected,
only the remaining Analysts and Advocates associated with that product will be available in the filters

Google chart table formatting cell as percentage

I am trying to format a cell in a google chart table as a percentage field.
For a column it works with :
var flow_format2 = new google.visualization.NumberFormat( {suffix: '%', negativeColor: 'red', negativeParens: true, fractionDigits: 0} );
But as far as I can read there is no possibility for a row, therefore I would like to do it on cell level - is that possible?
Is it with setProperty I need to do it and what is the formatting syntax.
you can use the formatValue method of NumberFormat to get the formatted string
rather than applying to the entire column
then you can manually setFormattedValue on the DataTable cell
to change the color, use setProperty to change the cell's 'style' property
the chart must be drawn afterwards
--or--
when the chart's 'ready' event fires, you can change the cell value using the DOM
the Table chart produces a normal set of html <table> tags
following is a working snippet, demonstrating both approaches...
google.charts.load('current', {
callback: function () {
var dataTable = new google.visualization.DataTable({
cols: [
{label: 'Name', type: 'string'},
{label: 'Amount', type: 'number'},
],
rows: [
{c:[{v: 'Adam'}, {v: -1201}]},
{c:[{v: 'Mike'}, {v: 2235}]},
{c:[{v: 'Stephen'}, {v: -5222}]},
{c:[{v: 'Victor'}, {v: 1288}]},
{c:[{v: 'Wes'}, {v: -6753}]}
]
});
var container = document.getElementById('chart_div');
var tableChart = new google.visualization.Table(container);
var patternFormat = {
suffix: '%',
negativeColor: '#FF0000',
negativeParens: true,
fractionDigits: 0
};
// create the formatter
var formatter = new google.visualization.NumberFormat(patternFormat);
// format cell - first row
dataTable.setFormattedValue(0, 1, formatter.formatValue(dataTable.getValue(0, 1)));
if (dataTable.getValue(0, 1) < 0) {
dataTable.setProperty(0, 1, 'style', 'color: ' + patternFormat.negativeColor + ';');
}
google.visualization.events.addOneTimeListener(tableChart, 'ready', function () {
// format cell via DOM - third row
var tableCell = container.getElementsByTagName('TR')[3].cells[1];
tableCell.innerHTML = formatter.formatValue(dataTable.getValue(2, 1));
if (dataTable.getValue(2, 1) < 0) {
tableCell.style.color = patternFormat.negativeColor;
}
});
tableChart.draw(dataTable, {
allowHtml: true
});
},
packages: ['table']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Google Charts: ChartWrapper and Formatters (NumberFormat)

How do I use ChartWrapper and a formatter to add a suffix to the tooltip on line / bar charts?
This is my code for the ChartWrapper
function drawChartb() {
var wrapper = new google.visualization.ChartWrapper({
chartType: 'LineChart',
dataTable: [['Person', 'Score'], [1, .50], [2, .25]],
options: {'legend': 'bottom', 'colors': ['#D70005'], 'chartArea': {left: 40, top: 10, width: 450}, 'vAxis': {format: '#,###%', 'viewWindow': {max: 1.05, min: .2}}, 'pointSize': 6},
containerId: 'chart_div'
});
wrapper.draw();
}
This is how I did it without using a chartwrapper.
// set tooltip as percentage
var formatter = new google.visualization.NumberFormat({
pattern: '#%',
fractionDigits: 2
});
formatter.format(data, 1);
Thanks
You can define your data outside the wrapper, use the formatter on it, and then set the dataTable to be equal to that data source:
function drawVisualization() {
var data = google.visualization.arrayToDataTable([
['Person', 'Score'], [1, .50], [2, .25]
]);
// set tooltip as percentage
var formatter = new google.visualization.NumberFormat({
pattern: '#%',
fractionDigits: 2
});
formatter.format(data, 1);
var wrapper = new google.visualization.ChartWrapper({
chartType: 'LineChart',
dataTable: data,
options: {'legend': 'bottom', 'colors': ['#D70005'], 'chartArea': {left: 40, top: 10, width: 450}, 'vAxis': {format: '#,###%', 'viewWindow': {max: 1.05, min: .2}}, 'pointSize': 6},
containerId: 'visualization'
});
wrapper.draw();
}
Result:
For those who generate their chart data using Google JSON schema and cannot get NumberFormat to work with ChartWrapper, you can apply formatting directly to the row "f":null
To note:
I have found the NumberFormat constructor method works with DataTables but not with ChartWrapper.
Using DataTable > OK
var chart = new google.visualization.PieChart(document.getElementById('chart'));
var dataTable = new google.visualization.DataTable(data);
var formatter = new google.visualization.NumberFormat({prefix: '$'});
formatter.format(dataTable, 1);
Using ChartWrapper > BAD
var formatter = new google.visualization.NumberFormat({prefix: '$'});
formatter.format(data, 1);
var wrapper = new google.visualization.ChartWrapper({
chartType: 'PieChart',
dataTable: data,
options: myPieChartOptions(),
containerId: 'chart_div'
});
This is how I properly formatted my data using Google JSON.
Example JSON:
{
"cols": [
{"id":"","label":"Product","pattern":"","type":"string"},
{"id":"","label":"Sales","pattern":"","type":"number"}
],
"rows": [
{"c":[{"v":"Nuts","f":null},{"v":945.59080870918,"f":"$945.59"}]}
]
}
And here's the PHP code to generate that JSON
setlocale(LC_MONETARY, 0);
// init arrays
$result['cols'] = array();
$result['rows'] = array();
// add col data
$result['cols'][] = array(
"id" => "",
"label" => "Product",
"pattern" => "",
"type" => "string"
);
$result['cols'][] = array(
"id" => "",
"label" => "Sales",
"pattern" => "",
"type" => "number"
);
$nutsTotalFormat = "$".number_format($nutsTotal, 2);
$result['rows'][]["c"] = array(array("v" => "Nuts","f" => null),array("v" => $nutsTotal,"f" => $nutsTotalFormat ));
Pie chart will show the formatted result of $nutsTotalFormat
"$945.59"