Labels for Nested Doughtnut Chart React ChartJS - reactjs

I am trying to implement nested Doughnut using React-ChartJS-2 but the label seem not to appear correctly in the Outer Doughnut.
Here is what I tried after checking out many examples online.
The version I use for chart.js is ^3.7.1 and ^4.1.0 for react-chartjs-2
import React from "react";
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
import { Doughnut } from "react-chartjs-2";
ChartJS.register(ArcElement, Tooltip, Legend);
const DoughnutChart = ({ xLabels, yData, titleText }) => {
console.log(xLabels);
console.log(yData);
const options = {
responsive: true,
rotation: 270,
circumference: 180,
maintainAspectRatio: true,
animation: false,
legend: {
display: false,
},
plugins: {
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
console.log(tooltipItem.datasetIndex);
var dataset = data.datasets[tooltipItem.datasetIndex];
var index = tooltipItem.index;
return dataset.labels[index] + ": " + dataset.data[index];
},
},
},
},
};
const data = {
labels: ["Time elapsed", "Time remaining"],
datasets: [
{
labels: ["Total Time"],
label: "D1",
data: [5],
backgroundColor: ["rgb(80, 170, 80)", "#ccc"],
},
{
label: "D2",
labels: ["Time elapsed", "Time remaining"],
data: [3.2, 1.3],
backgroundColor: ["goldenrod", "#cccff"],
},
],
};
return (
<div style={{ position: "relative", margin: "auto", width: "80%" }}>
<Doughnut data={data} options={options} />
</div>
);
};
export default DoughnutChart;
The outer doughnut "1" label should be Time elapsed: 5 (does not show correct label)
The inner doughnut "2" label should be Time elapsed: 3.2 and "3" should be Time remaining: 1.3 (correct label is shown)
I expect the outer doughnut label to show Total Time: 5 but I see Time elapsed: 5. How do I fix it or what am I doing wrong ?
By the way, I try to use the call back to update the label but it seems not to work.

For those facing similar issue, to name individual doughnut chart based on separate data within the dataset, I updated the callbacks for the tooltip like so:
plugins: {
tooltip: {
enabled: true,
callbacks: {
label: (tooltipItem) => {
var dataIndex = tooltipItem.dataIndex;
return (tooltipItem.dataset.labels[dataIndex] + ": " + tooltipItem.dataset.data[dataIndex]
);
}
}
}
}
Note: For Chart.js 3, "context" parameter can also be used instead of tooltipItem.

Related

antd chart in React: shrinks when global state changes

I have a simple antd bar chart within my React app. First it gets displayed fine, but when the user interacts with the website (and changes the global state) sometimes all of a sudden the chart shrinks.
I tried memoizing the chart and wrapped the component with memo() so that no state change in a parent component affects the chart but that did not help either.
As you can see the canvas has the correct dimensions but the chart drawn on that canvas is not filling it up anymore. The chart should be as big as the lightblue box:
import { memo } from 'react';
import { Column } from '#ant-design/plots';
import theme from '#themes/antd.charts.json';
const Chart = memo(({ data, type }) => {
const chartConfig = {
data,
loading: data.length === 0,
theme,
xField: 'type',
yField: 'value',
seriesField: 'type',
yAxis: {
label: {
formatter: (v) => numeral(v).format('0,0'),
},
},
xAxis: false,
height: 300,
appendPadding: 16,
legend: {
position: 'bottom',
flipPage: false,
itemWidth: 580 / 5, //todo: make dynamic depending on width/count
},
interactions: [
{
type: 'element-active',
},
],
label: {
position: 'top',
offsetY: 8,
formatter: ({ value }) =>
`${numeral(value).format('0,0')} ${type === 'hectare' ? `ha` : ``}`,
},
};
return <Column {...chartConfig} />;
});

react-chartjs-2 options are not recognized for Bars

I am trying to built a barchart component via "react-chartjs-2". I did pretty much paste my code from here: https://www.c-sharpcorner.com/article/create-different-charts-in-react-using-chart-js-library/.
This is how it looks:
import React from 'react';
import {Bar} from "react-chartjs-2";
const BarChart = () => {
const barChartData = {
labels: ["October", "November", "December"],
datasets: [
{
data: [8137119, 9431691, 10266674],
label: "Infected People",
borderColor: "#3333ff",
backgroundColor: "#547db4",
fill: true
},
{
data: [1216410, 1371390, 1477380],
label: "Deaths People",
borderColor: "#ff3333",
backgroundColor: "#f7813e",
fill: true
}
]
};
const barChart = (
<Bar
type="bar"
width={130}
height={50}
options={{
title: {
display: true,
text: "COVID-19 Cases of Last 3 Months",
fontSize: 15
},
legend: {
display: true, //Is the legend shown?
position: "bottom" //Position of the legend.
}
}}
data={barChartData}
/>
);
return barChart;
};
export default BarChart
Everything seems to be working fine, besides the fact that the options prop is not being recognized by the code.
Did anyone come across a similar issue and can help me out?
Update options prop as bellow.
options = {{
plugins: {
title: {
display: true,
text: "COVID-19 Cases of Last 3 Months"
},
legend: {
display: true,
position: "bottom"
}
}
}}

Chartjs React Typescript moving x axis labels above chart

I'm using chartjs to generate a bar chart, and one of the requirements is to have the x-axis labels appear at the top of the chart rather than the bottom. (Even though I disagree with this, apparently there is no leeway from the client) and I'm having trouble following the documentation and any examples I find are for older versions.
The relative packages I'm using are:
"chart.js": "^3.7.1",
"react-chartjs-2": "^4.0.0",
Secondly they want the labels to wrap rather being a single line based on bar width, since it's responsive. I was experimenting with using arrays to break up the words as an example, but wondering if this can be done within chartjs. Here is the code I have setup so far (I had to use some lorem ipsum cause of sensitive data):
import * as React from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
ChartOptions
} from 'chart.js';
import { Bar } from 'react-chartjs-2';
import { Chart } from 'react-chartjs-2';
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);
// added as an example. if there is a negative value, the bar color changes.
const generateBgColors = (data : number[]) => {
const bgColors = [];
for(let i = 0; i < data.length; i++) {
const value = data[i];
if(value > 0) {
bgColors.push('rgba(53, 162, 235, 0.5)');
} else {
bgColors.push('rgba(255, 99, 132, 0.5)');
}
}
return bgColors;
}
const options = {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: false
}
},
scales: {
}
}
var data = [2.0, -2.0, 0.5, 1.5];
const labels = [
['Lorem ipsum dolor sit amet,', ' consectetur adipiscing elit.', ' Integer eget auctor felis.'],
['label2'],
['label3'],
['label4'],
];
const chartData = {
labels: labels,
datasets: [
{
data: [2.0, -2.0, 0.5, 1.5],
backgroundColor: generateBgColors(data)
}
]
}
const BeliefsChart : React.FunctionComponent = (props) => {
const chartRef = React.useRef<ChartJS>(null);
return (
<React.Fragment>
<Chart type="bar" ref={chartRef} options={options} data={chartData} height={50} />
</React.Fragment>
);
}
To make the labels appear on top in V3 of chart.js you need to specify the position to top in options.scales.x like so:
options: {
scales: {
x: {
position: 'top'
}
}
}
To achieve multi line labels you will need to define your labels array as arrays for the the labels that have to be multi lined. Each entry in the nested arrray will be a new line
labels = ['singel line', ['line 1', 'line 2'], ['line 1', 'line 2', 'line3']]
Live Example:
const options = {
type: 'bar',
data: {
labels: ['singel line', ['line 1', 'line 2'], ['line 1', 'line 2', 'line3']],
datasets: [{
label: '# of Votes',
data: [12, 19, 3],
backgroundColor: 'orange'
},
{
label: '# of Points',
data: [7, 11, 5],
backgroundColor: 'pink'
}
]
},
options: {
scales: {
x: {
position: 'top'
}
}
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>
Apologies in advance since I'm not familiar with Typescript, but hopefully the following answers will be of help to you regardless.
To position the x-axis labels, try adding the following scales details to your options:
const options = {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: false
}
},
scales: {
xAxes: [{
position: "top"
}]
}
}
I don't know if it's possible to make the labels wrap, but an alternative responsive solution might be to use a variable for the fontSize of the ticks (labels) and vary the fontSize value based on the size of the screen using a media query. For example:
import { useMediaQuery } from "react-responsive";
const isMobile = useMediaQuery({ query: '(max-width: 480px)' });
const responsiveFontSize = isMobile ? 12 : 16;
const options = {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: false
}
},
scales: {
xAxes: [{
position: "top"
}]
ticks: {
fontSize: responsiveFontSize,
}
}
}

Line Chart Js x-axis values all 0 on React

