Hi! 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.
The tooltips are empty despite the bars displaying correctly with dynamically generated keys. The legends display properly using the same set of keys.
<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}`
}
/>
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,
};
});
https://github.com/plouc/nivo/assets/55926702/ac72b3c4-6f12-4faa-8be4-4ef3af06f711
Source: https://github.com/plouc/nivo/discussions/2583#discussioncomment-9310618
Author of the solution:
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:
theme={{ tooltip: { wrapper: { color: "#000000" } } }}