Iterate trought array and create a chart

Hello,

I would like to create a simple node that will read data from API and build a graph. Now I am stuck on pushing the data to the chart array. Can't find what is the problem here.

I'm quite new in programming, sorry if this topic is quite simple :slight_smile:

Here is my code:

var test_obj = [{ "Received": 1667342689, "OperationState": 3, "BatterySoC": 36 }, { "Received": 1667342749, "OperationState": 3, "BatterySoC": 20 }];

var all_keys = Object.keys(test_obj[0]);


/*

CHART VARIABLE SHOULD BE LIKE THIS:

var chart = [{
    "series": ["OperationState", "BatterySoC"],
    "data": [[{"x":1667342689, "y":3 },{"x":1667342749, "y":3}],    //Operation State
             [{"x":1667342689, "y":36},{"x":1667342749, "y":20}]],  //BatterySoC
             
    "labels": ["OperationState", "BatterySoC"]
}];
*/



var chart = [{
    "series": [],
    "data": [],
    "labels": []
}];

for (var i = 1; i < all_keys.length; i++) {

    chart[0].series.push(all_keys[i]);
    chart[0].data.push([]);
    chart[0].labels.push(all_keys[i]);
}


for (var j=0; j < test_obj.length; j++) {
    var temp_array = Object.entries(test_obj[j]);
    
    for (var k=1; k < temp_array.length; k++) {

        
        var example = { "x": temp_array[0][1], "y": temp_array[k][1] };
        chart[0].data[k].push(example);                                  //Can't push data to the chart variable here
        
    }
}

msg.payload = chart;

return msg;

Welcome to the forum @Viktor

Does your api give you a batch of historical data or are you trying to draw the chart as it happens?

You have not shown us what the incoming data look like. See this canned text for how you can display the data in the debug window and then copy/paste a selection of it here for us to look at:

There’s a great page in the docs (Working with messages : Node-RED) that will explain how to use the debug panel to find the right path to any data item.

Pay particular attention to the part about the buttons that appear under your mouse pointer when you over hover a debug message property in the sidebar.

BX00Cy7yHi

1 Like

The map function is your friend here.

Since your data is nicely typed { "Received": 1667342689, "OperationState": 3, "BatterySoC": 36 } you can map them almost directly into the chart data...

const test_obj = [{ "Received": 1667342689, "OperationState": 3, "BatterySoC": 36 }, { "Received": 1667342749, "OperationState": 3, "BatterySoC": 20 }];

const chart = [{
    "series": ["OperationState", "BatterySoC"],
    "data": [ 
        test_obj.map(e => { return { x: e.Received, y: e.OperationState } }), //Operation State
        test_obj.map(e => { return { x: e.Received, y: e.BatterySoC } })      //BatterySoC
    ],   
    "labels": ["OperationState", "BatterySoC"]
}];

msg.payload = chart;
return msg;

image

1 Like

Your k for loop starts at 1 but chart[0].data only has [0] initialised, you are trying to push to an undefined array element.

maybe something like this would work better.

const test_array = [
    { "Received": 1667342689, "OperationState": 3, "BatterySoC": 36 },
    { "Received": 1667342749, "OperationState": 3, "BatterySoC": 20 }];

let chart_keys = Object.keys(test_array[0]); 
chart_keys.splice(chart_keys.indexOf("Received"),1) //remove received
let data = [];

chart_keys.forEach((str,index) => {
    data[index] = []; // initialise array
    test_array.forEach(obj => {
        data[index].push( { "x": obj.Received * 1000, "y": obj[str] })
    })
})

msg.payload = [{
    "series": chart_keys,
    "data": data,
    "labels": chart_keys
}];

return msg;
1 Like

Thank you, guys!
Finally, after several days of my attempts, it's working :slight_smile:

@E1cid your solution works fine, thank you! Your code looks much better, but a bit complicated for me, at least for now :slight_smile: Will try to figure out how it works!

Thank you and have a nice evening :slight_smile: