Amcharts: how use csv files with factors? - csv

Is it possible to use draw several lines depending on the factor column? I'll explain. I have next csv files:
year,lessThanWorkingAge,withinWorkingAge,moreThanWorkingAge,sex
2004,203,4928,32143,female
2005,195,4728,32005,female
2006,155,4211,31578,female
2007,150,3997,30526,female
2008,151,3800,30930,female
2009,180,3544,30614,female
2010,194,3411,31236,female
2011,171,3294,29193,female
2012,181,3243,29913,female
2013,187,2992,29505,female
2004,298,17634,19317,male
2005,252,17070,19120,male
2006,223,15264,18594,male
2007,179,14023,18591,male
2008,206,13153,18469,male
2009,230,11998,18341,male
2010,238,11449,18867,male
2011,221,11043,17810,male
2012,242,10485,17961,male
2013,232,9879,17509,male
How can i draw two lines for female and male usnig sex column as factor, year as x axis category and lessThanWorkingAge as y axis value?

Normally, amCharts does not support data like this.
However, if you are using Data Loader to load the CSV data to the chart, you can use its postProcess handler to automatically reformat the data so same-category values are consolidated into the same data point, so it does work.
Something like this:
"dataLoader": {
"url": "data.csv",
"format": "csv",
"useColumnNames": true,
"postProcess": function(data) {
var tmp = {};
var newData = [];
for (var i = 0; i < data.length; i++) {
var row = data[i];
if (tmp[row.year] === undefined)
tmp[row.year] = {
"year": row.year
};
tmp[row.year][row.sex] = row.lessThanWorkingAge;
}
for (var x in tmp) {
if (tmp.hasOwnProperty(x))
newData.push(tmp[x]);
}
return newData;
}
}
Here's a working example of the chart that loads your data using Data Loader.

Related

Google App Script - Trouble Outputting and Parsing Data

