Reputation: 243
I need help in transforming data. I need to plot a stacked graph. The data which I am getting from the backend is not in chart js form. I need to calculate the percentage of the count of keywords by the same verticalName example (in my case Attrition in BCM is 56.52). Could you please guide me on how to tackle this problem?
const d = [
{
name: 'Attrition',
keywordId: 1,
verticalId: 1,
verticalName: 'BCM',
countOfKeywords: 20,
},
{
name: 'Others',
keywordId: 2,
verticalId: 1,
verticalName: 'BCM',
countOfKeywords: 26,
},
{
name: 'Others',
keywordId: 2,
verticalId: 2,
verticalName: 'CGLR',
countOfKeywords: 24,
},
];
What I tried?
const amp = d.map((a) => {
const vertName = a.verticalName;
if (obj && vertName in obj) {
obj[a.verticalName].sum += a.countOfKeywords;
obj[a.verticalName].keywords.push({ name: a.name, countOfKeyword: a.countOfKeywords });
} else {
obj[a.verticalName] = {};
obj[a.verticalName].keywords = [];
obj[a.verticalName].keywords.push({ name: a.name, countOfKeyword: a.countOfKeywords });
obj[a.verticalName].sum = a.countOfKeywords;
}
});
for (let i in obj) {
obj[i].keywords.forEach(e => {
e.pert = (e.countOfKeyword / obj[i].sum) * 100;
})
}
Output from my code -->
{
"BCM": {
"keywords": [
{
"name": "Attrition",
"countOfKeyword": 20,
"pert": 43.47826086956522
},
{
"name": "Others",
"countOfKeyword": 26,
"pert": 56.52173913043478
}
],
"sum": 46
},
"CGLR": {
"keywords": [
{
"name": "Others",
"countOfKeyword": 24,
"pert": 100
}
],
"sum": 24
}
}
End result what chart js required?
here dataset array consists of objects which includes another data array.
In labels, array 0 index represents BCM same rule applies to data property in datasets. if any name (keyword like attrition or others) are missing for a verticalName. We need to add 0 value in data array in a specific index.
example Attrition is not available in CGLR vertical so we need to add 0 in that index.
{
labels: ['BCM', 'CGLR'],
datasets: [
{
label: 'Attrition',
data: [43.47, 0]
},
{
label: 'Others',
data: [ 56.52, 100]
}
]
}
thanks, meet
Upvotes: 2
Views: 639
Reputation: 2383
My solution will create chartjs data with two steps first step I will create grouping data and template data.
name
and verticalName
with his countOfKeywords
.Second step I will get data from grouping and put it in the template.
Input
const array = [
{
name: 'Attrition',
verticalName: 'BCM',
countOfKeywords: 20,
},
{
name: 'Others',
verticalName: 'BCM',
countOfKeywords: 26,
},
{
name: 'Others',
verticalName: 'CGLR',
countOfKeywords: 24,
},
{
name: 'Attrition',
verticalName: 'NEW',
countOfKeywords: 20,
},
{
name: 'Others',
verticalName: 'NEW',
countOfKeywords: 1,
},
];
After Grouping
{
"BCM": {
"sum": 46,
"keywords": {
"Attrition": 20,
"Others": 26
}
},
"CGLR": {
"sum": 24,
"keywords": {
"Others": 24
}
},
"NEW": {
"sum": 21,
"keywords": {
"Attrition": 20,
"Others": 1
}
}
}
Template
{
"labels": [
"BCM",
"CGLR",
"NEW"
],
"datasets": [
{
"label": "Attrition",
"data": [
0,
0,
0
]
},
{
"label": "Others",
"data": [
0,
0,
0
]
}
]
}
Output
{
"labels": [
"BCM",
"CGLR",
"NEW"
],
"datasets": [
{
"label": "Attrition",
"data": [
43.47826086956522,
0,
95.23809523809523
]
},
{
"label": "Others",
"data": [
56.52173913043478,
100,
4.761904761904762
]
}
]
}
Full code
// input
const array = [
{
name: 'Attrition',
verticalName: 'BCM',
countOfKeywords: 20,
},
{
name: 'Others',
verticalName: 'BCM',
countOfKeywords: 26,
},
{
name: 'Others',
verticalName: 'CGLR',
countOfKeywords: 24,
},
{
name: 'Attrition',
verticalName: 'NEW',
countOfKeywords: 20,
},
{
name: 'Others',
verticalName: 'NEW',
countOfKeywords: 1,
},
];
// declare variables
let uniqueNames = new Set();
const grouping = {};
const template = {
labels: [],
datasets: []
}
// create grouping object and create template labels
for (let i = 0; i < array.length; i += 1) {
const element = array[i];
if (grouping[element.verticalName] === undefined) {
template.labels.push(element.verticalName);
grouping[element.verticalName] = { sum: 0, keywords: {} };
};
grouping[element.verticalName].sum += element.countOfKeywords;
grouping[element.verticalName].keywords[element.name] = grouping[element.verticalName].keywords[element.name] ? grouping[element.verticalName].keywords[element.name] + element.countOfKeywords : element.countOfKeywords
uniqueNames.add(element.name);
}
// uniqueNames Set to Array
uniqueNames = [...uniqueNames];
// create template datasets with 0 percentage
// I did it after first loop because I want to makesure the template.labels.length completed
template.datasets = uniqueNames.map(label => ({ label, data: new Array(template.labels.length).fill(0) }));
// target for now create grouping & create template with labels and 0 percentages
// console.log(JSON.stringify(grouping, null, 2));
// console.log(JSON.stringify(template, null, 2));
// calculate the percentages
for (let i = 0; i < template.datasets.length; i++) {
const uniqueName = uniqueNames[i];
for (let j = 0; j < template.labels.length; j++) {
const label = template.labels[j];
if (grouping[label].keywords[uniqueName] === undefined) {
template.datasets[i].data[j] = 0;
} else {
template.datasets[i].data[j] = grouping[label].keywords[uniqueName] / grouping[label].sum * 100;
}
}
}
// output
console.log(JSON.stringify(template, null, 2));
UPDATE
More optimized code by skip add datasets to template before second loop
// input
const array = [
{
name: 'Attrition',
verticalName: 'BCM',
countOfKeywords: 20,
},
{
name: 'Others',
verticalName: 'BCM',
countOfKeywords: 26,
},
{
name: 'Others',
verticalName: 'CGLR',
countOfKeywords: 24,
},
{
name: 'Attrition',
verticalName: 'NEW',
countOfKeywords: 20,
},
{
name: 'Others',
verticalName: 'NEW',
countOfKeywords: 1,
},
];
// declare variables
let uniqueNames = new Set();
const grouping = {};
const template = {
labels: [],
datasets: []
}
// create grouping object and create template labels
for (let i = 0; i < array.length; i += 1) {
const element = array[i];
if (grouping[element.verticalName] === undefined) {
template.labels.push(element.verticalName);
grouping[element.verticalName] = { sum: 0, keywords: {} };
};
grouping[element.verticalName].sum += element.countOfKeywords;
grouping[element.verticalName].keywords[element.name] = grouping[element.verticalName].keywords[element.name] ? grouping[element.verticalName].keywords[element.name] + element.countOfKeywords : element.countOfKeywords
uniqueNames.add(element.name);
}
// uniqueNames Set to Array
uniqueNames = [...uniqueNames];
// target for now create grouping & create template with labels and without datasets
// console.log(JSON.stringify(grouping, null, 2));
// console.log(JSON.stringify(template, null, 2));
// add datasets
// calculate the percentages
for (let i = 0; i < uniqueNames.length; i++) {
const uniqueName = uniqueNames[i];
template.datasets.push({ label: uniqueName, data: [] })
for (let j = 0; j < template.labels.length; j++) {
const label = template.labels[j];
if (grouping[label].keywords[uniqueName] === undefined) {
template.datasets[i].data[j] = 0;
} else {
template.datasets[i].data[j] = grouping[label].keywords[uniqueName] / grouping[label].sum * 100;
}
}
}
// output
console.log(JSON.stringify(template, null, 2));
Upvotes: 1