0

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.

user15187712
  • 57
  • 1
  • 5

1 Answers1

0

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
    }
  ])
);
tperamaki
  • 1,028
  • 1
  • 6
  • 12
  • technically this works, however there is an issue where the chart displays all the empty datasets. What I've noticed is that datasets contains arrays, when really it should have objects with a labels property and data property, where the data property is an array. – user15187712 Jul 01 '21 at 22:18
  • You can filter out those where there are no entries at all. For example change the row where `conArr` and `canArr` is set to something like: `let conArr = constituencies.filter((con) => data.some((entry) => entry.constituencyId === con.constituencyId)).map((con) => con.name);`. And to optimise it you should only do it once and use that for both rows. – tperamaki Jul 02 '21 at 06:50
  • Indeed, with some additional modification I got it work. It's not well optimized but it will work for now. Thank you – user15187712 Jul 02 '21 at 13:23