Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic bar width is set to zero when there is only one data point #3640

Closed
1 task done
Nicolapps opened this issue Jun 23, 2023 · 8 comments
Closed
1 task done
Labels
bug General bug label

Comments

@Nicolapps
Copy link

  • I have searched the issues of this repository and believe that this is not a duplicate.

Reproduction link

Edit on CodeSandbox

Steps to reproduce

  • Create a BarChart with a XAxis of type number and a domain
  • Use a data set that has only one data point

What is expected?

The bar has a width that makes it visible.

What is actually happening?

The bar has a zero width by default, which makes it invisible.

Environment Info
Recharts v2.7.2
React 18.2.0
System macOS Ventura 13.4
Browser Safari 16.5, Firefox 114.0.2, Chrome 114.0.5735.133
@Nicolapps
Copy link
Author

It is worth noting that if your chart is affected by this behavior, it is possible to set manually barSize on Bar in the case where there is only one data point (and leave it undefined otherwise to keep using the automatic width).

@ckifer
Copy link
Member

ckifer commented Jun 23, 2023

This behavior is the same in previous versions right? (I think it is)

@ckifer ckifer added the bug General bug label label Jun 23, 2023
@Nicolapps
Copy link
Author

Yes, I have the same behavior with earlier versions.

@graup
Copy link
Contributor

graup commented Mar 19, 2024

This is still broken and the barSize workaround doesn't work for me. Does anyone know any other workarounds?

@graup
Copy link
Contributor

graup commented Mar 19, 2024

I created another example showing how this works (or doesn't work) with date axes: https://codesandbox.io/p/sandbox/tiny-bar-chart-forked-vk9fyv?file=%2Fsrc%2FApp.tsx

Here is what I expect:
Screenshot 2024-03-19 at 11 41 19
expected

I don't believe the PR achieves what's in the second image, instead making the bar always 1/3 the width of the chart. How can we have one bar with a size considering the ticks/domain? My hunch is that the bug isn't in the calculation of the bar size but in the calculation of the visible ticks...

For now the only real workaround seems to be to create dummy data for missing x values yourself.

@graup
Copy link
Contributor

graup commented Apr 4, 2024

After much digging, I have concluded that there is no easy & correct fix for this.

  • The automatic bar size calculation in getBandSizeOfAxis uses the minimum distance between any two adjacent categorical values. This is smart because, with a numerical domain used categorically, we cannot determine the bar width just from the domain or axis ticks. Consider a domain of [0, 10] with one bar per whole number; we expect a bar to have a width of 1/10 of the chart width. Now if instead data points were on 0.5 increments, we expect a bar to have a width of 1/20.
  • The corollary to this is that when we only have one data point on a numerical categorical axis, it is logically impossible to calculate how wide it should be. What does a single tick at "5" mean on the domain [0, 10]? We cannot know if this should be 1/10 or 1/20 wide.
  • So in this case, we need some more information from the user. Currently, it is possible to provide an absolute barSize but this doesn't scale responsively. Also it currently overrides the automatic calculation, so you have to jump through some hoops if you want both.
    • Maybe we could allow percentage values for barSize, so the user could calculate it themselves (e.g. "10%" if you expect 10 bars in one chart.
    • Alternatively, it would be nice to be able to provide a logical value, e.g. barWidthInDomain=1 meaning "in this chart, one bar shall be 1 unit wide in my domain". Then we could use the axis.scale() method to determine coordinates of a virtual data point at (ticks[0] + barWidthInDomain) and thus use the existing getBandSizeOfAxis calculation. In other words, there needs to be a way for the user to tell us how to interpret the domain.

@ckifer @nikolasrieble does this make sense?

@nikolasrieble
Copy link
Contributor

feat(BarChart): support percentage for barSize. Fixes #3640 #4390

Love the writeup, agree very much. At this point it is mostly an aesthetic defaults question. Your solution makes sense, thank you for your contribution ❤️

graup added a commit to graup/recharts that referenced this issue Apr 9, 2024
…echarts#4390)

This adds support for percentage values for `barSize` as a workaround
for recharts#3640. See also my comment at
recharts#3640 (comment)

This is not really the perfect solution, but it allows users to at least
have a good workaround.

If you know how many data points your axis domain expects, you can
hard-code `barSize` to `100%/numberOfDataPoints` (e.g. `'10%'` for 10
data points).

You can also combine this with the automatic calculation, e.g.
`barSize={data.length > 1 ? undefined : '10%'}`.

```
<BarChart
  width={500}
  height={300}
  data={[[4.5, 10]]}
  barSize="30%" /* When there's only one data point on a numerical domain, we cannot automatically calculate the bar size */
  margin={{
    top: 5,
    right: 30,
    left: 20,
    bottom: 5,
  }}
>
  <XAxis dataKey={v => v[0]} type="number" domain={[0, 10]} />
  <YAxis />
  <Tooltip />
  <CartesianGrid strokeDasharray="3 3" />
  <Bar dataKey={v => v[1]} />
</BarChart>
```

![Screenshot 2024-04-04 at 16 31
49](https://github.com/recharts/recharts/assets/898549/d4fcbdad-d6ae-468d-b522-fb008c20a2a4)
# Conflicts:
#	src/chart/generateCategoricalChart.tsx
ckifer pushed a commit that referenced this issue Apr 9, 2024
***Backport of #4390***

This adds support for percentage values for `barSize` as a workaround
for #3640. See also my comment at
#3640 (comment)

This is not really the perfect solution, but it allows users to at least
have a good workaround.

If you know how many data points your axis domain expects, you can
hard-code `barSize` to `100%/numberOfDataPoints` (e.g. `'10%'` for 10
data points).

You can also combine this with the automatic calculation, e.g.
`barSize={data.length > 1 ? undefined : '10%'}`.

```
<BarChart
  width={500}
  height={300}
  data={[[4.5, 10]]}
  barSize="30%" /* When there's only one data point on a numerical domain, we cannot automatically calculate the bar size */
  margin={{
    top: 5,
    right: 30,
    left: 20,
    bottom: 5,
  }}
>
  <XAxis dataKey={v => v[0]} type="number" domain={[0, 10]} />
  <YAxis />
  <Tooltip />
  <CartesianGrid strokeDasharray="3 3" />
  <Bar dataKey={v => v[1]} />
</BarChart>
```

![Screenshot 2024-04-04 at 16 31

49](https://github.com/recharts/recharts/assets/898549/d4fcbdad-d6ae-468d-b522-fb008c20a2a4)
# Conflicts:
#	src/chart/generateCategoricalChart.tsx

<!--- Provide a general summary of your changes in the Title above -->

## Description

<!--- Describe your changes in detail -->

## Related Issue

<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an
issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps
to reproduce -->
<!--- Please link to the issue here: -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

## How Has This Been Tested?

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran
to -->
<!--- see how your change affects other areas of the code, etc. -->

## Screenshots (if appropriate):

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes.
- [ ] I have added a storybook story or extended an existing story to
show my changes
@ckifer
Copy link
Member

ckifer commented Apr 12, 2024

Released in https://github.com/recharts/recharts/releases/tag/v2.12.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug General bug label
Projects
None yet
Development

No branches or pull requests

4 participants