Search code examples
javascriptreactjsd3.jsreact-d3

D3.extent() throws TypeError : Values is not iterable


I have been scratching my head over this for the past three hours, if anyone can help, please do. I am not very adept at D3 in combination with React.

So, basically, I have an anomaly detector algorithm running in the backend Flask App which returns values in form of a dictionary (then converted to json object via json.dumps()) that will, further, be plotted on my React app using D3.

Initially, I thought the problem was with my Database because the app was working perfectly on codesandbox and in all my prior versions.

This is what the console.log(data) looks like : enter image description here

I was told that a problem could be with the varying data points for A_Epoch(3) and Time_Epoch(151). Having resolved that didn't help either.

This is what the code looks like:

const timeDomain = d3.extent(data, d=>(d.Time_Epoch*1000));
const bytesReadDomain = d3.extent(data, (d) => d.Bytes_Read);
const bytesWriteDomain = d3.extent(data, (d) => d.Bytes_Write);
const bytesSentDomain = d3.extent(data, (d) => d.Bytes_Sent);
const bytesRecvDomain = d3.extent(data, (d) => d.Bytes_Recv);

This part is throwing error.


Solution

  • data is an object, not an array.

    d3.extent expects an array as the first argument, with the second function in d3.extent being an optional key function. That function is executed for every array element. So for example if you have an array of complex objects, with every object having an id, you can use the following:

    const data = [{
      id: 1,
    }, {
      id: 2,
    }];
    
    console.log(d3.extent(data, (d) => d.id));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

    You actually have an object, where the values are numerical arrays. So instead of

    const bytesReadDomain = d3.extent(data, (d) => d.Bytes_Read);
    

    you should just use

    const bytesReadDomain = d3.extent(data.Bytes_Read);
    

    This is equivalent to d3.extent([0, 1, 2, 3, 4]), and doesn't require a key function.


    For Time_Epoch, where you want to multiply all values times 1000, just use Array.prototype.map to apply the same function to all array elements, before calling d3.extent():

    d3.extent(data.Time_Epoch.map((d) => d * 1000);