nivo
nivo copied to clipboard
Is there a way to remove gaps when using a grouped bar chart with missing data?
Is your feature request related to a problem? Please describe. I'm using a grouped bar component, but there's not always a guarantee that the group members will be the same for each group. The way things are working right now, even members without a key in the datum will take up space in the bar chart and cause gaps (see screenshot). Is there a way to solve this using existing options?
Describe the solution you'd like It would be helpful if there was an option to have the graph draw the bars so that they ignore entries without data. Ideally the bars would be centered on the tick as if they were the only elements, not spaced based on data that doesn't exist.
Additional context
Change your keys in your code. Check your data before you put it into the chart. Remove the entries with a 0 or null or something.
I came across this issue after encountering the same problem and searching for a workaround. I agree that the proposed solution would probably be the best way of addressing this. To note, this behavior will occur if the keys for grouped bar charts are not exactly the same across each item and is not caused by values of null or zero.
@drj17 @djpowers is there a solution for this? Running into this now...
@hanford, still on the lookout for a solution, myself.
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Bump
Bump
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Bump
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Bump
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Bumping again
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
bump
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
^
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Bump, please
@djpowers, is there a specific use-case/scenario that you are looking at? Could you share an example?
A personal view is that gaps can be quite informative. When the data is dense, then a few gaps don't take up a lot of space and help preserve the structure/order of bars across the groups. Omiting the gaps could make a chart confusing (again, personal view).
In cases like in the original example, grouped bars can indeed become hard to read. Such data can sometimes be visualized with other techniques, e.g. perhaps a series of smaller charts? or a heatmap?

https://codesandbox.io/s/nifty-joliot-jy6fv3?file=/src/App.js
Hi @tkonopka, in my case, I personally didn't find the gap to provide any useful information. My scenario had the gaps in the last position of a given bar chart group, which to me looks more like a spacing issue. It also results in the grouped bars not being centered on the x-axis hash mark, which also looks a bit odd to me:
That being said, I understand your points and recognize this would introduce some complexity to things. Feel free to close this as wontfix if it seems like something that won't realistically be implemented.
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you!
Has anyone found a solution to this. Or any alternative to this?
Has anyone found a solution to this. Or any alternative to this?
I was never able to find any sort of solution or workaround, unfortunately.
I encountered a version of this problem, that is a bit more simple than the general use case.
What I need to do:
- have 3 bars that get shown for different keys
- I know that the 2 bars are only displayed with some constraints: I either display the first bar or the other 2
Given the simplified version of my problem I wrote the following BarComponent
import { BarItem, BarItemProps } from "@nivo/bar";
import React, { useEffect, useState } from "react";
interface CustomBarDatum extends BarDatum {
key_1: number;
key_2: number;
key_3: number;
}
type TranslationValues = {
x: number;
y: number;
};
function parseTranslate(translateString: string): TranslationValues {
const result = { x: 0, y: 0 };
// Extracting translate values using a regular expression
const matches = translateString.match(
/translate(?:X|Y)?\(([^,]+)(?:,\s*([^)]+))?\)/
);
if (matches) {
// If there's a match, parse X and Y values
result.x = parseFloat(matches[1]);
if (matches[2]) {
result.y = parseFloat(matches[2]);
} else {
// If only one value is present, determine if it's X or Y based on the function used
if (translateString.startsWith("translateY")) {
result.y = result.x;
result.x = 0;
}
}
}
return result;
}
const CustomBarNoGaps = (props: BarItemProps<CustomBarDatum>) => {
const { style, fullData, ...otherProps } = props;
const [isAdapted, setIsAdapted] = useState(false);
useEffect(() => {
if (isAdapted) return;
const isBarShown = [
"key_1",
"key_2",
"key_3",
].map((k) => !!props.bar.data.data[k]);
const numberBars = isBarShown.filter((t) => t).length;
console.log(style);
const barTranslate = parseTranslate(style.transform.goal);
console.log(style.transform.goal);
if (numberBars === 1) {
style.labelX.set(Math.round(style.labelX.goal + style.width.goal));
style.width.set(Math.round(style.width.goal * 3));
} else if (numberBars === 2) {
const newTranslationString = `translate(${Math.round(
barTranslate.x -
(props.bar.data.id === "key_2"
? style.width.goal
: 0.5 * style.width.goal)
)}, ${barTranslate.y})`;
style.labelX.set(Math.round(style.labelX.goal + style.width.goal / 4));
style.transform.set(newTranslationString);
style.width.set(Math.round(style.width.goal * 1.5));
}
setIsAdapted(true);
}, [style, props, isAdapted]);
console.log(props.bar.data);
console.log(fullData);
return <BarItem style={style} {...otherProps} />;
};
export { CustomBarNoGaps };
This can be passed to the barComponent
property. See how it is used
This solution is very specific for my use case but it can be generalized if one would need to dynamically compute my hardcoded values (1.5, 3, etc.) to take into account the number of bars skipped vs the number of bars rendered so far.