I'm using a google app script to pull data in regards to our chrome book devices, all is working ok apart from when trying to interrogate the "cpuStatusReports"
If i use
cputemp = JSON.stringify(chromebooks[i].cpuStatusReports)
Logger.log(cputemp);
the output i get is this
[{"cpuUtilizationPercentageInfo":[23,16,12,18,15,12,18,15,20,16],"cpuTemperatureInfo":[{"temperature":43,"label":"soc_dts0\n"},{"temperature":43,"label":"soc_dts1\n"}],"reportTime":"2019-06-24T11:53:24.973Z"},{"cpuUtilizationPercentageInfo":[45],"cpuTemperatureInfo":[{"temperature":33,"label":"soc_dts0\n"},{"temperature":34,"label":"soc_dts1\n"}],"reportTime":"2019-06-25T12:43:40.826Z"},{"cpuUtilizationPercentageInfo":[12],"cpuTemperatureInfo":[{"temperature":42,"label":"soc_dts0\n"},{"temperature":42,"label":"soc_dts1\n"}],"reportTime":"2019-06-25T14:01:47.016Z"},{"cpuUtilizationPercentageInfo":[27],"cpuTemperatureInfo":[{"temperature":29,"label":"soc_dts0\n"},{"temperature":30,"label":"soc_dts1\n"}],"reportTime":"2019-06-26T07:59:40.739Z"},{"cpuUtilizationPercentageInfo":[12,12,7,8,3,4,14,13,27,12],"cpuTemperatureInfo":[{"temperature":45,"label":"soc_dts0\n"},{"temperature":46,"label":"soc_dts1\n"}],"reportTime":"2019-06-26T10:59:41.370Z"}]
How can i split this? in particular im after the "cpuTemperatureInfo" field?
If someone could provide a working example i can then use this for the Diskreport as well as this is also outputting in the same format.
Thankyou for your help!
UPDATE:
** Full code of function
function chromebookdetails2() {
var domain, chromebooks, page, ss, sheet, pageToken, i
var sheetData4 = onSheet.getSheetByName("chromebook")
//sheetData4.clear();
domain = "my domain here"
chromebooks= new Array()
do{
page = AdminDirectory.Chromeosdevices.list("my_customer",
{domain: domain,
maxResults: 1000,
pageToken: pageToken
})
for (i in page.chromeosdevices){
chromebooks.push(page.chromeosdevices[i])
}
pageToken = page.nextPageToken
}while(pageToken){
var row = 3 //starting row position
for (var i = 0; i < chromebooks.length; i++) {
var sheetData4 = onSheet.getSheetByName("chromebook")
/////////////////////Header////////////////////////////////////////
var date = Utilities.formatDate(new Date(), "GMT+1", "dd/MM/yyyy")
sheetData4.getRange(1,1).setValue("Date Ran - "+date); //(2,1 means 2nd row, 1st column)
sheetData4.getRange(2,1).setValue("orgUnitPath"); //(2,1 means 2nd row, 1st column)
sheetData4.getRange(2,2).setValue("annotatedUser");
sheetData4.getRange(2,3).setValue("annotatedLocation");
sheetData4.getRange(2,4).setValue("annotatedAssetId");
sheetData4.getRange(2,5).setValue("serialNumber");
sheetData4.getRange(2,6).setValue("lastEnrollmentTime");
sheetData4.getRange(2,7).setValue("deviceId");
sheetData4.getRange(2,8).setValue("bootMode");
sheetData4.getRange(2,9).setValue("recentUsers");
sheetData4.getRange(2,10).setValue("macAddress");
sheetData4.getRange(2,11).setValue("lastSync");
sheetData4.getRange(2,12).setValue("osVersion");
sheetData4.getRange(2,13).setValue("platformVersion");
sheetData4.getRange(2,14).setValue("activeTimeRanges");
sheetData4.getRange(2,15).setValue("model");
sheetData4.getRange(2,16).setValue("etag");
sheetData4.getRange(2,17).setValue("firmwareVersion");
sheetData4.getRange(2,18).setValue("status");
sheetData4.getRange(2,19).setValue("ethernetMacAddress");
sheetData4.getRange(2,20).setValue("notes");
sheetData4.getRange(2,21).setValue("systemRamTotal");
sheetData4.getRange(2,22).setValue("CPU");
if(chromebooks[i].length == 0){
// array is empty
Logger.log('empty');
} else {
//array not empty
Logger.log('not empty');
cputemp = JSON.stringify(chromebooks[i].cpuStatusReports)
Logger.log(cputemp);
/////////////////////Array Data///////////////////////////////////
sheetData4.getRange(row,1).setValue(chromebooks[i].orgUnitPath);
sheetData4.getRange(row,2).setValue(chromebooks[i].annotatedUser);
sheetData4.getRange(row,3).setValue(chromebooks[i].annotatedLocation);
sheetData4.getRange(row,4).setValue(chromebooks[i].annotatedAssetId);
sheetData4.getRange(row,5).setValue(chromebooks[i].serialNumber);
sheetData4.getRange(row,6).setValue(chromebooks[i].lastEnrollmentTime);
sheetData4.getRange(row,7).setValue(chromebooks[i].deviceId);
sheetData4.getRange(row,8).setValue(chromebooks[i].bootMode);
sheetData4.getRange(row,9).setValue(chromebooks[i].recentUsers);
sheetData4.getRange(row,10).setValue(chromebooks[i].macAddress);
sheetData4.getRange(row,11).setValue(chromebooks[i].lastSync);
sheetData4.getRange(row,12).setValue(chromebooks[i].osVersion);
sheetData4.getRange(row,13).setValue(chromebooks[i].platformVersion);
sheetData4.getRange(row,14).setValue(chromebooks[i].activeTimeRanges);
sheetData4.getRange(row,15).setValue(chromebooks[i].model);
sheetData4.getRange(row,16).setValue(chromebooks[i].etag);
sheetData4.getRange(row,17).setValue(chromebooks[i].firmwareVersion);
sheetData4.getRange(row,18).setValue(chromebooks[i].status);
sheetData4.getRange(row,19).setValue(chromebooks[i].ethernetMacAddress);
sheetData4.getRange(row,20).setValue(chromebooks[i].notes);
sheetData4.getRange(row,21).setValue(chromebooks[i].systemRamTotal / (1024*1024) /1024); // "/ (1024*1024)" converts bytes to Mb "/1024" then converts back to Gb
//sheetData4.getRange(row,22).setValue(placeholder for cpu temp results));
}
row++
Logger.log(row)
}
}
}
Try this:
cputemp =(chromebooks[i].cpuStatusReports).toString().split(",");
Logger.log(cputemp);
for (var j in cputemp)
{
var element = cputemp[j];
Logger.log(element);
}
You can see then which j has the entry you need

Removing duplicates while loading a combo in HTML using a txt file

