I want to generate a Pie Chart, but I keep on having this error even if my array is containing all the necessary information to be displayed on the Pie Chart (via the console log). I don't even know where this error come from on my code:
here is my Pie component :
import { Box } from "@mui/material";
import Header from "../components/Header";
import PieChart from "../components/PieChart";
import { useEffect, useState } from "react";
import { mockDistrictData } from "../data/MockData";
const Pie = () => {
const [districts, setDistricts] = useState([]);
const [selectedDistrict, setSelectedDistrict] = useState('');
const [finalData, setFinalData] = useState([]);
const lightGreenColor = "hsl(154,52%,45%)";
const greenColor = "hsl(139,100%,83%)";
const [isGeneratingChart, setIsGeneratingChart] = useState(false);
// Fetch data for mechanical bikes
const fetchMechanicalBikes = (districtName) => {
const url = `http://localhost:8800/station_status/bikes/mechanical/${districtName}`;
return fetch(url)
.then(response => response.json())
.then(data => {
// Transform the fetched data and assign random colors
return data.map(i => ({
id: `Mechanical bikes`,
label: `Mechanical bikes`,
value: i.value,
color: lightGreenColor
}));
});
};
// Fetch data for electronic bikes
const fetchElectronicBikes = (districtName) => {
const url = `http://localhost:8800/station_status/bikes/electric/${districtName}`;
return fetch(url)
.then(response => response.json())
.then(data => {
// Transform the fetched data and assign random colors
return data.map(item => ({
id: `Electronic bikes`,
label: `Electronic bikes`,
value: item.value,
color: greenColor
}));
});
};
// Combine the fetched data for mechanical and electronic bikes
const combineFetchedData = async (districtName) => {
try {
setIsGeneratingChart(true); // Set the flag to indicate chart generation in progress
const mechanicalData = await fetchMechanicalBikes(districtName);
const electronicData = await fetchElectronicBikes(districtName);
// Combine the two arrays into a single array
const combinedData = [...mechanicalData, ...electronicData];
setTimeout(() => {
setFinalData(combinedData);
console.log(combinedData); // Print the combined data
setIsGeneratingChart(false); // Set the flag to indicate chart generation completed
}, 3000); // 3 seconds delay
// You can use the combined data for further processing or visualization
} catch (error) {
console.error('Error fetching data: ', error);
setIsGeneratingChart(false); // Set the flag to indicate chart generation completed with an error
}
};
useEffect(() => {
// Fetch districts
const fetchDistricts = () => {
setDistricts(mockDistrictData.map(district => district.district_name));
};
fetchDistricts();
}, []);
return (
<Box m="20px">
<Header title="Pie Chart" subtitle="Electric Bikes & Mechanical Bikes" />
<Box height="75vh">
<div>
<select value={selectedDistrict} onChange={e => setSelectedDistrict(e.target.value)}>
<option value="">Select a district</option>
{districts.map(district => (
<option key={district} value={district}>{district}</option>
))}
</select>
<button disabled={isGeneratingChart} onClick={() => combineFetchedData(selectedDistrict)}>
{isGeneratingChart ? 'Generating...' : 'Generate Chart'}
</button>
</div>
{finalData.length > 0 && <PieChart data={finalData} />}
</Box>
</Box>
);
};
export default Pie;
here is my PieChart component :
import { ResponsivePie } from "@nivo/pie";
import { tokens } from "../theme";
import { useTheme } from "@mui/material";
const PieChart = (finalData) => {
const theme = useTheme();
const colors = tokens(theme.palette.mode);
return (
<ResponsivePie
data={finalData}
theme={{
axis: {
domain: {
line: {
stroke: colors.grey[100],
},
},
legend: {
text: {
fill: colors.grey[100],
},
},
ticks: {
line: {
stroke: colors.grey[100],
strokeWidth: 1,
},
text: {
fill: colors.grey[100],
},
},
},
legends: {
text: {
fill: colors.grey[100],
},
},
}}
margin={{ top: 40, right: 80, bottom: 80, left: 80 }}
innerRadius={0.5}
padAngle={0.7}
cornerRadius={3}
activeOuterRadiusOffset={8}
borderColor={{
from: "color",
modifiers: [["darker", 0.2]],
}}
arcLinkLabelsSkipAngle={10}
arcLinkLabelsTextColor={colors.grey[100]}
arcLinkLabelsThickness={2}
arcLinkLabelsColor={{ from: "color" }}
enableArcLabels={false}
arcLabelsRadiusOffset={0.4}
arcLabelsSkipAngle={7}
arcLabelsTextColor={{
from: "color",
modifiers: [["darker", 2]],
}}
defs={[
{
id: "dots",
type: "patternDots",
background: "inherit",
color: "rgba(255, 255, 255, 0.3)",
size: 4,
padding: 1,
stagger: true,
},
{
id: "lines",
type: "patternLines",
background: "inherit",
color: "rgba(255, 255, 255, 0.3)",
rotation: -45,
lineWidth: 6,
spacing: 10,
},
]}
legends={[
{
anchor: "bottom",
direction: "row",
justify: false,
translateX: 0,
translateY: 56,
itemsSpacing: 0,
itemWidth: 100,
itemHeight: 18,
itemTextColor: "#999",
itemDirection: "left-to-right",
itemOpacity: 1,
symbolSize: 18,
symbolShape: "circle",
effects: [
{
on: "hover",
style: {
itemTextColor: "#000",
},
},
],
},
]}
/>
);
};
export default PieChart;
Can somebody help me solve the problem please ?
Your PieChart component receives props, not a finalData
argument.
<PieChart data={finalData} />
// finalData here is a props object that has a data field
const PieChart = (finalData) => {
...
<ResponsivePie
data={finalData} // finalData isn't what you appear to think it is.
Suggested fix:
const PieChart = (props) => {
...
<ResponsivePie
data={props.data}
...
Or you could destructure data
from props if you prefer:
const PieChart = ({ data }) => {
...
<ResponsivePie
data={data}
...
ResponsivePie
expects data to be an array and is attempting to call map on it. (I assume.)