Chart.js icon indicating copy to clipboard operation
Chart.js copied to clipboard

Chart fill mode 'stack' - negative values

Open jacobsorme opened this issue 2 years ago • 3 comments

Expected behavior

When using fill mode stack (fill: 'stack') I expect:

  • All lines to be stacked on top of each other, even if some data points or data sets are negative
  • Areas under lines to be stacked, even if some data points or data sets are negative
  • Stacks to have the area end at 'origin' - or at least an option to enable it

Current behavior

Currently the top of the stacks does not represent the sum of the values, if some dataset values are negative. The areas under the datasets look strange. There is no (?) Option to have stacking and have the area under the lines end at origin.

image

Figure 1: Stacking of total values, sum of these data points should be 20. The peak of the stacked values end up at 25.



image Figure 2: Stacking with tooltip info

Reproducible sample

https://jsbin.com/tayareqige/1/edit?html,output

Optional extra steps/info to reproduce

No response

Possible solution

  • Add new fill modes, e.g. fill: {stack: 'origin'}, fill: {stack: 'start'}, fill: 'stack-origin'
  • Change existing fill mode "stack"
image

Figure 3: Montage of an example solution, where the constant-value green dataset is stacked on top of the negative red dataset, and where the pink and red datasets cancel out -- having the total/sum stay the same thoughout. The red dataset has no area.

Context

I am trying to have negative values in a stacked area chart, having one negative and one positive data set cancel out.

chart.js version

v3.7.1

Browser name and version

Safari

Link to your project

No response

jacobsorme avatar Mar 02 '22 19:03 jacobsorme

Tagging as an enhancement because it's working as designed right now. We designed this to have positive and negative stacks separate. Some new configuration would be required to have a single stack mixed with positive and negative numbers. I do think that it will cause the fill to look weird if the datasets are not sorted in a good order. I don't think we'd want to change the dataset order on a per datapoint basis because it would make things visually very weird.

@kurkle @LeeLenaleee any ideas?

etimberg avatar Apr 03 '22 16:04 etimberg

It looks like the negative fill is not based on the origin, so that would be a bug in current behavior.

For the desired behavior, the stacking would need another mode, the lines need to be drawn in the desired locations without the fill first, before fill can work.

We also have 'single' mode for stacking, which stacks positive and negative together. But I guess its not what you are looking for:

image

https://jsbin.com/raloyawoca/1/edit?html,output

kurkle avatar Apr 03 '22 16:04 kurkle

I looked around a bit and made some changes. As you say this negative stacking is not that trivial.

A suggestion for an assumption that the negative stacking could be based upon is that the negative datasets are in the very beginning of the dataset list. That would visually look the best, bit I think it would still require a bit more looking around when creating the boundary lines. For example, not only looking at linesBelow but also e.g. linesAbove, since the negative stacking is "upside down" with the current behavior of stacking the lines starting with the first dataset closest to origin.

As you say @etimberg handling dataset order on a per datapoint basis sounds complex and weird.

Changing the applyStack to skip the check of sign(value) === sign(otherValue)), as well as handling the boundary lines in a bit more dynamic manner could result in something like this (still with stacking targets weird): image

Having the order of datasets change on the negative side (e.g. having green stack towards red instead of blue when negative) would make the stacking look nice. But again, this sounds very complex to do.

Compared to originally: image

jacobsorme avatar Apr 05 '22 19:04 jacobsorme