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

fix(bar): fix bar chart bars overflowing the coordinate system #19973

Closed
wants to merge 2 commits into from

Conversation

KurtGokhan
Copy link

@KurtGokhan KurtGokhan commented May 23, 2024

Brief Information

This pull request is in the type of:

  • bug fixing

What does this PR do?

Bar chart clip option now clips the bar at the edges of the coordinate system so that it doesn't overflow.

Fixed issues

Fixes #19972

Details

See #19972 for detailed info and additional links.

Before: What was the problem?

See example

image

After: How does it behave after the fixing?

bar-clip test covers this case.

image

There is also a test with dataZoom.filterMode:'none'

image

Document Info

  • This PR doesn't relate to document changes
  • The document should be updated later
  • The document changes have been made in apache/echarts-doc#xxx

Misc

ZRender Changes

  • This PR depends on ZRender changes (ecomfe/zrender#xxx).

Related test cases or examples to use the new APIs

N.A.

Others

Merging options

  • Please squash the commits into a single one when merging.

Other information

Here is the diff

image

Copy link

echarts-bot bot commented May 23, 2024

Thanks for your contribution!
The community will review it ASAP. In the meanwhile, please checkout the coding standard and Wiki about How to make a pull request.

@apache apache deleted a comment from gooroodev May 26, 2024
@apache apache deleted a comment from admsev May 26, 2024
Copy link
Contributor

@Ovilia Ovilia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a highly anticipated feature that has been requested by multiple users, so it's exciting to see this pull request.

Let's first clarify the behavior.

Without dataZoom

When dataZoom is not used, this pull request introduces a breaking change for bar series. According to the documentation, clip: true means: "Clip all the overflowed. With bar width kept." Therefore, we cannot consider the previous behavior a bug.

Bar: Clip all the overflowed. With bar width kept.
The English documentation might be a bit unclear. The Chinese version specifies that the bars are not clipped.

Recommendation

We can either:

  1. Maintain the behavior of clip: true and introduce another option like clipMode or string values for clip: 'xxx'. While this may not be the perfect default solution, it does provide developers with a method to achieve their desired outcomes.
  2. Clip bars outside the grid as the current implementation does, and introduce this breaking change in ECharts 6.0, which is expected to be released early next year. Special attention should be given to cases with a category axis with boundaryGap: false, where the axis should shrink to ensure it won't be clipped. See the images below for reference.

Current Behavior

If we clip the bars as shown in the image below, the first and last bar will have half width, which is not expected.

image

Expected Behavior

If the axis can be shrunk and the grid width remains unchanged as shown below, then it won't be affected when clipped.

image

As illustrated, solution 2 requires more effort for you but has the potential to be more intuitive. Therefore, you may want to consider which approach we should take.

With dataZoom

If no breaking changes are considered, bars should never be clipped because neither clip: true nor any value of filterMode will result in the expected clipping behavior. If breaking changes are considered, please refer to the above notes on solution 2.

@KurtGokhan
Copy link
Author

I appreciate the review, and can understand the concern about the breaking change.

Despite my attempts, I couldn't find a case where clip: true and clip: false acts differently for a bar chart. It seems like users could use clip: false if they want to keep the bar width. Most people won't run into this issue because there is a boundaryGap by default so the bars will be inside the grid in a category axis.

Clipping everything outside the grid when clip is true sounds like a more intuitive solution to me. Arguably, we could try to preserve the radius of an item in a scatter chart, or width of the bars in the candlestick. My point is, there is no end to the edge cases. I don't understand why bar chart is treated differently.

@Ovilia
Copy link
Contributor

Ovilia commented Jun 19, 2024

@KurtGokhan Here is an example

option = {
  xAxis: {
    min: 109
  },
  yAxis: {
    type: 'value'
  },
  grid: {
    left: 350
  },
  series: [
    {
      data: [120, 150, 80, 70, 110, 130],
      type: 'bar',
      clip: false
    }
  ]
};
image

I agree with the saying that it's more intuitive to hide the two bars outside of the grid area. But for the bar at 110, it may be controversial whether or not to clip that part outside of the grid.

@KurtGokhan
Copy link
Author

@Ovilia I see. What do you suggest? Maybe we can introduce a clip: 'strict' option in addition to true/false. For bar chart, it would work like I did in this PR, and for other charts it would work like true.

@Ovilia
Copy link
Contributor

Ovilia commented Jun 21, 2024

@Ovilia I see. What do you suggest? Maybe we can introduce a clip: 'strict' option in addition to true/false. For bar chart, it would work like I did in this PR, and for other charts it would work like true.

I'm making a breaking axis feature for ECharts 6.0 where bars get clipped by default. But I'm still working on it and not sure at this moment what it will ended up to be. I need to consider more carefully on this when I do with breaking axis, which may probably take another few months. So do you mind if we close this PR for now and see how it goes?

@KurtGokhan
Copy link
Author

@Ovilia ok, we can close this. But I need a fix for now because the bar chart clipping with the axis labels seems too wrong:
image

I tried using a custom series. But I couldn't figure out how to do stacked bars with custom series. Any tips or resources you can guide me for doing that?

@Ovilia
Copy link
Contributor

Ovilia commented Jun 21, 2024

Do you want to clip the left-most and right-most bars, or is this acceptable?

@KurtGokhan
Copy link
Author

Yes, I don't want the bars to go out of the grid. I also want it to work reliably with any axis type, i.e. time.

@Ovilia
Copy link
Contributor

Ovilia commented Jun 21, 2024

Then I think custom series is a must. It would be challenging to implement stacking, but since stacking on time axis is also not supported for bar series, using custom series seems to be the only possible solution.

@KurtGokhan
Copy link
Author

KurtGokhan commented Jun 21, 2024

Stacking on time axis is also not supported for bar series

It seems supported. I am using it and it works for me. The only limitation is that all series must have uniform data (all series must have values at same x axis values in the same order).

@Ovilia
Copy link
Contributor

Ovilia commented Jun 24, 2024

Yes, it's supported, sorry I forgot. If you have no objection, perhaps we could close this PR and I will see what we can do when I complete the break axis feature.

@KurtGokhan
Copy link
Author

Tbh, my problem isn't solved. And I don't see how "breaking axes" solves the problem. But you can close the PR.

@grenobnik
Copy link

It is a pity that this PR is closed without further development. I also need to clip the stacked bars to the grid. The proposed "strict" value for clip option sounds like a reasonable solution to not introduce the breaking changes.

Copy link

@mazoqui mazoqui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still does no fix the issue, whether a background is set to the bar serie.
A workaround would require to also clip the bar background in the edges and make not opaque the ones already far from them

Something like below:

.update(function (newIndex, oldIndex) {
                var itemModel = data.getItemModel(newIndex);
                var layout = getLayout[coord.type](data, newIndex, itemModel);
                if (drawBackground) {
                    var isClipped = clip[coord.type](coordSysClipArea, layout);
                    var bgEl;
                    var bgSt;
                    var diff;
                    if (oldBgEls.length === 0) {
                        bgEl = createBackground(oldIndex);
                    }
                    else {
                        bgEl = oldBgEls[oldIndex];
                        bgSt = backgroundModel.getBarItemStyle();
                        if (isClipped) {
                            bgSt.opacity = 0;
                        }
                        bgEl.useStyle(bgSt);
                        // Only cartesian2d support borderRadius.
                        if (coord.type === 'cartesian2d') {
                            bgEl.setShape('r', barBorderRadius);
                        }
                        bgEls[newIndex] = bgEl;
                    }
                    var bgLayout = getLayout[coord.type](data, newIndex);
                    var shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord);
                    if (coord.type === 'cartesian2d') {
                        if (shape.x < coordSysClipArea.x) {
                            diff = coordSysClipArea.x - shape.x;
                            shape.x += diff;
                            shape.width -= diff;
                        }
                        else if ((shape.x + shape.width) > (coordSysClipArea.x + coordSysClipArea.width)) {
                            diff = (shape.x + shape.width) - (coordSysClipArea.x + coordSysClipArea.width);
                            shape.width -= diff;
                        }
                    }
                    updateProps(bgEl, { shape: shape }, animationModel, newIndex);
                }
                var el = oldData.getItemGraphicEl(oldIndex);
                if (!data.hasValue(newIndex)) {
                    group.remove(el);
                    return;
                }

                if (needsClip) {
                    var isClipped = clip[coord.type](coordSysClipArea, layout);
                    if (isClipped) {
                        group.remove(el);
                        return;
                    }
                }
....

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

Successfully merging this pull request may close these issues.

[Bug] Bar Chart bars overflow out of the coordinate system
4 participants