Create aggregation function to report most popular in Google DataTable - google-visualization

I have a Google DataTable which looks like this:
var data = new google.visualization.DataTable();
data.addColumn('string', 'City');
data.addColumn('string', 'Model');
data.addColumn('number', 'Sold');
data.addRows([
["Melbourne","Ford",10],
["Perth","Ford",2],
["Melbourne","Ford",7],
["Melbourne","Holden",25],
["Perth","Holden",25],
["Melbourne","Holden",12],
["Melbourne","Ford",11]
]);
What I would like to do is group by City and report the Model with the highest cumulative Sold value for that City.
The result returned would be :
City Model
Melbourne Holden
Perth Ford
From my reading of the Google Visualisation API it is possible to write a custom aggregation function but that is beyond my limited experience.
Any assistance would be greatly appreciated.

This would require a double grouping: the first time to get total sold per model per city, and the second time to get the most popular model.
var g1 = google.visualization.data.group(data, [0, 1], [{
type: 'number',
label: 'Total Sold',
column: 2,
aggregation: google.visualization.data.sum
}]);
// create a view to merge columns 1 and 2 together for the grouping below
var view = new google.visualization.DataView(g1);
view.setColumns([0, {
type: 'string',
label: 'Model QTy Sold',
calc: function (dt, row) {
var o = {model: dt.getValue(row, 1), sold: dt.getValue(row, 2)};
return JSON.stringify(o);
}
}]);
var g2 = google.visualization.data.group(data, [0], [{
type: 'string'
label: 'Most Popular'
aggregation: function (values) {
var max = null, ret = null;
for (var i = 0; i < values; i++) {
var o = JSON.parse(values[i]);
if (max == null || o.sold > max) {
max = o.sold;
ret = o.model;
}
}
return ret;
}
}]);
g2 should contain model with highest sales grouped by city. If there is a tie between two models, this will return the first model in the values array (likely values will be ordered by model name, but this is not guaranteed).

The edits I made to asgallant's second grouping were:
var g2 = google.visualization.data.group(view, [0], [{
type: 'string',
label: 'Most Popular',
column: 1,
aggregation: function (values) {
var max = null, ret = null;
for (var i = 0; i < values.length; i++) {
var o = JSON.parse(values[i]);
if (max == null || o.sold > max) {
max = o.sold;
ret = o.model;
}
}
return ret;
}
}]);

Related

DynamoDB Query with sort key and partition key