Below is my code to load the combo using a txt file:
$("#Combo1").change(function() {
$('#Combo2').empty();
$.ajax({
url: 'File.txt',
type: 'get',
success: function(txt){
var value = [];
var txtArray = txt.split('\n');
for (var i = 0; i < txtArray.length; i++)
{
var tmpData = txtArray[i].split(',');
if (!value[tmpData[1]])
{
value.push([tmpData[1]]);
value[tmpData[1]] = true;
}
}
$('#Combo2').empty();
$.each(value, function(i, p) {
$('#Combo2').append($('<option></option>').val(p).html(p));
});
}
})
});
$("#Combo1").trigger("change");
Here on change of Combo1, this will be called. The Ajax is used to read the content of File.txt File.txt has a "," seperated two columns, out of which I am willing to print coulmn2. Given below are the contents of File.TXT.
A,31JAN
B,25JAN
C,31JAN
D,6JAN
E,6JAN
I was to load the above dates in Combo2. With the above code, I am able to ignore 31JAN. But 6JAN is getting repeated. In short, the value which is given at the last row gets repeated. Rest is fine.
Try this:
var txt="A,31JAN\nB,25JAN\nC,31JAN\nD,6JAN\nE,6JAN";
var txtArray = txt.split('\n');
for (var i = 0; i < txtArray.length; i++)
txtArray[i] = txtArray[i].split(",").pop();
var value = txtArray.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]);
console.log(value); //returns array
Also, give this a read: https://stackoverflow.com/a/9229821/9920079 :)

Using document.getSelection() to get data to array like document.getSelection().toString() does for strings

I have an table in angular JS with filtering. I want to have only the selected data in the table in an array rows[] of arrays cell[]. This is why i cannot just export the table data.
I have tried the document.getSelection().toString() class and then .split but this failed as the elements in the table might consist of more than one word with blanks in between.
Is there a way to loop thru the object i get from document.getSelection() and distinguish between rows and cells?
With this i get the data as text, but i need an array:
var txt = '';
if (document.getSelection) {
txt = document.getSelection().toString();
} else if (document.selection) {
txt = document.selection.createRange().text;
}
Here i get the object:
if (document.getSelection) {
txt = document.getSelection();
} else if (document.selection) {
txt = document.selection.createRange();
}
console.log(txt)
Selection { anchorNode: , anchorOffset: 0, focusNode: , focusOffset: 3, isCollapsed: false, rangeCount: 1, caretBidiLevel: 0 }
Actually the answer was quite easy. I just had to use the document.getSelection().toString() function and use the split("/n") to get all the lines into an array, then i used split again to separate the elements by the tab that is added between column cells.
var tmp = [];
var rows = [];
var cells = [];
tmp = txt.split("\n");
for (var i=0; i<tmp.length; i++) {
cells.length = 0;
cells = tmp.split("\t");
rows.push(cells);
}

show multiple data sets in C3.js line chart

