Search code examples
javascriptreactjsnext.jschart.jsreact-chartjs

Display JSON data in react-chartjs-2


I have JSON data that gets returned from the backend in the following format:

[
   0: {
       candidateId: "1",
       constituencyId: "2",
       count: 50
   },
   1: {
       candidateId: "2",
       constituencyId: "2",
       count: 20
   }
]

I want to display the above in a bar chart and have constituencyId as the labels on the x axis, candidateId as the dataset and count as the values.

constituencyId refers to a location and it can have up to 4 persons in this case, so I'm trying to figure out how to display it on the chart.

This is what I've done so far:

const generateGraph = (data) => {
    let conArr = [];
    let canArr = [];
    data.forEach((d) => {

        // get the names of the constituencies that are in data
        // each constituency is a label for the chart
        constituencies.forEach((con) => {
            if (con.constituencyId === d.constituencyId) {
                if (!conArr.includes(con.name)) {
                    conArr.push(con.name);
                }
            }
        });

        // get the names of the candidates that are in data
        // each candidate is a dataset object for the chart
        candidates.forEach((can) => {
            if (can.candidateId === d.candidateId) {
                canArr.push({
                    label: can.lastName + ", " + can.firstName,
                    data: [d.count], // problem in this line
                });
            }
        });
    });

    const chartData = {
        labels: conArr,
        datasets: canArr,
    };

    return chartData;
};

The issue with the above code is that, the line where I set the data value in the dataset (data: [d.count]), if I add another candidate but from a different constituency, the count is displayed for the first label/constituency.

What happens:

labels = ["A", "B"]
datasets = [{ label: "Person 1", data: [1] }, { label: "Person 2", data: [1] }]

So what should happen is, I should see 1 bar for the first constituency and another bar for the other constituency but what I'm getting is 2 bars for the first constituency and none for the other.

What should happen:

labels = ["A", "B"]
datasets = [{ label: "Person 1", data: [1] }, { label: "Person 2", data: [0,1] }]

Each persons data should correspond to the appropriate label in labels

I do know that the values for the datasets are done based on the index of the labels, but I'm not sure how I would write this.


Solution

  • Would this work for you? A bit different approach on going through the data.

    https://codesandbox.io/s/vigilant-faraday-4n1nb?file=/src/index.js

    const constituencies = [
      { constituencyId: "1", name: "A" },
      { constituencyId: "2", name: "B" }
    ];
    const candidates = [
      { candidateId: "1", lastName: "Person", firstName: "1" },
      { candidateId: "2", lastName: "Person", firstName: "2" }
    ];
    
    const generateGraph = (data) => {
      let conArr = constituencies.map((con) => con.name);
      let canArr = constituencies.map((con, index) =>
        data
          .filter((entry) => entry.constituencyId === con.constituencyId)
          .map((entry) => {
            const candidate = candidates.find(
              (can) => can.candidateId === entry.candidateId
            );
            if (candidate === null) {
              return null;
            }
            return {
              label: candidate.lastName + ", " + candidate.firstName,
              data: new Array(index).fill(0).concat([entry.count])
            };
          })
      );
    
      const chartData = {
        labels: conArr,
        datasets: canArr
      };
    
      return chartData;
    };
    
    console.log(
      generateGraph([
        {
          candidateId: "1",
          constituencyId: "2",
          count: 50
        },
        {
          candidateId: "2",
          constituencyId: "2",
          count: 20
        }
      ])
    );