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

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.

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"
};

Create aggregation function to report most popular in Google DataTable

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;
}
}]);

Google visualization data table-getFilteredRows method

Im trying to filter column 'time' in visualization data table using getFilteredRows(filters) method.I provided column value with minimum and maximum values as,
var timesheet_dataTable = new google.visualization.DataTable(data, 0.6);
var time_filter = timesheet_dataTable.getFilteredRows([{column: 3, minValue: '2:28 PM', maxValue: '3:01 PM'}]);
and then created data view with setRows method to display the data but the table displayed without filtering the data.I checked with other column values and received proper output.So whether 'timeofday' data type is supported in this type of filters?
Is there any other method to filter column based on time?
Update:
This is the code for formatting and passing value to the visualization table.Value of variable startTime will be like '14:28:12'.
val datetimeStart: String = "Date(0,0,0,"
val datetimeEnd: String = ")"
val simpleDateTimeFormat = new SimpleDateFormat("HH,mm,ss")
Json.obj("v" -> JsString(datetimeStart + (simpleDateTimeFormat.format(tsl.startTime)).toString() + datetimeEnd))
before displaying in visualization table i have used formatter as:
var formatter_short1 = new google.visualization.DateFormat({pattern:'h:mm aa'});
formatter_short1.format(timesheet_dataTable,3);
The "timeofday" data type is supported by the filter method, you just need to use it correctly:
// filter column 3 from 2:28PM to 3:01PM
var time_filter = timesheet_dataTable.getFilteredRows([{
column: 3,
minValue: [14, 28, 0, 0],
maxValue: [15, 1, 0, 0]
}]);
var view = new google.visualization.DataView(timesheet_dataTable);
view.setRows(time_filter);
Make sure you are using the view you create to draw your chart, instead of the DataTable:
chart.draw(view, options);
[edit - example for filtering "datetime" type column]
// filter column 3 from 2:28PM to 3:01PM
var time_filter = timesheet_dataTable.getFilteredRows([{
column: 3,
minValue: new Date(0, 0, 0, 14, 28, 0, 0),
maxValue: new Date(0, 0, 0, 15, 1, 0, 0)
}]);
var view = new google.visualization.DataView(timesheet_dataTable);
view.setRows(time_filter);

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]);
}

graphael bar chart with text x-axis

