Tooltip not displaying data with dynamic keys in BarChart #2583
-
DescriptionHi! I'm working on a bar chart. Everything is functioning as expected, except the default tooltip, which appears empty when I hover over the bars. My chart uses dynamic keys for the legends, which work correctly, but the same keys don't seem to work for tooltips. IssueThe tooltips are empty despite the bars displaying correctly with dynamically generated keys. The legends display properly using the same set of keys. Code SnippetsChart Configuration<ResponsiveBar
data={barData}
keys={chartKeys}
indexBy="year"
margin={{ top: 50, right: 130, bottom: 50, left: 60 }}
padding={0.3}
valueScale={{ type: "linear" }}
indexScale={{ type: "band", round: true }}
colors={{ scheme: "nivo" }}
borderColor={{
from: "color",
modifiers: [["darker", 1.6]],
}}
axisTop={null}
axisRight={null}
axisBottom={{
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: "year",
legendPosition: "middle",
legendOffset: 32,
}}
axisLeft={{
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: "credito_vigente",
legendPosition: "middle",
legendOffset: -40,
}}
enableTotals={true}
labelSkipWidth={12}
labelSkipHeight={12}
labelTextColor={{ from: "color", modifiers: [["darker", 1.6]] }}
legends={[
{
dataFrom: "keys",
anchor: "bottom-right",
direction: "column",
justify: false,
translateX: 120,
translateY: 0,
itemsSpacing: 1, // Reduced spacing between items
itemWidth: 80, // Smaller width
itemHeight: 15, // Smaller height
itemDirection: "left-to-right",
itemOpacity: 0.85,
symbolSize: 12, // Smaller symbol size
effects: [
{
on: "hover",
style: {
itemOpacity: 1,
},
},
],
},
]}
role="application"
ariaLabel="Nivo bar chart demo"
barAriaLabel={(e) =>
`${e.id}: ${e.formattedValue} in year: ${e.indexValue}`
}
/> Data Handling const [dataByYear, setDataByYear] = useState<AñoConSusActividades[]>([]);
const [chartKeys, setChartKeys] = useState<string[]>([]); // State to store unique keys
const transformAndSetData = useCallback(
(data: PresupuestoPorProgramaUNI[]) => {
const groupedData = data.reduce((acc, curr) => {
// Find an existing year entry in the accumulated data
const yearEntry = acc.find(
(entry) => entry.year === curr.impacto_presupuestario_anio
);
// Construct a new activity object
const activity = {
actividad_desc: curr.actividad_desc,
credito_vigente: Number(curr.credito_vigente.toFixed(0)),
};
if (yearEntry) {
// If an entry for the year already exists, push the new activity into this year's activities array
yearEntry.activities.push(activity);
} else {
// If no entry for the year exists, create a new one with the current activity
acc.push({
year: curr.impacto_presupuestario_anio,
activities: [activity],
});
}
return acc;
}, [] as AñoConSusActividades[]);
// Update the state with the new grouped data
setDataByYear(groupedData);
// Update the chart keys based on the new data
setChartKeys(extractUniqueKeys(groupedData));
},
[setDataByYear, setChartKeys]
); // Include these as dependencies
useEffect(() => {
async function fetchData() {
try {
const response = await fetch("/api/presupuestoUni");
const jsonData = await response.json();
const dataRes: PresupuestoPorProgramaUNI[] = jsonData.dataRes;
console.log("Fetched Data:", dataRes); // Log the raw fetched data
transformAndSetData(dataRes);
} catch (error) {
console.error("Failed to fetch data:", error);
}
}
fetchData();
}, [transformAndSetData]); // Now only re-runs if transformAndSetData changes, which shouldn’t happen due to useCallback
const extractUniqueKeys = (data: AñoConSusActividades[]): string[] => {
const allKeys = new Set(
data.flatMap((yearGroup) =>
yearGroup.activities.map((activity) => activity.actividad_desc)
)
);
return Array.from(allKeys);
};
//PENSAR SI PUEDO HACER ESTO DIRECTAMENTE EN transformAndSetData
const barData = dataByYear.map((yearGroup) => {
// Define the accumulator with an index signature.
// This tells TypeScript that the object will have any number of properties,
// where each property key is a string and each property value is a number.
const activitiesAccumulator: Record<string, number> = {};
yearGroup.activities.forEach((activity) => {
activitiesAccumulator[activity.actividad_desc] = activity.credito_vigente;
});
return {
year: yearGroup.year.toString(), // This maps directly to 'indexBy' in the ResponsiveBar component
...activitiesAccumulator,
};
}); Video of the default tool tip not working:Create.Next.App.-.Personal_.Microsoft.Edge.2024-05-02.20-33-40.mp4 |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
@vladimirzb, thank you for providing details about your issue, but could you please reproduce the issue in codesandbox for example? It's going to be hard to investigate without having the actual data, so a static version would be great, thank you. |
Beta Was this translation helpful? Give feedback.
-
Thank you for the response @plouc ! :) Here is the CodeSandbox link . I don't use CodeSandbox very often, so if there's anything specific you think I should adjust, please let me know. The project is in its early stages and quite barebones, but I've tried to simplify it as much as possible. If you need more information or require any specific changes, just let me know! :) |
Beta Was this translation helpful? Give feedback.
-
@vladimirzb, thank you, it really helped :) So the tooltips are working, the problem comes from your styles: @media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
}
}
body {
color: rgb(var(--foreground-rgb));
} By default the text color is white, and so is the tooltip background, that's why it seems empty, you can either adjust your css or pass a theme to the chart:
|
Beta Was this translation helpful? Give feedback.
@vladimirzb, thank you, it really helped :)
So the tooltips are working, the problem comes from your styles:
By default the text color is white, and so is the tooltip background, that's why it seems empty, you can either adjust your css or pass a theme to the chart: