Creating dynamic data coming from multiple queries for SunBurst graph - javascript

I'm working on SunBurst graph using d3 for my project. I'm able to render it. The problem is for SunBurst we always have pass data in a certain format to make it work.
I have a code that takes 4 query data and merges into one. But this is very specific to 1 graph. I want it to be dynamic so that I can interchange their order.
Note: The last data should always hold name and count keys.
function createpayload(name, count){
var x = {
name: name,
count: count,
children: []
}
return x
}
function createpayloads(name, count){
var x = {
name: name,
count: count
}
return x
}
function createPayload(projectType, subProject, status, assignedTo){
var payload = {
name:"My Project",
children:[]
}
payload.children = projectType
payload.children.forEach(element => {
element.children = []
subProject.forEach(val => {
if(element.name == val.projecttype){
element.children.push(createpayload(val.name))
}
})
element.children.forEach((item) => {
status.forEach(valst => {
if(element.name == valst.projecttype && item.name == valst.subproject){
item.children.push(createpayload(valst.name))
}
})
item.children.forEach((items) => {
assignedTo.forEach(valss => {
if(element.name == valss.projecttype && item.name == valss.subproject && items.name == valss.status){
items.children.push(createpayloads(valss.name, valss.count))
}
})
})
})
})
return payload
}
Here this code works but the number of inputs it takes is fixed to 4((projectType, subProject, status, assignedTo). I want this to accept any number of parameter in any order. But if I change the order how to make this dynamic enough to get the desired output?
This the the structure d3 SunBurst Accepts
var nodeData = {
"name": "TOPICS", "children": [{
"name": "Topic A",
"children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
}, {
"name": "Topic B",
"children": [{"name": "Sub B1", "size": 3}, {"name": "Sub B2", "size": 3}, {
"name": "Sub B3", "size": 3}]
}, {
"name": "Topic C",
"children": [{"name": "Sub A1", "size": 4}, {"name": "Sub A2", "size": 4}]
}]
};

Related

Mapping in map in json response

I need to parse json api response, with response.data equals:
[
{
"name": "Programming",
"subcategories": [
{"name": "web-development"},
{"name": "backend-development"},
{"name": "data-scince"}
]
},{
"name": "Design",
"subcategories": [
{"name": "Graphic-design"},
{"name": "Motion-design"},
{"name": "3D modeling"}
]
and I need to return one array[String] with all subcategories, ex ["web-development", "backend-development" ... "3D modeling"]
All that I did is:
let subs = categories.data.map(function(category) {
return category.subcategories.map(function(subcategory) {
return subcategory.name
})
})
and it returns Array of arrays with categories. Im sure, that there near a better and easier way. Thanks!
let data = [{
"name": "Programming",
"subcategories": [{
"name": "web-development"
},
{
"name": "backend-development"
},
{
"name": "data-scince"
}
]
}, {
"name": "Design",
"subcategories": [{
"name": "Graphic-design"
},
{
"name": "Motion-design"
},
{
"name": "3D modeling"
}
]
}]
let subs = data.flatMap(function(category) {
return category.subcategories.map(function(subcategory) {
return subcategory.name
})
})
console.log(subs)
Try using Array flatMap
You can get a flat array by replacing:
categories.data.map
with
categories.data.flatMap

Need to make on object in Javascript based on an existing object which is efficient considering its performance

{
"name": "test name",
"description": "test desc",
"data_table_id": 3,
"column_0": {
"value": "1",
"label": "name"
},
"condition_0": {
"value": "101",
"label": "Is equal to"
},
"column_1": {
"value": "2",
"label": "age"
},
"condition_1": {
"value": "102",
"label": "Is less than"
}
}
I have the above object in JavaScript. From this object I need to create the following object. Need to find a way which is good from performance point of view. The below conditions array is based on the object starting with 'column_' in the above object.
For example: if there are column_0, column_1, column_2, the length of conditions array will be 3. These columns will be coming dynamically, can be from 0-n, n = any integer >= 0. (i.e. column_0 - column_n)
The same condition applies for condition_0, condition_1. Also, condition_0 is always associated with column_0, condition_1 is always associated with column_1 ans so on.
{
"name": "test name",
"description": "test desc",
"data_table_id": 3,
"conditions" : [
{
"column_id": 1, // column_0.value
"column_name": "name", // column_0.label
"condition_id": 101 // condition_0.value
},
{
"column_id": 2, // column_1.value
"column_name": "age", // column_1.label
"condition_id": 102 // condition_1.value
}
],
}
extract the conditions using ...rest, reduce the Object.entries , construct the data structure and push it to the resulting array, finally put everything back together :
const data = {
"name": "test name",
"description": "test desc",
"data_table_id": 3,
"column_0": {
"value": "1",
"label": "name"
},
"condition_0": {
"value": "101",
"label": "Is equal to"
},
"column_1": {
"value": "2",
"label": "age"
},
"condition_1": {
"value": "102",
"label": "Is less than"
}
}
const {
name,
description,
data_table_id,
...rest
} = data;
const conditions = Object.entries(rest).reduce((all, [key, obj]) => {
if (key.startsWith('condition')) {
const id = key.split('_')[1];
const condition = {
"column_id": rest[`column_${id}`].value,
"column_name": rest[`column_${id}`].label,
"condition_id": obj.value,
}
all.push(condition)
}
return all;
}, []);
const result = {
name,
description,
data_table_id,
conditions
}
console.log(result)

Getting Specific data from Nested Json which is having multiple Parent Children

Am trying to filter out some specific data's from Nested JSON which is having multiple Parent Children . Here is my json ,
[{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
What am trying to do here is i have to get some specific data's which are inside this nested json . For Ex : i need output like ["parent","Child","Child-Child"...etc ] . So i used map function using java script but the output was different like this one ["ParentChildChildChild"] (With No spaces) .If output's are String only mean's i can put "\n" and separate them but sometimes they are in Numbers so problem will occur's . Here is my Code which i tried ,
var myReturnedValues = mainSteps.map(x => [
x.steps.map(y => y.name +
y.steps.map(z => z.name +
z.steps.map(a => a.name + a.steps.map(b => b.name))
)
)
]);
Can someone help/clarify Me .
To achieve this most effectively you need To achieve this most effectively you need To achieve this most effectively you need to use recursion use recursion use recursion.
Using this pattern means that the array will always be filled no matter how many levels of nested object you have. Try this:
var data = [{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
var names = [];
function getNames(arr) {
for (var i = 0; i < arr.length; i++) {
names.push(arr[i].name);
if (arr[i].steps && arr[i].steps.length)
getNames(arr[i].steps);
}
}
getNames(data);
console.log(names);
You can achieve this using the javascript map function & recursion
var jsonArray = [{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
var namesArray = [];
var recur = function(obj) {
namesArray.push(obj.name);
if(obj.steps) {
obj.steps.map(recur);
}
}
jsonArray.map(recur);
console.log(namesArray);
You can also try
function getObjectKeyValues(obj, objKey) {
var result = [];
JSON.stringify(obj, function(key, value) {
if (key === objKey) {
result.push(value)
}
return;
});
return result;
}
Check:
MDN JSON.stringify()

Converting into a hierarchical array in javascript

Fiddle Example
I want to convert this JSON data
var data = [
{
"computer": 24,
"brand": "Italy A",
"phone": 0,
"country": "Italy"
},
{
"brand": "Italy C",
"computer": 0,
"phone": 0,
"country": "Italy"
},
{
"brand": "Brazil B",
"computer": 0,
"phone": 22,
"country": "Brazil"
},
{
"computer": 0,
"brand": "Brazil D",
"phone": 62,
"country": "Brazil"
},
{
"computer": 34,
"brand": "US E",
"phone": 41,
"country": "US"
}
];
into a hierarchical form for a d3 graph:
{
"name": "categories",
"children": [
{
"name": "phone",
"children": [
{
"name": "US",
"children": [
{
"brand": "US E",
"size": 41
}
]
},
{
"name": "Brazil",
"children": [
{
"brand": "Brazil B",
"size": 22
},
{
"brand": "Brazil D",
"size": 62
}
]
},
{
"name": "Italy",
"children": []
}
]
},
{
"name": "computer",
"children": [
{
"name": "US",
"children": [
{
"brand": "US E",
"size": 34
}
]
},
{
"name": "Brazil",
"children": []
},
{
"name": "Italy",
"children": [
{
"brand": "Italy A",
"size": 24
}
]
}
]
}
]
}
I came up with this code to generate the format:
function group_children(data){
var categories = ["phone","computer"];
var countries = ["US","Brazil","Italy"];
var object = {name:"categories",children:[]};
for(var c =0; c < categories.length;c++){
object.children.push({"name":categories[c],children:[]});
for(var con = 0;con < countries.length;con++){
object.children[c].children.push({"name":countries[con],"children":[]});
}
}
for(var i = 0;i < data.length;i++){
var row = data[i];
for(var c =0; c < categories.length;c++){
for(var con = 0;con < countries.length;con++){
var cat_key = categories[c],
country_key = countries[con];
if(row[cat_key] > 0){
if(object.children[c].name == cat_key && row.country == country_key){ object.children[c].children[con].children.push({brand:row["brand"],size:row[cat_key]});
}
}
}
}
}
return object;
}
Is it possible , during the iteration, not to push a country into the brand or computer's children array if the country's children array is empty?
For example, these objects should be removed
// computer
{
"name": "Brazil",
"children": []
}
// phone:
{
"name": "Italy",
"children": []
}
Here's the part that push each country into each category's children array:
for(var c =0; c < categories.length;c++){
object.children.push({"name":categories[c],children:[]});
for(var con = 0;con < countries.length;con++){
object.children[c].children.push({"name":countries[con],"children":[]});
}
}
My approach is probably wrong, so any other suggestions converting the data into that hierarchical form is also appreciated.
Check this fiddle, is this what you're looking for? I decided to go for a different approach to the one you followed, hope you don't mind. I've commented the code so that it's clearer:
var result = {
name: "categories",
children: [{
"name": "phone",
"children": []
}, {
"name": "computer",
"children": []
}]
};
$.each(data, function (index, item) {// Go through data and populate the result object.
if (+item.computer > 0) { // Computer has items.
filterAndAdd(item, result.children[1], "computer");
}
if (+item.phone > 0) { // Phone has items.
filterAndAdd(item, result.children[0], "phone");
}
});
function filterAndAdd(item, result_place, type) {// Search and populate.
var i = -1;
$.each(result_place.children, function (index,a) {
if( a.name === item.country ) {
i = index;
return false;
}
});
if (i > -1) {// Country already exists, add to children array.
result_place.children[i].children.push({
"brand": item.brand,
"size": item[type]
});
} else {// Country doesn't exist, create it.
result_place.children.push({
"name": item.country,
"children": [{
"brand": item.brand,
"size": item[type]
}]
});
}
}
Hope it helps.
You have to use d3.nest() function to group array elements hierarchically. The documentation is available
here. Also go through this tutorial which could definitely help you to create hierarchical data.
That's not enough, you get hierarchical data in terms of key and value pairs. But if you want to convert into name and children, already a question on SO is asked, check this.
With your current approach you should iterate the data to find the empty ones, before pushing the countries, which would result in way more iteration than just simply iterating the result at the end to filter the empty ones.
Otherwise you should create the scruture in the same iterations of the data insertion, thus reducing the iterations to 1.

How to get the total depth of an unknown JSON hierarchy?

I've been struggling to find/build a recursive function to parse this JSON file and get the total depth of its children.
The file looks something like this:
var input = {
"name": "positive",
"children": [{
"name": "product service",
"children": [{
"name": "price",
"children": [{
"name": "cost",
"size": 8
}]
}, {
"name": "quality",
"children": [{
"name": "messaging",
"size": 4
}]
}]
}, {
"name": "customer service",
"children": [{
"name": "Personnel",
"children": [{
"name": "CEO",
"size": 7
}]
}]
}, {
"name": "product",
"children": [{
"name": "Apple",
"children": [{
"name": "iPhone 4",
"size": 10
}]
}]
}]
}
You can use a recursive function to go through the whole tree:
getDepth = function (obj) {
var depth = 0;
if (obj.children) {
obj.children.forEach(function (d) {
var tmpDepth = getDepth(d)
if (tmpDepth > depth) {
depth = tmpDepth
}
})
}
return 1 + depth
}
The function works as follow:
If the object is not a leaf (i.e the object has the children attribute), then:
Compute the depth of each child, save the maximal one
return 1 + the depth of the deepest child
Otherwise, return 1
jsFiddle: http://jsfiddle.net/chrisJamesC/hFTN8/
EDIT
With modern JavaScript, the function could look like this:
const getDepth = ({ children }) => 1 +
(children ? Math.max(...children.map(getDepth)) : 0)
jsFiddle: http://jsfiddle.net/chrisJamesC/hFTN8/59/
This will count the number of "leaves" in a tree:
var treeCount = function (branch) {
if (!branch.children) {
return 1;
}
return branch.children.reduce(function (c, b) {
return c + treeCount(b);
}, 0)
}
And an alternative way to get depth:
var depthCount = function (branch) {
if (!branch.children) {
return 1;
}
return 1 + d3.max(branch.children.map(depthCount));
}

Categories