Kr0n0s
Kr0n0s

Reputation: 77

Format data for chart

I'm having some trouble formatting/transforming some simple data into a format that I can use to graph, and I'm hoping someone might help me solve. Currently, I have something like this

somedata= 
    {test1: {good: 3, bad: 2, redo: 2}}
    {test2: {good: 4, bad: 3}}
    {test3: {good: 3, redo: 4}}

into something like

series: 
[{name: "good", data: [3,4,3]}, 
{name: "bad", data: [2,3,0]}, 
{name: "redo", data: [2,0,4]}]

I can grab the categories by using Object.keys(somedata) easy enough i.e. ['test1', 'test2', 'test3'] but having problem formatting the rest of the data. I tried something like

 let combine = {};
                Object.values(somedata).map((row) => {
                    for (const [key, value] of Object.entries(row)) {
                        combine.hasOwnProperty(key)
                            ? combine[key].push(value)
                            : (combine[key] = [value]);
                    }
                    console.log("combined", combine);
                });

but quickly realized that it won't add 0 when key doesn't exist, which is required for the chart to compare between the different series, such as bar charts. So, any help is appreciated.

Upvotes: 0

Views: 88

Answers (2)

Lactose.Int.Robot
Lactose.Int.Robot

Reputation: 81

something like this: for each test, group categories (can optionally restrict to a subset) - assume Zero for missing category

const someData = {test1: {good: 3, bad: 2, redo: 2}, test2: {good: 4, bad: 3}, test3: {good: 3, redo: 4}};

function prepMyGraphData(data, fields) {

    let out = {
    }

    for (const [k, el] of Object.entries(data)) {
        const _fields = new Set((fields || Object.keys(el)).concat(Object.keys(out)));
        for (const f of _fields) {
            const v = el.hasOwnProperty(f) ? el[f] || 0 : 0 ; // own field or 0
            if (out.hasOwnProperty(f)) {
                out[f].data.push(v) // existing category
            }else{
                out[f] = {name: f, data: [v]} // new category entry
            }
        }
    }
    return Object.values(out)
}

let fields = ['good', 'bad', 'redo']; // OR, undefined, for ALL own properties
const data = prepMyGraphData(someData, fields);

Upvotes: 1

Hassan Imam
Hassan Imam

Reputation: 22574

You can first collect all unique values and then using array#reduce and other array methods generate all the values corresponding to each key in an object accumaltor.

const somedata = [{test1: {good: 3, bad: 2, redo: 2}}, {test2: {good: 4, bad: 3}}, {test3: {good: 3, redo: 4}}],
      uniqueValues = [...new Set(
        somedata.reduce((r,o) => {
          Object.values(o).forEach(ob => {
           r.push(...Object.keys(ob));
          });
          return r;
        }, [])
      )];
      result = Object.values(somedata.reduce((r, o) => {
        Object.values(o).forEach(ob => {
          uniqueValues.forEach(k => {
            r[k] = r[k] || { name: k, data: []};
            ob[k] ? r[k].data.push(ob[k]): r[k].data.push(0);
          });
        });
        return r;
      },{}));
      
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions