antd chart in React: shrinks when global state changes - reactjs

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} />;
});

Related

How to use a static color for Chart.js bar chart's legend, when using an array of background colors [duplicate]

I have a bar chart that always shows 4 bars. The bars are coloured dynamically. It looks like the coloured box takes its colour from the first data. I would like to use the colour from the 4th (last) data value. Maybe the options:plugins:legend:label:sort function helps but I don't understand what it does.
options
const options = {
scales: {
x: {
grid: {
display: false,
color: 'rgba(0,0,0)'
}
},
y: {
display: false,
min: 0,
max: 4
},
},
plugins: {
legend: {
position: 'bottom'
}
}
}
So I don't know if I can change the data that the box color comes from, or if there is a config option somewhere where I can change it manually.
You can use the generateLabels function as described here.
Please take a look at below runnable sample code and see how it works.
new Chart('myChart', {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow'],
datasets: [{
label: 'My Dataset',
data: [300, 50, 100],
backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56']
}]
},
options: {
responsive: false,
plugins: {
legend: {
labels: {
generateLabels: chart => {
let ds = chart.data.datasets[0];
let color = ds.backgroundColor[ds.backgroundColor.length - 1];
return [{
datasetIndex: 0,
text: ds.label,
fillStyle: color,
strokeStyle: color
}];
}
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="myChart" height="180"></canvas>
Following up with #uminder's answer, if you want to keep the hide/show chart and the line-through style after clicking on the legend, you can add the following line:
options: {
responsive: false,
plugins: {
legend: {
labels: {
generateLabels: chart => {
let ds = chart.data.datasets[0];
let color = ds.backgroundColor[ds.backgroundColor.length - 1];
return [{
datasetIndex: 0,
text: ds.label,
fillStyle: color,
strokeStyle: color,
+ hidden: !chart.isDatasetVisible(0)
}];
}
}
}
}
}

Labels for Nested Doughtnut Chart React ChartJS

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.

How to fill background color in ant-design charts with y-axis value condition

So I'm currently using ant-design charts to plot data which I pull from Django to React. What I wanna do is to fill colors to the background according to the y-axis values. For eg, I want the background color for 15-18 to be red, 18-20 to be yellow, 20-25 to be green and so on and so forth. Here's a screenshot of what I want to achieve:
and what I have so far is a very simple Line chart:
import React from "react";
import { Line } from "#ant-design/charts";
const Graph = (props) => {
var config = {
data: props.data,
padding: "auto",
xField: "Hour",
yField: "Measurement",
yAxis: {
minLimit: 15,
maxLimit: 30,
tickCount: 16,
},
};
return <Line {...config} />;
};
export default Graph;
I've tried finding articles or guides online but is unable to find any. Any help would be appreciated thank you so much!
You can use Region annotations
https://g2plot.antv.vision/en/docs/api/plots/tiny-area#-region-annotation
var config = {
...
annotations: [
{
type: 'region',
start: ['min', 15]
end: ['max', 18],
style: {
fill: '#ff0000'
}
},
{
type: 'region',
start: ['min', 18]
end: ['max', 20],
style: {
fill: '#00ffff'
}
}
...
]
}

Reverse the order of data from an API call works with console.log

Building a Covid tracker using React and ChartJS-2 I found that I couldn't reverse the incoming data through usual means ie. through the recommendations in the chartJS docs. What seems to work is console.log(res.data.data.reverse())
Without this line of code printing to the console, the data displays the opposite way around.
Why is this?
The xAxes params don't take effect, either, but I'm probably just missing a '}' or ']', somewhere.
import { useState, useEffect } from 'react';
import { Line } from 'react-chartjs-2';
import axios from 'axios';
const CovidCases = () => {
const [chartData, setChartData] = useState({});
const chart = () => {
//set variables to pass in as dynamic data
let covCase = [];
let covDate = [];
// axios get endpoint
axios
.get(
'https://api.coronavirus.data.gov.uk/v1/data?filters=areaName=England;areaType=nation&structure={"date":"date","name":"areaName","code":"areaCode","newCasesByPublishDate":"newCasesByPublishDate","cumCasesByPublishDate":"cumCasesByPublishDate","newDeaths28DaysByPublishDate":"newDeaths28DaysByPublishDate","cumDeaths28DaysByPublishDate":"cumDeaths28DaysByPublishDate"}',
)
.then((res) => {
// here I reverse the order that the data comes into the console
console.log(res.data.data.reverse());
for (const dataObj of res.data.data) {
covCase.push(parseInt(dataObj.newCasesByPublishDate));
covDate.push(parseInt(dataObj.date));
// setting the chart data STATE with the chart.js labels and datasets with data: covCase variable
setChartData({
// https://www.chartjs.org/docs/latest/getting-started/usage.html for layout requirements
labels: covDate,
datasets: [
{
label: 'New Covid Cases by Date (England)',
data: covCase,
backgroundColor: ['rgba(81, 250, 157, 0.6)'],
borderWidth: 2,
},
],
});
}
})
.catch((err) => {
console.log(err);
}).catch((err) => {
console.log(err.message)
})
// console.log(covCase, covDate);
};
useEffect(() => {
chart();
}, []);
return (
<div className="charts" style={{ height: 700, width: 900 }} >
<Line
// passing in the STATE as the data to be rendered
data={chartData}
// chart.js options parameters
options={{
title: { text: 'Covid Cases', display: true },
scales: {
yAxes: [
{
ticks: {
autoSkip: true,
beginAtZero: true,
},
},
],
xAxes: [
{
autoSkip: true,
padding: 10,
// this section didn't make the difference expected of it. reversing the console.log() did, though!!
// ticks: {
// // reverse: true,
// maxTicksLimit: 7,
// display: false,
// },
},
],
},
}}
/>
</div>
);
};
export default CovidCases;
Also, the xAxes parameters were taking no effect but I think I'm within the code recommendations?
Thanks.

Zoom on chart not working in react-plotly.js

I have created a bar chart with rangeslider using react-plotly.js. I want to enable drag and zoom feature on chart area as provided by the library. But that feature is not working for me. The fixedRange attribute of layout is not true. The cursor changes to the double arrow cursor but when I perform drag action, nothing happens. The area selected is not highlighted and not even zoomed in. But when I double click, the area get zoomed out.
My layout settings looks like:
const layout = {
title: this.state.chartTitle,
autosize: true,
dragmode: false,
// showlegend: true,
margin: {
r: 0,
t: 50,
b: 100,
pad: 0,
autoexpand: true
},
scrollZoom: true,
hoverlabel: {
bgcolor: 'rgba(0,0,0,1)',
bordercolor: 'rgba(200,200,200,1)'
},
width: this.state.layoutWidth,
height: '750',
yaxis: {
title: this.state.yaxisTitle,
type: 'linear',
showgrid: true
},
xaxis: {
title: this.props.intl.formatMessage(messages.xAxisTitle),
type: this.state.xaxisType,
autorange: false,
showgrid: false,
range: this.state.axisRange,
rangeslider: {
visible: true,
range: this.state.sliderRange
}
}
I even tried scrollZoom attribute but that doesn't work either. The version of plotly.js and react-plotly.js that I am using is :
"plotly.js": "^1.41.3",
"react-plotly.js": "^2.2.0",
"react-plotlyjs": "^0.4.4",
Am I suppose to also add some css settings to it ? Please help.
Instead of putting
scrollZoom: true to layout, please try to put it into the config tree, like:
const Plot = createPlotlyComponent(Plotly);
ReactDOM.render(
React.createElement(Plot, {
data: [...],
layout: {...},
config: {
scrollZoom: true,
}
}),
document.getElementById('root')
);

Resources