0

I hesitate to post this as I've made no significant progress. I should probably step away for a day. I am attempting to average values by date for use in HighStock charts. The data is in the form of json. The issue arises when I have two sets of data on the same day, I need to average these values based on the date. On a given day there may be 0,1, or 2 values. Days with no values need to be null rather than 0 so there highstock will show the gap. I have been trying to work on a js solution to the problem. Conceptually this seems very easy; group by date, sum and divide by the length. But I have not made good progress. Here is a fiddle without my blunders. Any assistance or nudge in the right direction is appreciated.

    {
"nfdrs": {
    "row": [{
        "@num": "141",
        "sta_id": "350920",
        "sta_nm": "HEHE 1",
        "latitude": "44.9559",
        "longitude": "-121.4991",
        "nfdr_dt": "08\/10\/2016",
        "nfdr_tm": "13",
        "nfdr_type": "O",
        "mp": "1",
        "msgc": "7C2P2",
        "one_hr": "5",
        "ten_hr": "6",
        "hu_hr": "11",
        "th_hr": "10",
        "xh_hr": "8",
        "ic": "28",
        "kbdi": "304",
        "sc": "8",
        "ec": "14",
        "bi": "27",
        "sl": "3-",
        "lr": "0",
        "lo": "0",
        "hr": "0",
        "ho": "0",
        "fl": "19",
        "hrb": "60",
        "wdy": "78",
        "adj": "M"
    }, {
        "@num": "142",
        "sta_id": "352108",
        "sta_nm": "WARM SPRINGS BASE",
        "latitude": "44.7795",
        "longitude": "-121.2501",
        "nfdr_dt": "08\/10\/2016",
        "nfdr_tm": "13",
        "nfdr_type": "O",
        "mp": "1",
        "msgc": "7A2A2",
        "one_hr": "5",
        "ten_hr": "6",
        "hu_hr": "8",
        "th_hr": "8",
        "xh_hr": "3",
        "ic": "19",
        "kbdi": "587",
        "sc": "34",
        "ec": "2",
        "bi": "22",
        "sl": "2",
        "lr": "0",
        "lo": "0",
        "hr": "0",
        "ho": "0",
        "fl": "16",
        "hrb": "5",
        "wdy": "60",
        "adj": "L"
    }, 

And, how to do I control the size of that code sample while including all of the code>

2
  • From the JSFiddle I can see that the key nfdr_dt is the date. What about the keys to the values? Which value do I average? Commented Aug 29, 2016 at 0:14
  • Sorry, i am trying to average ec in the json, it is erc in the js. Thank you for taking look. Commented Aug 29, 2016 at 0:30

2 Answers 2

2

I guess your main question is "how do I pro grammatically perform a groupBy on 2 different dataset".

There are many ways you can do this. One way is to use the reduce function to merge the 2 datasets into one complete one.

Example:

function printAverage(data) {
  for (var time in data) {
    // Do ec
    var ec_totalValue = 0;
    data[time].ec_values.forEach(value => { ec_totalValue += value; });
    var ec_average = ec_totalValue / data[time].ec_values.length;

    // do erc
    var erc_totalValue = 0;
    data[time].erc_values.forEach(value => { erc_totalValue += value; });
    var erc_average = erc_totalValue / data[time].erc_values.length;

    console.log("Time => " + time + ", average EC => " + ec_average + ", average ERC =>" + erc_average);
  }
}

function getEpochTime(dateStr) {
  return Date.parse(dateStr);
}

function hasDataForDate(dataset, epochTime) {
  return dataset.hasOwnProperty(epochTime);
}

function addValue(dataset, item) {
  var epochKey = getEpochTime(item.nfdr_dt);
  if (!hasDataForDate(dataset, epochKey)) {
    dataset[epochKey] = {};
    dataset[epochKey].ec_values = [];
    dataset[epochKey].erc_values = [];
  }
  if (item.ec) dataset[epochKey].ec_values.push(parseInt(item.ec));
  if (item.erc) dataset[epochKey].erc_values.push(parseInt(item.erc));

  return dataset;
}

function groupRows(data) {
  return data.reduce(addValue, {});
}

var data =
{
  "nfdrs": {
    "row": [
      {
        "@num": "141",
        "sta_id": "350920",
        "sta_nm": "HEHE 1",
        "latitude": "44.9559",
        "longitude": "-121.4991",
        "nfdr_dt": "08\/10\/2016",
        "nfdr_tm": "13",
        "nfdr_type": "O",
        "mp": "1",
        "msgc": "7C2P2",
        "one_hr": "5",
        "ten_hr": "6",
        "hu_hr": "11",
        "th_hr": "10",
        "xh_hr": "8",
        "ic": "28",
        "kbdi": "304",
        "sc": "8",
        "ec": "14",
        "erc": "80",
        "bi": "27",
        "sl": "3-",
        "lr": "0",
        "lo": "0",
        "hr": "0",
        "ho": "0",
        "fl": "19",
        "hrb": "60",
        "wdy": "78",
        "adj": "M"
      },
      {
        "@num": "142",
        "sta_id": "352108",
        "sta_nm": "WARM SPRINGS BASE",
        "latitude": "44.7795",
        "longitude": "-121.2501",
        "nfdr_dt": "08\/10\/2016",
        "nfdr_tm": "13",
        "nfdr_type": "O",
        "mp": "1",
        "msgc": "7A2A2",
        "one_hr": "5",
        "ten_hr": "6",
        "hu_hr": "8",
        "th_hr": "8",
        "xh_hr": "3",
        "ic": "19",
        "kbdi": "587",
        "sc": "34",
        "ec": "2",
        "erc": "100",
        "bi": "22",
        "sl": "2",
        "lr": "0",
        "lo": "0",
        "hr": "0",
        "ho": "0",
        "fl": "16",
        "hrb": "5",
        "wdy": "60",
        "adj": "L"
      }]
  }
};

var grouped = groupRows(data.nfdrs.row);
printAverage(grouped);

Essentially what the code does is that it loops through the data row and check if the "merged dataset" has already got that key defined.

If it has then the code simply just pushes the values of that row into the value array. Otherwise it defines a JS {} object and adds it under that key and then pushes the row value to it.

For more example usages of reduce and what it is.

See:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Sign up to request clarification or add additional context in comments.

14 Comments

@pcLoadLetter let me know if this works for you or if there is any thing you don't understand
Thank you Samuel. This seems to be averaging for the entire dataset? I'm looking for the average for ec or erc for each day. Usually there are two values, rarely there is only 1 or even 0 on occasion. Originally my code would return the epoch date from nfdr_dt and the erc from ec in json. This would look like: [[1464764400000, 26], [1464764400000, 4]] I would like this to return one date and an average of the two number: [[1464764400000, 15]] Thank you for the reference to Reduce. I have read it before, but it may make more sense now.
@pcLoadLetter maybe I am missing something. My code is calculating the average ec value for a particular day, that is 8/10/2016. which is 14 + 2 / 2
How did you derive value 26 and 4? Using your dataset above the ec value was 14 and 2.
You are correct. Sorry I have too may datasets open. I see now! I did not understand. standby, let me look at this more closely. Apologies.
|
1

The thing you're looking for can be solved through using objects (or 2 arrays)... Here's the example with objects:

$(document).ready(function() {
     $("#driver").click(function(event) {
    $.getJSON("", function(json) {

       // USE objects instead of array
       var tempObj = {};
       JSONData.nfdrs.row.forEach(function(item) {
       var erc = item.ec;
       // before adding check if the date value is already present
       if(!tempObj.hasOwnProperty(item.nfdr_dt)) {
              tempObj[item.nfdr_dt] = parseInt(erc);
          }else {
       // if present it means that the date has other value.. so  concat both the values by a UNIQUE seperator
               tempObj[item.nfdr_dt] = tempObj[item.nfdr_dt]  +'--'+parseInt(erc);
          }
                });       
        // Now proccess the object and wherever we find the string -- we can safely assume that its an extra value
        var newObj = {};
        Object.keys(tempObj).map(function(key){
           if(typeof(tempObj[key])=='string' && tempObj[key].indexOf('--') > -1) {            //use the function to convert string with unique seperator to int 
             newObj[key] = avg(tempObj[key]) ;
           }else{
           newObj[key]  = tempObj[key] ;}
        });
        $('#stage').html('<p> date: ' +  JSON.stringify(newObj) + '</p>');

    });
  });
});

//function to convert string with ints and unique separator to average of strings
function avg(val) {
    var arr = val.split('--');
    var sum =arr.reduce(function(p, c) {return parseInt(p) +parseInt( c);});
    return sum/arr.length;
}

Working fiddle: https://jsfiddle.net/80Lfqmur/11/

1 Comment

Thank you Nishanth. I will try to incorporate this into my chart and see what happens.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.