show multiple data sets in C3.js line chart - json

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)

Related

How to get value only from json array using Jquery?

I am trying to get the value only from a json array. I have search some answer in stackoverflow but seems like not the one for me.
my code looks like this:
.done(function (data) {
var jdata = JSON.stringify(data['queryBuilder']);
var arrdata = JSON.parse(jdata);
var fdata = JSON.stringify(arrdata);
printtopdf(fdata);
);
//this code is from the answer posted here in stackoverflow:
function printtopdf(fdata) {
var values = Object.keys(fdata).map(function (key) { return fdata[key]; });
console.log(fdata);
}
and the result:
[
{
"rownum":2,
"rr_id":"RR2100001",
"ref_id":"UCL2100001",
"cdescription":"65UGHDFH56Y</br>, 65UGHDFH56Y</br>",
"rr_status":"Pending",
"date_created":"2021-01-08 13:46:03"
}
]
I just want to get the value only, like this:
[
2,
"RR2100001",
"UCL2100001",
"65UGHDFH56Y</br>, 65UGHDFH56Y</br>",
"Pending",
"2021-01-08 13:46:03"
]
Any idea? thanks.
You can achieve this using Array.prototype.map and Object.prototype.values.
const data = [
{
"rownum":2,
"rr_id":"RR2100001",
"ref_id":"UCL2100001",
"cdescription":"65UGHDFH56Y</br>, 65UGHDFH56Y</br>",
"rr_status":"Pending",
"date_created":"2021-01-08 13:46:03"
}
];
// Get values for all data points
const v1 = data.map(value => Object.values(value));
console.log(v1);
// Get values for first data point
const v2 = Object.values(data.shift());
console.log(v2);

Convert and parse json string to key value pairs using NewtonSoft

Trying to convert a json string to key value pairs using Newtonsoft but no luck so far.
Response from the API:
var response = #"{'result':{'0199 - B344EE33':
{
'6400_00260100':{'1':[{'val':336688}]},
'6400_00462500':{'1':[{'val':null}]},
'6800_00832A00':{'1':[{'low':3000,'high':3000,'val':3000}]},
'6800_008AA200':{'1':[{'low':0,'high':null,'val':0}]}
}}}";
Result I want is a new object of key value pairs:
{
"6400_00260100" : 336688,
"6400_00462500" : null,
"6800_00832A00" : 3000,
"6800_008AA200" : 0
}
In the response the result will always be the first and only prop. In the next level the code 0199 - B344EE33 can change but there will be only one prop in this level so we can always take the first one. Then in the last level we always need the val property.
What I have is the following but for getting the key value pairs in a clean way I got stuck:
var json = JObject.Parse(response);
var result = json["result"].First;
var path = result.Path;
UPDATE
var jObjectResult = new JObject();
var response = #"{'result':{'0199 - B344EE33':
{
'6800_10821E00':{'1':[{'val':'SMA Sunny Boy'}]},
'6800_00A21E00':{'1':[{'val':'3.0.0.2222'}]},
'6800_00823400':{'1':[{'low':3000,'high':3000,'val':3000}]},
'6800_08822B00':{'1':[{'val':'SMA'}]},
'6800_08822000':{'1':[{'val':'Sunny Boy 3.0'}]}
}}}";
var json = JObject.Parse(response);
var json_serial = json["result"].First.Children<JObject>().ToList()[0];
foreach(var token in json_serial)
{
var tokenKey = token.Key;
var tokenVal = token.Value.SelectToken("$.1[0].val");
jObjectResult.Add(tokenKey, tokenVal);
}
You could use SelectTokens with the recursive descent operator .. to find all the val properties, then walk up the chain using .Parent repeatedly to get the corresponding key. Create new JProperties from this information and put them into a new JObject to get your result. Here is a "one-liner":
var result = new JObject(
JObject.Parse(response)
.SelectTokens("$..val")
.Select(jt => new JProperty(
((JProperty)jt.Parent.Parent.Parent.Parent.Parent.Parent).Name,
jt
))
);
Fiddle: https://dotnetfiddle.net/TbZ7LS
At the end with some pointers form #Brian Rogers I came with the following solution:
// Arrange
var response = #"{'result':{'0199 - B344EE33':
{
'6800_10821E00':{'1':[{'val':'SMA Sunny Boy'}]},
'6800_00A21E00':{'1':[{'val':'3.0.0.2222'}]},
'6800_00823400':{'1':[{'low':3000,'high':3000,'val':3000}]},
'6800_08822B00':{'1':[{'val':'SMA'}]},
'6800_08822000':{'1':[{'val':'Sunny Boy 3.0'}]}
}}}";
// Act
var json = JObject.Parse(response);
var json_serial = (JProperty)json["result"].First();
var jObjectResult = new JObject(
json_serial.Value.Select(p =>
{
return new JProperty(
((JProperty)p).Name,
p.First.SelectToken("$.1[0].val")
);
}));

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

Amcharts: how use csv files with factors?

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.

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.