I have following json:
[
{"data"=>"data1", "value1"=>10, "value2"=>6, "day"=>"05-20-2016"},
{"data"=>"data1", "value1"=>17, "value2"=>10, "day"=>"05-21-2016"},
{"data"=>"data1", "value1"=>12, "value2"=>8, "day"=>"05-22-2016"},
{"data"=>"data2", "value1"=>5, "value2"=>1, "day"=>"05-20-2016"},
{"data"=>"data2", "value1"=>11, "value2"=>3, "day"=>"05-21-2016"},
{"data"=>"data2", "value1"=>25, "value2"=>18, "day"=>"05-22-2016"}
]
What I want is to display these values in a line chart with C3.js and have a separate line for each value.
Based on the example, I want to have one line for data1 and value1, one line for data1 and value2, one line for data2 and value1, one line for data2 and value2 and in the legend I want to have Value1 > Data1, Data2 and Value2 > Data1, Data2 (each data line to have a different color).
Right now, when I load this in C3.js, it will only show me 2 lines (one for data1 and one for data2).
Can someone show me exactly how to do this?
This is a data wrangling exercise in that you want to turn data like
{"data"=>"data1", "value1"=>10, "value2"=>6, "day"=>"05-20-2016"},
...
{"data"=>"data2", "value1"=>5, "value2"=>1, "day"=>"05-20-2016"},
into something like
{"data1value1"=>10, "data1value2"=>6,
"data2value1"=>17, "data2value2"=>10, "key"=>"05-20-2016"},
This can be achieved like this:
var json = [
{"data":"data1", "value1":10, "value2":6, "day":"05-20-2016"},
{"data":"data1", "value1":17, "value2":10, "day":"05-21-2016"},
{"data":"data1", "value1":12, "value2":8, "day":"05-22-2016"},
{"data":"data2", "value1":5, "value2":1, "day":"05-20-2016"},
{"data":"data2", "value1":11, "value2":3, "day":"05-21-2016"},
{"data":"data2", "value1":25, "value2":18, "day":"05-22-2016"}
];
var valFields = ["value1", "value2"];
var dataIndexField = "data";
var keyField = "day";
var newMap = {}; // new data will be built up in here
json.forEach (function (d) {
// get new data obj for key, which in this case is the day value
var key = d[keyField];
var newObj = newMap[key];
if (!newObj) { // make the obj if it doesn't exist
newObj = {key: key};
newMap[key] = newObj;
}
// in this obj merge the dataIndexField and valFields to make new datapoints
var dataIndex = d[dataIndexField]; // either data1 or data2
valFields.forEach (function (vField) { // vfield will loop value1 then value2
newObj[dataIndex+vField] = d[vField]; // data1/2value1/2 = the value of value1/2
});
});
var newJson = d3.values(newMap); // array of objs suitable for c3
// dataFields are the names of the new datapoint properties minus 'key'
var newDataFields = d3.keys(newJson[0]);
newDataFields.splice (newDataFields.indexOf("key"), 1);
var chart = c3.generate({
data: {
json: newJson,
keys: {
x: 'key',
value: newDataFields
}
},
axis: {
x: {
type: 'category'
}
}
});
http://jsfiddle.net/w7o8k40q/3/
Basically the bit in the middle merges the data1/2 and value1/2 figures like you asked and adds them into objects that have a unique key, in this case taken from the day field of each row. The Json.stringified output of newJson is as so:
[
{"key":"05-20-2016","data1value1":10,"data1value2":6,"data2value1":5,"data2value2":1},
{"key":"05-21-2016","data1value1":17,"data1value2":10,"data2value1":11,"data2value2":3},
{"key":"05-22-2016","data1value1":12,"data1value2":8,"data2value1":25,"data2value2":18}
]
This is enough for c3 if you tell it which properties in each row are data (which is what newDataFields does) and which one is the key for the x value (PS as we interpret key as a categorical value you may need to sort the json by the key field so the days don't appear out of turn - luckily we encounter them in order in the original dataset)

Slickgrid - Column Definition with Complex Objects

I have a Java object where the person object contains a displayName object. I have converted it to a JSON object for my JSP. The data looks like the following:
var people = [
{"id":52959,"displayName":{"firstName":"Jim","lastName":"Doe","middleName":"A"},"projectId":50003,"grade":"8","statusCode":"A","gradYear":2016,"buyer":false},
{"id":98765,"displayName":{"firstName":"Jane","lastName":"Doe","middleName":"Z"},"projectId":50003,"grade":"8","statusCode":"A","gradYear":2016,"buyer":true}
];
I want to bind my columns to the name properties that reside within the displayName object, but I am cannot get the column definition to recognize where the data resides. Here is an example of my firstName column definition:
{id: 'displayName.firstName', field: 'displayName.firstName', name: 'First Name',
width: 110, sortable: true, editor: TextCellEditor, formatter: SpaceFormatter,
cssClass: '', maxLength: 250, editable: true}
The view does not render the names although the data is there. Is it possible to bind a column to an object property that resides within another object? If so, what am I doing wrong?
Slickgrid doesn't support this capability by default, but you can workaround it by adding custom value extractor to your options object:
var options = {
dataItemColumnValueExtractor: function(item, columnDef) {
var names = columnDef.field.split('.'),
val = item[names[0]];
for (var i = 1; i < names.length; i++) {
if (val && typeof val == 'object' && names[i] in val) {
val = val[names[i]];
} else {
val = '';
}
}
return val;
}
}
var grid = new Slick.Grid($("#slickgrid"), data, columns, options);
The code is tested with slickgrid 2.0 and is working just fine. Unfortunately seems that slickgrid code is a bit inconsistent and editors don't take into account this option, so this solution is usable only if you will display the data without editing.
I know this is a bit old... but my work around is to do a pre-process on my items. Basically, flattening the model out:
var preProcessItems = function (items) {
var newItems = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
item['firstName'] = item['displayName']['firstName'];
newItems[i] = item;
}
return newItems;
};
/// when the value is updated on the flat structure, you can edit your deep value here
var fNameFormatter = function (row, cell, value, columnDef, dataContext) {
// datacontext.displayName.firstName = value;
return value ? value : "";
};
This problem seems to be more a of a data modeling issue though.