I am currently unable to sort the datasets that shown in each stacked bars in descending order; they are currently displaying randomly. Here is my current code
import React from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from 'chart.js';
import { Bar } from 'react-chartjs-2';
import { claimStatues, demoClaimsValue, generateMockData } from './data.mock';
import { stackedBarChartOptions } from './Barchart.options';
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
);
const xLabels = [
'In-patient',
'Out-patient',
'Dental',
'Vision',
'Vaccination',
'Total permanent disability',
'Critical illness',
'Accident',
'Maternity',
'Death',
'Others',
];
const dataPoints = [
{
label: 'Received',
data: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
backgroundColor: '#1F659F',
},
{
label: 'Rejected',
data: [20, 30, 10, 60, 70, 60, 70, 80, 90, 100],
backgroundColor: '#F44336',
},
{
label: 'Processing',
data: [30, 10, 20, 80, 90, 60, 70, 80, 90, 100],
backgroundColor: '#FFC107',
},
{
label: 'Approved',
data: [40, 10, 20, 80, 90, 60, 70, 80, 90, 100],
backgroundColor: '#4CAF50',
},
{
label: 'Custom',
data: [50, 10, 20, 80, 90, 60, 70, 80, 90, 100],
backgroundColor: '#00BCD4',
},
];
export const data = {
labels: xLabels,
datasets: dataPoints.map((dataPoint) => ({
...dataPoint,
})),
};
/**
*
* generateMockData({
columns: demoClaimsValue,
statues: claimStatues,
}),
*/
export default function BarChart() {
return (
<div className="relative bg-white">
<Bar options={stackedBarChartOptions} data={data} />
</div>
);
}
Here is the package json
{
"name": "rws-econcierge-cms",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"dev:prod": "env-cmd -f .env.prod next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"export": "next build && next export",
"build:prod": "env-cmd -f .env.prod yarn build"
},
"dependencies": {
"@faker-js/faker": "^8.3.1",
"@fullcalendar/core": "^6.1.9",
"@fullcalendar/daygrid": "^6.1.9",
"@fullcalendar/interaction": "^6.1.9",
"@fullcalendar/react": "^6.1.9",
"@heroicons/react": "^2.0.18",
"@hookform/resolvers": "^2.9.8",
"@tanstack/react-query": "^4.3.9",
"@tanstack/react-query-devtools": "^4.32.6",
"antd": "^5.8.0",
"axios": "^0.27.2",
"chart.js": "^4.4.1",
"class-variance-authority": "^0.7.0",
"classnames": "^2.3.2",
"date-fns": "^2.29.3",
"date-fns-tz": "^1.3.7",
"dayjs": "^1.11.9",
"dnd-core": "^16.0.1",
"dompurify": "^3.0.6",
"draft-js": "^0.11.7",
"draftjs-to-html": "^0.9.1",
"env-cmd": "^10.1.0",
"file-saver": "^2.0.5",
"immutability-helper": "^3.1.1",
"jszip": "^3.10.1",
"next": "12.3.0",
"qs": "^6.11.0",
"react": "18.2.0",
"react-chartjs-2": "^5.2.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "18.2.0",
"react-draft-wysiwyg": "^1.15.0",
"react-hook-form": "^7.35.0",
"react-quill": "^2.0.0",
"recoil": "^0.7.5",
"recoil-persist": "^4.2.0",
"underscore": "^1.13.6",
"validator": "^13.11.0",
"yup": "^1.2.0"
},
"devDependencies": {
"@types/file-saver": "^2.0.6",
"@types/node": "18.7.18",
"@types/qs": "^6.9.7",
"@types/react": "18.0.20",
"@types/react-dom": "18.0.6",
"@types/underscore": "^1.11.9",
"@types/validator": "^13.11.5",
"autoprefixer": "^10.4.11",
"eslint": "8.23.1",
"eslint-config-next": "12.3.0",
"postcss": "^8.4.16",
"prettier": "^3.0.2",
"prettier-plugin-tailwindcss": "^0.5.3",
"tailwindcss": "^3.1.8",
"typescript": "4.8.3"
}
}
I notice that the issues might be related to the data structure that i am using currently
Below is the screen short to reference
The bars are never displayed randomly; the image you attached shows that each stack has the bars in the same order, the order in which you defined datasets array: 'Received' at the bottom, then 'Approved', ..., and at the top 'Rejected' (obviously, some bars are not visible if the corresponding value is too small or zero).
The colours follow each other in the same order in the stack; this is also the order of the items in the legend. This is the how stacked bars are expected to behave; users also expect that and can easily read such a chart. You can't change this order by a mapping of data.
If you want to change the order of the bars as to sort them by their values, you could use floating bars; you have to disable scales.y.stacked
option (default is false
) and specify for each item both two numbers in an array: its base and its top.
Here's an example of that approach with a sort
of the data in your post.
const xLabels = [
'In-patient',
'Out-patient',
'Dental',
'Vision',
'Vaccination',
'Total permanent disability',
'Critical illness',
'Accident',
'Maternity',
'Death',
'Others',
];
const dataPoints = [
{
label: 'Received',
data: [20, 20, 30, 40, 50, 60, 70, 80, 90, 100],
backgroundColor: '#1F659F',
},
{
label: 'Rejected',
data: [20, 30, 10, 60, 70, 60, 70, 80, 90, 100],
backgroundColor: '#F44336',
},
{
label: 'Processing',
data: [30, 10, 20, 80, 90, 60, 70, 80, 90, 100],
backgroundColor: '#FFC107',
},
{
label: 'Approved',
data: [40, 10, 20, 80, 90, 60, 70, 80, 90, 120],
backgroundColor: '#4CAF50',
},
{
label: 'Custom',
data: [50, 10, 20, 80, 90, 60, 70, 80, 90, 100],
backgroundColor: '#00BCD4',
},
];
const datasets = dataPoints.map((dataPoint) => ({
...dataPoint,
})); // if they need to be copied
datasets[0].data.forEach((_, datasetIndex)=>{ // all .data arrays should have equal length for this to work
const all_i = datasets.map((d, dataIndex)=>[d.data[datasetIndex], dataIndex])
.sort(([data1], [data2]) => data1 - data2);
let sum = 0;
all_i.forEach(
([data, datasetIdx]) => {
datasets[datasetIdx].data[datasetIndex] = [sum, sum + data];
sum = sum + data;
}
);
});
const data = {
labels: xLabels,
datasets,
};
const config = {
type: 'bar',
data: data,
options: {
responsive: true,
scales:{
x: {
stacked: true,
},
// y:{
// stacked: true
// }
},
},
};
new Chart(document.querySelector('#chart1'), config);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js" integrity="sha512-ZwR1/gSZM3ai6vCdI+LVF1zSq/5HznD3ZSTk7kajkaj4D292NLuduDCO1c/NT8Id+jE58KYLKT7hXnbtryGmMg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div style="min-height: 60vh">
<canvas id="chart1">
</canvas>
</div>