I was wondering how I can make a simple bar chart that perhaps has day as the x-axis, with values 'today' and 'yesterday', and the y-axis as perhaps 'time' with corresponding values '1' and '2'. I guess I'm confused as to how to set text as the values for the x-axis, how to show the y axis, and what exactly r.g.axis does...
(I found an example using axis = r.g.axis(0,300,400,0,500,8,2) and I only know it's the xpos, ypos,width, ??, ?? num ticks, ??). Any insight would be great! Or a page with more fully featured bar chart examples (labels, etc). Thanks.
For the sake of all those googling this:
r.g.axis(x_start, y_start, x_width, from, to, steps, orientation, labels, type, dashsize)
x_start and y_start: distance of the axis text from the bottom left corner
x_width: position of the end of the text along the x axis
from and to: used to specify and range to use instead of using the labels argument
steps: is the number of ticks - 1
orientation: seems to specify x-axis vs. y-axis
type: is the type of tick mark used.
This was all deduced from the source code. I think I'll be switching to a charting library with documentation now...
The current code (Raphaeljs 2.0) has changed and has to be slightly adapted to use Raphael.g.axis instead of r.g.axis:
Raphael.g.axis(85,230,310,null,null,4,2,["Today", "Yesterday",
"Tomorrow", "Future"], "|", 0, r)
You're on the right track. You use g.axis and the positional arguments for setting the text is found in the 'text' arg (positional) and for toggling the y using the 'orientation' args. I added an example here,
Barchart with text x-axis
Reading this Q&A and a dozen like it, I still could not get gRaphaƫl to show proper labels for a bar chart. The recipes all seemed to refer to older versions of the library, or to github pages that are no longer there. gRaphaƫl produces some great looking output--but its docs leave much to be desired.
I was, however, able to use a combination of Firebug and Inspect This Element to follow the code and see what it produced. Diving into the barchart object, the required geometry is right there. To save others the frustration, here's how I solved the problem:
<script>
function labelBarChart(r, bc, labels, attrs) {
// Label a bar chart bc that is part of a Raphael object r
// Labels is an array of strings. Attrs is a dictionary
// that provides attributes such as fill (text color)
// and font (text font, font-size, font-weight, etc) for the
// label text.
for (var i = 0; i<bc.bars.length; i++) {
var bar = bc.bars[i];
var gutter_y = bar.w * 0.4;
var label_x = bar.x
var label_y = bar.y + bar.h + gutter_y;
var label_text = labels[i];
var label_attr = { fill: "#2f69bf", font: "16px sans-serif" };
r.text(label_x, label_y, label_text).attr(label_attr);
}
}
// what follows is just setting up a bar chart and calling for labels
// to be applied
window.onload = function () {
var r = Raphael("holder"),
data3 = [25, 20, 13, 32, 15, 5, 6, 10],
txtattr = { font: "24px 'Allerta Stencil', sans-serif", fill: "rgb(105, 136, 39)"};
r.text(250, 10, "A Gratuitous Chart").attr(txtattr);
var bc = r.barchart(10, 10, 500, 400, data3, {
stacked: false,
type: "soft"});
bc.attr({fill: "#2f69bf"});
var x = 1;
labelBarChart(r, bc,
['abc','b','card','d','elph','fun','gurr','ha'],
{ fill: "#2f69bf", font: "16px sans-serif" }
);
};
</script>
<div id="holder"></div>
There are a bunch of little cleanups you could do to labelBarChart(), but this basically gets the job done.
Here's a function I wrote for adding the labels. It's not particularly elegant but it will add the labels:
Raphael.fn.labelBarChart = function(x_start, y_start, width, labels, textAttr) {
var paper = this;
// offset width and x_start for bar chart gutters
x_start += 10;
width -= 20;
var labelWidth = width / labels.length;
// offset x_start to center under each column
x_start += labelWidth / 2;
for ( var i = 0, len = labels.length; i < len; i++ ) {
paper.text( x_start + ( i * labelWidth ), y_start, labels[i] ).attr( textAttr );
}
};
Usage is as follows:
var paper = Raphael(0, 0, 600, 400);
var chart = paper.barchart(0, 0, 600, 380, [[63, 86, 26, 15, 36, 62, 18, 78]]);
var labels = ['Col 1', 'Col 2', 'Col 3', 'Col 4', 'Col 5', 'Col 6', 'Col 7', 'Col 8'];
paper.labelBarChart(0, 390, 600, labels, {'font-size': 14});
I would like to propose a solution of an issue of the labelBarChart function proposed by Jonathan Eunice.
considering stacked bar-graphes (or other bar-graphes with more than one array of values), I added a test on bc.bars[0] in case the bc.bars.length means the number of arrays of values stacked.
This lead to the code :
<script>
function labelBarChart(r, bc, labels, attrs) {
// Label a bar chart bc that is part of a Raphael object r
// Labels is an array of strings. Attrs is a dictionary
// that provides attributes such as fill (text color)
// and font (text font, font-size, font-weight, etc) for the
// label text.
//Added test : replace bc.bars by generic variable barsRef
var barsRef = (typeof bc.bars[0].length === 'undefined') ? bc.bars : bc.bars[0];
var bar, gutter_y, label_x, label_y, label_text;
//Added consideration of set attrs (if set)
var label_attr = (typeof attrs === 'undefined') ? {} : attrs;
label_attr['fill'] = (typeof label_attr['fill'] === 'undefined') ? "#2f69bf" : label_attr['fill'];
label_attr['font'] = (typeof label_attr['font'] === 'undefined') ? "16px sans-serif" : label_attr['font'];
for (var i = 0; i<barsRef.length; i++) {
bar = barsRef[i];
gutter_y = bar.w * 0.4;
label_x = bar.x
label_y = bar.y + bar.h + gutter_y;
label_text = labels[i];
r.text(label_x, label_y, label_text).attr(label_attr);
}
}
// what follows is just setting up a bar chart and calling for labels
// to be applied
// I added an array of data to illustrate : data4
window.onload = function () {
var r = Raphael("holder"),
data3 = [25, 20, 13, 32, 15, 5, 6, 10],
data4 = [0, 2, 1, 40, 1, 65, 46, 11],
txtattr = { font: "24px 'Allerta Stencil', sans-serif", fill: "rgb(105, 136, 39)"};
r.text(250, 10, "A Gratuitous Chart").attr(txtattr);
var bc = r.barchart(10, 10, 500, 400, [data3, data4] {
stacked: true,
type: "soft"});
bc.attr({fill: "#2f69bf"});
labelBarChart(r, bc,
['abc','b','card','d','elph','fun','gurr','ha'],
{ fill: "#2f69bf", font: "16px sans-serif" }
);
};
</script>
<div id="holder"></div>
I just tested it with 2 arrays of values stacked.