I am using JS SDK with DynamoDB to fetch data.
I am able to fetch data from my table using simple query with partition key and sort key.
My sort key sk has records -
Year#Batch#Rate
If I pass var sk = "2006#CSE#90"; it returns all of records matching this,
Requirement - How can I get all products with year 2006 , Batch CSE AND Rate =>90
readItem_pbro(){
console.log("inside pbro");
var table2 = "pbro";
var pk = "1";
var sk = "2006#CSE#90";
var params2 = {
TableName: table2,
Key:{
"pk": pk,
"sk": sk
}
};
Edit 1 :: Created a different column for score/rate as score. It is numeric.
Now my query in JS is -
but I am getting error - ValidationException: The provided key element does not match the schema
readItem_score_filter(){
console.log("inside pbro");
var table2 = "pbro";
var pk = "1"; // string
var sk = "2006#CSE"; // string
var score = 90; //number
var params2 = {
TableName: table2,
Key:{
"pk": pk,
"sk": sk,
FilterExpression:'score >=:score',
}
};
what is wrong in my FilterExpression.
Edit 2 :: Added Key condition Expression but issue still remains the same
Error: ValidationException: The provided key element does not match the schema
Here is my complete function now:
readItem_score_filter(){
console.log("inside pbro");
var table2 = "pbro";
var pk = "1"; //string
var sk = "2006#CSE"; // string
var score = 90; //number
var params2 = {
TableName: table2,
Key:{
"pk": pk,
"sk": sk,
"score": score,
KeyConditionExpression: 'pk = :pk AND sk=:sk',
FilterExpression: "score >=:score",
}
};
this.user.docClient.get(params2, function(err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
}
Screenshot of table attached incase you need to see::
If "2006#CSE#90" this is the value of sort key column then you cant do anything at Dynamodb level..
comparings like this can be done through regular expressions but DynamoDB doesn't support Regular Expressions.
you simply need to get results and then seperate these values and compare ..
Updated :- use different column for score.
And use Filter Expression to get records having rate more than 90.
I dont know python , but still am trying here
var params2 = {
TableName: "pbro",
KeyConditionExpression: "pk = :pk AND sk =:sk",
FilterExpression: "score >= :score"
};

Type Mismatch error when altering a google.visualization.DataTable() column value even after explicitly changing its data type

I have a datatable that's being returned by google.visualization.data.group()
var aggData = google.visualization.data.group(
view,
[0],
aggColumns
);
I want to set several columns to be of type string with a tooltip role, and converting values in them to an html string
for (var col=2; col < aggData.getNumberOfColumns(); col = col + 2){
aggData.setColumnProperties(col,{'type':'string', 'role':'tooltip', 'p':{'html':true}});
//looking to see if the column type was actually changed
console.log('Column '+col+' type: ' + aggData.getColumnProperty(col, 'type'))
for (var row = 0; row < aggData.getNumberOfRows(); row = row + 1){
aggData.setValue(row, col, getHTML(aggData.getValue(row, col)))
}
}
function getHTML(count) {;
return 'Projects Completed: <b>' + count + '</b>';
}
I checked the column data type in the log and it does return a string but when i set the value to a string it throws a type mismatch error.
Column 2 type: string
Uncaught Error: Type mismatch. Value Projects Completed: <b>2</b> does not match type number in column index 2
I also tried setting the column type using setColumnProperty() method but it's the same result. What am I missing?
================================================================================================
Below is a snippet of the larger script if needed
Sample input data looks like
"Oct 1, 2019, 12:00:00 AM",Team C,68
"Sep 23, 2019, 12:00:00 AM",Team C,68
"Nov 29, 2019, 12:00:00 AM",Team C,87
"Dec 31, 2019, 12:00:00 AM",Team C,62
....................................
"Nov 21, 2018, 12:00:00 AM",Team A,79
"Dec 29, 2018, 12:00:00 AM",Team A,58
"Nov 15, 2018, 12:00:00 AM",Team B,96
"Dec 29, 2018, 12:00:00 AM",Team B,77
The data is being read into a data table
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Year');
data.addColumn('string', 'Team');
data.addColumn('number', 'Total Score');
var groupData = google.visualization.data.group(
data,
[
{
column: 0,
modifier: getYear,
type: 'number'
},
1
],
[
{
column: 2,
aggregation: google.visualization.data.sum,
type: 'number'
},
{
column: 2,
aggregation: google.visualization.data.count,
type: 'number',
role: 'tooltip'
}
]
);
// create data view from groupData
var view = new google.visualization.DataView(groupData);
// sum column array
var aggColumns = [];
// use year (column 0) as first view column
var viewColumns = [0];
// build calculated view & agg columns for each team
groupData.getDistinctValues(1).forEach(function (team, index) {
// add a column to the view for each team
viewColumns.push({
calc: function (dt, row) {
if (dt.getValue(row, 1) === team) {
return dt.getValue(row, 2);
}
return null;
},
label: team,
type: 'number'
});
viewColumns.push({
calc: function (dt, row) {
if (dt.getValue(row, 1) === team) {
return dt.getValue(row, 3);
}
return null;
},
label: 'Number of Projects',
type: 'number'
});
// add sum column for each team
aggColumns.push({
aggregation: google.visualization.data.sum,
column: index*2 + 1,
label: team,
type: 'number'
});
aggColumns.push({
aggregation: google.visualization.data.sum,
column: index*2 + 2,
type: 'number',
role: 'tooltip',
});
});
// set view columns
view.setColumns(viewColumns);
var aggData = google.visualization.data.group(
view,
[0],
aggColumns
);
/*
The aggData looks like
"2,018",137,2,173,2,0,0
"2,019",864,12,"1,028",12,610,12
*/
for (var col=2; col < aggData.getNumberOfColumns(); col = col + 2){
aggData.setColumnProperties(col,{'type':'string', 'role':'tooltip', 'p':{'html':true}});
console.log('Column '+col+' type: ' + aggData.getColumnProperty(col, 'type'))
for (var row = 0; row < aggData.getNumberOfRows(); row = row + 1){
aggData.setValue(row, col, getHTML(aggData.getValue(row, col)))
}
}
data table method setColumnProperties isn't doing what you expect.
it only sets the properties portion of the column --> 'p':{'html':true}
so after your code runs, you end up with the following in your column properties.
'p': {'type':'string', 'role':'tooltip', 'p':{'html':true}}
and in fact, it is not possible to change a column's type,
once it has been created.
instead, you'll need to either use the addColumn or insertColumn method.
another option would be to use a data view.
then you could use a calculated column for the tooltip,
and exclude the original column you are trying to change,
using the setColumns method on the data view.

google visualization query limit

I have a Google visualization query for which data is coming from fusion table as,
var query = new google.visualization.Query("https://www.google.com/fusiontables/gvizdata?tq=select * from *******************");
But it select only first 500 rows of data. How to overcome this limitation?
The Fusion Tables SQL queries are deprecated. The new version of the API is not limited to 500 rows, see the Fusion Tables API for details.
Edit:
Here is an example Dashboard using the Google Fusion Tables code Odi posted in comments below:
function drawTable(response) {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Country Name');
data.addColumn('number', 'Population in 1960');
data.addColumn('number', 'Population in 2000');
var rows = [];
for (var i = 0; i < response.rows.length; i++) {
rows.push([response.rows[i][0], parseInt(response.rows[i][1]), parseInt(response.rows[i][2])]);
}
data.addRows(rows);
var table = new google.visualization.ChartWrapper({
containerId: 'table_div',
chartType: 'Table',
options: {
}
});
var control = new google.visualization.ControlWrapper({
containerId: 'control_div',
controlType: 'StringFilter',
options: {
filterColumnIndex: 0
}
});
var dashboard = new google.visualization.Dashboard(document.querySelector('#dashboard'));
dashboard.bind([control], [table]);
dashboard.draw(data);
}
function getData() {
// Builds a Fusion Tables SQL query and hands the result to dataHandler
var queryUrlHead = 'https://www.googleapis.com/fusiontables/v1/query?sql=';
var queryUrlTail = '&key=AIzaSyCAI2GoGWfLBvgygLKQp5suUk3RCG7r_ME';
var tableId = '17jbXdqXSInoNOOm4ZwMKEII0sT_9ukkqt_zuPwU';
// write your SQL as normal, then encode it
var query = "SELECT 'Country Name', '1960' as 'Population in 1960', '2000' as 'Population in 2000' FROM " + tableId + " ORDER BY 'Country Name' LIMIT 10";
var queryurl = encodeURI(queryUrlHead + query + queryUrlTail);
var jqxhr = $.get(queryurl, drawTable, "jsonp");
}
google.load('visualization', '1', {packages:['controls'], callback: getData});
See it working here: http://jsfiddle.net/asgallant/6BXsy/
Give the date format yyy-mm-dd, this is how you would create Date objects from it:
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
// other columns
var rows = [], dateArray, year, month, day;
for (var i = 0; i < response.rows.length; i++) {
dateArray = response.rows[i][0].split('-');
year = parseInt(dateArray[0]);
month = parseInt(dateArray[1]) - 1;
day = parseInt(dateArray[2]);
rows.push([new Date(year, month, day) /*, other data */]);
}
data.addRows(rows);

Google Table Chart: Date Format

I am returning data to the chart using JSON.
I've managed to format the date for the x-axiz of the Line Chart, using;
var options = {
hAxis: {
format: ' dd MMM yy'
},
}
But I need help doing the same for a Table Chart where one of the columns should be of date format.
At the moment it is displaying "/Date(1372761341103)/"
How do I format this option?
As I understand it, the "options" variable setting is not available for the Table Chart.
Also, when I add my columns, setting my 'Date' column's data type to 'date' doesn't work...no chart is returned.
This is my code currently:
function drawChart3() {
$.get('/MyMall/GetAdRunData', {},
function (data) {
/* Add data */
var tdata = new google.visualization.DataTable()
tdata.addColumn('number', 'Id');
tdata.addColumn('string','Date');
tdata.addColumn('number', 'Opens');
for (var i = 0; i < data.length; i++) {
tdata.addRow([data[i].Id, data[i].Date, data[i].Opens]);
}
/* Draw chart */
var chart = new google.visualization.Table(document.getElementById('chart_adRun'));
//var formatter = new google.visualization.ColorFormat();
//var monthYearFormatter = new google.visualization.DateFormat({ pattern: "MMM yyyy" });
monthYearFormatter.format(tdata, 0);
formatter.addRange(-1, 1, 'white', 'orange');
formatter.addRange(0, 2, 'red', '#33ff33');
formatter.addRange(1, 10, 'red', 'pink');
formatter.format(tdata, 1); // Apply formatter to second column
chart.draw(tdata, { allowHtml: true, showRowNumber: false });
}
)
}
I solved it this way...
for (var i = 0; i < data.length; i++) {
var date = new Date(parseInt(data[i].Date.substr(6)));
tdata.addRow([data[i].Id, date, data[i].Opens]);
}

How to interact with a table in a dashboard drawn by using google graphs api?

I have a dashboard containing a table and a string filtering box. I would like to interact with the table to be able to select rows and retrieve respective data from it.
after slight changes I got the getSelection() method working but there appeared another problem.. With the code below I try to filter the table and then select and get row data.. It all seems okay but when I do so the filtered table row numbers and the row numbers in the actual data does not match. that is I end up alerting the row data with reference to the pre-filtered table... Again any suggestion is highly valued.. thanks..
var dashboard, table, data;
function drawVisualization() {
var array = new Array(['ticker','time','bid','open','high','low','volume']);
var ticker, time, bid, open, high, low, volume;
$.get('php/getdata.php', {input: 'stocklist'}, function(data1){
$.each(data1, function(index, value){
ticker = value.ticker;
time = value.time;
bid = parseFloat(value.bid);
open = parseFloat(value.open);
high = parseFloat(value.high);
low = parseFloat(value.low);
volume = parseFloat(value.volume);
array.push([ticker, time, bid, open, high, low, volume]);
});
data = google.visualization.arrayToDataTable(array);
var stringFilter = new google.visualization.ControlWrapper({
'controlType': 'StringFilter',
'containerId': 'control1',
'options': {
'filterColumnLabel': 'ticker'
}
});
table = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'chart1',
'options': {'showRowNumber': false, 'height': '130px', 'width': '1000px'}
});
dashboard = new google.visualization.Dashboard(document.getElementById('dashboard'))
dashboard.bind(stringFilter, table);
dashboard.draw(data);
google.visualization.events.addListener(table, 'select', selectHandler);
}, "json");
}
function selectHandler() {
var selection = table.getChart().getSelection();
for (var i = 0; i < selection.length; i++) {
var item = selection[i];
if (item.row != null && item.column != null) {
} else if (item.row != null) {
stockID = data.getFormattedValue(item.row, 0);
} else if (item.column != null) {
stockID = data.getFormattedValue(0, item.column);
}
}
if (stockID == '') {
return;
}
alert(stockID);
}
google.setOnLoadCallback(drawVisualization);
I've had a similar problem.
You have to get the new DataTable after applying the filter. Try changing
stockID = data.getFormattedValue(item.row, 0);
to
stockID = table.getDataTable().getFormattedValue(item.row, 0);
and the same for the other case.
cheers