echarts icon indicating copy to clipboard operation
echarts copied to clipboard

feat: support `stackPercent` for normalized stacking

Open sjcobb opened this issue 8 months ago • 10 comments

Brief Information

This pull request is in the type of:

  • [ ] bug fixing
  • [x] new feature
  • [ ] others

What does this PR do?

Adds support for stackPercent: boolean, which normalizes all stacked series values into percentages per category index (so the stacked total always adds up to 100%).

Fixed issues

  • #17179

Details

Before: What was the problem?

No built-in way to compute percent-stacked values across a stack group without pre-processing data (see bar-stack-normalization example).

image

image

After: How does it behave after the fixing?

When stackPercent: true is set on a stacked series, values are automatically normalized to percentages per category. Tooltip shows both raw value and percentage.

image

image

With formatters: image

Document Info

One of the following should be checked.

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

Misc

ZRender Changes

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

Related test cases or examples to use the new APIs

bar-stack-normalization

Others

Merging options

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

Other information

sjcobb avatar Apr 10 '25 15:04 sjcobb

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.

Document changes are required in this PR. Please also make a PR to apache/echarts-doc for document changes and update the issue id in the PR description. When the doc PR is merged, the maintainers will remove the PR: awaiting doc label.

echarts-bot[bot] avatar Apr 10 '25 15:04 echarts-bot[bot]

And I'm not sure how to let the axis know that this is a normalized series and should use % in the axis labels. Maybe it's still necessary to set formatter: (params) => Math.round({params or params.value} * 1000) / 10 + '%' both in series.label and yAxis.axisLabel. Do you have any better ideas?

Ovilia avatar Apr 11 '25 07:04 Ovilia

If we are going to support normalized stacking, it should not use stackStrategy because this concept is for deciding whether to stack positive/negative values. You should probably need another new option for this feature.

Stacking by percentage can be supported with current ECharts with a little hacking so it should be nice to have this feature to make the option more intuitive. Thanks for your contribution.

Yeah this makes sense, I found an older discussion on this topic here where you proposed: stackPercent: true

I went ahead and made that change in this commit but open to any other ideas!

sjcobb avatar Apr 11 '25 15:04 sjcobb

And I'm not sure how to let the axis know that this is a normalized series and should use % in the axis labels. Maybe it's still necessary to set formatter: (params) => Math.round({params or params.value} * 1000) / 10 + '%' both in series.label and yAxis.axisLabel. Do you have any better ideas?

Agreed this seems difficult, I think starting with requiring the custom formatter can work (I can point this out in docs / create a new example).

I played around with setting the axisLabel formatter automatically (when one isn't already defined) in this branch, but that doesn't seem like a great solution

EDIT: Added examples in percent-stack.html here

sjcobb avatar Apr 11 '25 16:04 sjcobb

Maybe you should set the axis max to 100%? Otherwise the total value maybe 1.00000001(due to precision lost)and causes the max value to be 120%

Justin-ZS avatar Apr 21 '25 01:04 Justin-ZS

Maybe you should set the axis max to 100%? Otherwise the total value maybe 1.00000001(due to precision lost)and causes the max value to be 120%

Yeah good call, it is a little awkward to do this for similar reasons as here but I'll look into it more. This PR is already pretty large, @Ovilia would you prefer I open a separate PR to adjust the axis max / formatter or keep adding to this one?

sjcobb avatar Apr 28 '25 18:04 sjcobb

Hi, based on this PR. How can we get the raw value/total value so that we can customize the datalabel/tooltip with label.formatter/tooltip.formatter?

Justin-ZS avatar May 06 '25 08:05 Justin-ZS

Do you happen to have any updates here? wish to see this pr be merged, it's beneficial

yuicer avatar May 22 '25 08:05 yuicer

Hi, based on this PR. How can we get the raw value/total value so that we can customize the datalabel/tooltip with label.formatter/tooltip.formatter?

Raw value is still included and the normalized value was added in series label and tooltip formatter as percent (I reused this since it was already in types from 'pie' series), example:

https://github.com/apache/echarts/blob/1d0603fe492fc10ced8a48631de5a18f1d5a011e/test/percent-stack.html#L182-L187

image

sjcobb avatar May 23 '25 18:05 sjcobb

Do you happen to have any updates here? wish to see this pr be merged, it's beneficial

Glad to hear you find it useful! I just opened a docs PR so I'm waiting on more feedback on the initial implementation and the new option name stackPercent.

Hoping to add enhancements like appending '%' to series label / yAxis.axisLabel and setting yAxis.max to 100 automatically in a later PR (since they can be set explicitly as shown in percent-stack.html example)

sjcobb avatar May 23 '25 19:05 sjcobb

Rebased and fixed all merge conflicts from the stackOrder PR #20998

sjcobb avatar Aug 15 '25 17:08 sjcobb