I'm trying to implement a line graph through chart js on react, however, whenever my function sets the x and y axis data, it keeps returning a line chart that is vertical with x-axis values at 0.
Here is my code below:
import React, { useEffect, useState } from 'react'
import './LineGraph.css'
import {Line} from "react-chartjs-2"
function LineGraph() {
const [ graphData, setGraphData ] = useState([])
const data = [{x:10, y:20}, {x:15, y:10}, {x:12, y:4}]
const createMockData = () => {
let data = [];
let value = 50;
for(var i = 1; i < 366; i++) {
let date = new Date()
date.setHours(0,0,0,0)
date.setDate(i)
value += Math.round((Math.random() < 0.5 ? 1 : 0) * Math.random() * 10)
data.push({x: value, y:value})
console.log(data)
}
setGraphData(data)
}
useEffect(()=> {
createMockData()
}, [])
return (
<div className="linegraph">
<Line
data={{
datasets: [
{
type: "line",
data: graphData,
backgroundColor: "black",
borderColor: "#5AC53B",
borderWidth: 2,
pointBorderColor: 'rgba(22, 22, 22, 0)',
pointBackgroundColor: 'rgba(0,0,0,0)',
pointHoverBackgroundColor: '#5AC53B',
pointHoverBorderColor: '#000000',
pointHoverBorderWidth: 4,
pointHoverRadius: 6,
}
]
}}
options={{
plugins:{
legend: {
display: false
},
tooltips: {
interaction: {
mode: "index",
intersect: false
}
}
},
scales: {
x: [
{
type: "time",
time: {
format: "MM/DD/YY",
tooltipFormat: "ll",
},
ticks: {
display: false,
}
},
],
y: {
ticks: {
display: false
}
}
}
}}
/>
</div>
)
}
export default LineGraph
I'm using react-charts-2, latest version 3.5.1. I think the main problem is with my x-axis because my y-coordinates all show up, which is why the line is vertical, however, all the x values are 0, so their is not diagonal or correlated uphill/downhill line. Please help me resolve this
You are defining the x axis scale as an array , this is v2 syntax. All scales have to be defined as an object. So at the moment chart.js sees your scale as a category scale instead of a time scale and it cant handle number inputs as labels.
To fix this you will need to change your scale like so:
scales: {
x: {
type: "time",
time: {
format: "MM/DD/YY",
tooltipFormat: "ll",
},
ticks: {
display: false,
}
},
,
}
For using the timescale you will also need a date adapter, since you are using js dates you can just use the normal datefns adapter like so:
npm install date-fns chartjs-adapter-date-fns --save
import {Line} from "react-chartjs-2"
import 'chartjs-adapter-date-fns';

make every labels different in doughnut chart (react js)

i have double doughnut chart in my react js project code. in that double chart dougnut i want to have 3 different labels in 3 different colour, what should i write to make that?
this my code now
var dataDoughnut1 = {
labels: ["Blue", "Green", "Red"],
datasets: [{
data: [1000],
backgroundColor: [
"#36A2EB"
],
labels: [
'Blue',
]
}, {
data: [400,600],
backgroundColor: [
"#C4D34C",
"#F7464A"
],
labels: [
'Green',
'Red'
],
}],
};
until now with that code the output labels is "blue","green" and "green" again
i want to make 3 different labels in 3 different colour too, anyone can help me?
result :
Ok, so i have read the docs of react-chartjs-2 and their Doughnut Chart does not support rendering two datasets like you want, i came up with this workaround that will help you to achieve what you want.
import React from "react";
import { Doughnut } from "react-chartjs-2";
import { MDBContainer } from "mdbreact";
const App = () => {
var dataDoughnut1 = {
labels: ["Blue", "Green", "Red"],
datasets: [
{
data: [1000, 0, 0],
//You should set here all the other colors desired from the other datasets so it can be interpreted by the component
backgroundColor: ["#36A2EB"],
labels: ["Blue"],
},
{
data: [400, 600],
backgroundColor: ["#C4D34C", "#F7464A"],
labels: ["Green", "Red"],
},
],
};
const options = {
responsive: true,
legend: {
display: false,
},
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
console.log(tooltipItem.datasetIndex);
var dataset = data.datasets[tooltipItem.datasetIndex];
var index = tooltipItem.index;
return dataset.labels[index] + ": " + dataset.data[index];
},
},
},
};
return (
<MDBContainer>
<h3 className="mt-5">Doughnut chart</h3>
<Doughnut data={dataDoughnut1} options={options} />
</MDBContainer>
);
};
export default App;
Here is the result

Resources