Skip to content

fix(stacker): correct stacking for mixed positive/negative values (#2073, #2152) - #2173

Merged
beto-rodriguez merged 2 commits into
masterfrom
fix/issue-2152-stacker-mixed-signs
Apr 26, 2026
Merged

fix(stacker): correct stacking for mixed positive/negative values (#2073, #2152)#2173
beto-rodriguez merged 2 commits into
masterfrom
fix/issue-2152-stacker-mixed-signs

Conversation

@beto-rodriguez

Copy link
Copy Markdown
Collaborator

Summary

Background

PR #2085 tried to fix #2073 by accumulating every value into both End and NegativeEnd. That gave area charts a continuous baseline but corrupted both tracks: column/row series above a series with a negative value started their positive bar from the negative end (e.g. -52.89) instead of 0 — the visible bug in #2152's docs sample.

The two needs are genuinely different:

Series Stacking semantics
Stacked column / row Positives stack up from 0; negatives stack down from 0; streams are independent.
Stacked area / step-area / line Single running cumulative — baseline must stay continuous when values cross zero.

So Stacker now keeps both: sign-segregated End / NegativeEnd for columns and rows, plus CumulativeEnd for area/line.

Test plan

  • dotnet test --project tests/CoreTests/ --framework net8.0 — 453/453 pass, including the rewritten ShouldHandleMixedPositiveNegativeValues tests for stacked area and stacked step area.
  • dotnet test --project tests/SnapshotTests/ — 100/100 pass, including the new StackedAreaTests.Issue2073_MixedSigns and StackedRowSeriesTests.Issue2152_MixedSigns regressions.
  • StackedColumnsTests_Basic baseline regenerated (the previous baseline locked in PR Fix stack calculation for positive and negative values #2085's broken rendering at indices with mixed signs).

🤖 Generated with Claude Code

… signs

PR #2085 fixed stacked area with mixed signs (#2073) by accumulating every
value into both End and NegativeEnd. That gave area charts an Excel-like
continuous baseline but broke stacked column/row series (#2152): a positive
bar above a previous negative value started at the negative end instead of 0.

Column/row stacks need positives and negatives in separate streams (each grows
from 0 in its own direction). Area/line stacks need a single running total to
keep the baseline continuous when values cross zero. Stacker now exposes both:
End/NegativeEnd are sign-segregated again, and a new CumulativeStart/CumulativeEnd
track always accumulates regardless of sign. CoreLineSeries and
CoreStepLineSeries read the cumulative track when stacked.

Snapshot regressions added for #2073 and #2152. The previous
StackedColumnsTests_Basic baseline was captured under the buggy behavior and
has been regenerated. The CoreTests ShouldHandleMixedPositiveNegativeValues
tests for stacked area / step area, which had been written to assert PR #2085's
broken numbers, now assert the correct dual-track + cumulative semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 26, 2026 15:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes stacking semantics for mixed positive/negative values by restoring sign-segregated stacking for bar/column/row series while adding a separate cumulative stacking track for stacked line/area series to keep an Excel-like continuous baseline.

Changes:

  • Restore sign-segregated Start/End vs NegativeStart/NegativeEnd stacking for bars/columns/rows and introduce CumulativeStart/CumulativeEnd for continuous stacked line/area baselines.
  • Update CoreLineSeries and CoreStepLineSeries to use the cumulative stacking track when stacked.
  • Add/refresh core + snapshot regression tests and update snapshot baselines for issues #2073 and #2152.

Reviewed changes

Copilot reviewed 8 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/LiveChartsCore/Kernel/Stacker.cs Implements cumulative stacking track while keeping positive/negative tracks sign-segregated.
src/LiveChartsCore/Kernel/StackedValue.cs Adds CumulativeStart/CumulativeEnd to expose cumulative stacking offsets.
src/LiveChartsCore/CoreLineSeries.cs Switches stacked line baseline offset to CumulativeStart.
src/LiveChartsCore/CoreStepLineSeries.cs Switches stacked step-line baseline offset to CumulativeStart.
tests/CoreTests/SeriesTests/StackedAreaSeriesTest.cs Rewrites mixed-sign stacking assertions to validate the new three-track semantics.
tests/CoreTests/SeriesTests/StackedStepAreaSeriesTest.cs Same as above for stacked step-area.
tests/SnapshotTests/StackedAreaTests.cs Adds snapshot regression for #2073 mixed-sign stacked area.
tests/SnapshotTests/StackedRowSeriesTests.cs Adds snapshot regression for #2152 mixed-sign stacked rows.
tests/SnapshotTests/Snapshots/StackedAreaTests_Issue2073_MixedSigns.png New snapshot baseline for #2073 regression.
tests/SnapshotTests/Snapshots/StackedRowSeriesTests_Issue2152_MixedSigns.png New snapshot baseline for #2152 regression.
tests/SnapshotTests/Snapshots/StackedColumnsTests_Basic.png Regenerated baseline to reflect corrected stacking behavior.

Comment thread src/LiveChartsCore/Kernel/Stacker.cs
@github-actions

github-actions Bot commented Apr 26, 2026

Copy link
Copy Markdown

Thanks for your contribution!

Benchmark delta — ✅ 6 improvements, no regressions

Show details

Base: master — Head: c8cdd0b (run)
Thresholds: 🔴 > +10% slower, 🟢 > -10% faster. Numbers on GitHub-hosted runners are noisy — treat double-digit deltas on non-trivial benchmarks as signal, single-digit as noise.

Benchmark Base (ms) Head (ms) Δ Alloc base Alloc head
BoxSeriesBench.Reinvalidate 12.552 12.244 -2.5% 631.4 KB 631.4 KB
BoxSeriesBench.UpdateOnePoint 12.550 12.300 -2.0% 631.5 KB 631.5 KB
CandlesticksSeriesBench.Reinvalidate 12.061 11.265 -6.6% 657.3 KB 657.3 KB
CandlesticksSeriesBench.UpdateOnePoint 12.901 11.257 🟢 -12.7% 657.5 KB 657.5 KB
ColumnSeriesBench.Reinvalidate 6.321 5.447 🟢 -13.8% 524.5 KB 524.5 KB
ColumnSeriesBench.UpdateOnePoint 6.075 5.424 🟢 -10.7% 518.3 KB 518.3 KB
HeatSeriesBench.Reinvalidate 3.449 2.870 🟢 -16.8% 502.4 KB 502.4 KB
HeatSeriesBench.UpdateOnePoint 3.356 2.860 🟢 -14.8% 502.4 KB 502.4 KB
LineSeriesBench.FirstRender(PointCount: 1000) 22.799 18.781 🟢 -17.6% 3.2 MB 3.2 MB
LineSeriesBench.FirstRender(PointCount: 10000) 171.567 183.617 +7.0% 27.5 MB 27.5 MB
LineSeriesBench.Reinvalidate(PointCount: 1000) 16.517 16.011 -3.1% 801.1 KB 801.1 KB
LineSeriesBench.Reinvalidate(PointCount: 10000) 147.286 148.207 +0.6% 4.0 MB 4.0 MB
LineSeriesBench.ToggleNullGap(PointCount: 1000) 17.102 16.270 -4.9% 849.7 KB 849.7 KB
LineSeriesBench.ToggleNullGap(PointCount: 10000) 148.316 143.662 -3.1% 4.4 MB 4.4 MB
LineSeriesBench.UpdateOnePoint(PointCount: 1000) 16.358 16.116 -1.5% 801.2 KB 801.2 KB
LineSeriesBench.UpdateOnePoint(PointCount: 10000) 143.764 144.115 +0.2% 4.0 MB 4.0 MB
PieSeriesBench.Reinvalidate 1.491 1.350 -9.5% 96.6 KB 97.2 KB
PieSeriesBench.UpdateOnePoint 1.506 1.373 -8.8% 96.6 KB 97.3 KB
PolarLineSeriesBench.Reinvalidate 14.395 14.433 +0.3% 637.6 KB 637.6 KB
PolarLineSeriesBench.UpdateOnePoint 15.558 14.665 -5.7% 637.6 KB 637.7 KB
ScatterSeriesBench.Reinvalidate 6.734 6.154 -8.6% 528.0 KB 528.0 KB
ScatterSeriesBench.UpdateOnePoint 6.626 6.109 -7.8% 521.8 KB 521.8 KB
StackedAreaSeriesBench.Reinvalidate 5.143 5.248 +2.1% 1.7 MB 1.9 MB
StackedAreaSeriesBench.UpdateOnePoint 5.039 5.242 +4.0% 1.7 MB 1.9 MB
StepLineSeriesBench.Reinvalidate 16.086 15.836 -1.6% 722.8 KB 722.8 KB
StepLineSeriesBench.ToggleNullGap 16.790 15.751 -6.2% 771.3 KB 771.3 KB
StepLineSeriesBench.UpdateOnePoint 15.866 15.834 -0.2% 722.8 KB 722.8 KB

Build summary for run #347.

Packing ✅

Download the NuGet packages for this build here (dev-347). Available for 30 days — you can either use them directly or wait for this PR to be merged to have them published to NuGet.org.

Tests ✅

Show details
  • Avalonia
    • desktop (windows) ✅ — trx
    • desktop (linux) ✅ — trx
    • desktop (mac) ✅ — trx
    • android ✅ — trx
    • ios ✅ — trx
    • browser ✅ — trx
  • Uno
    • desktop (windows) ✅ — trx
    • win10.0.19041 (windows) ✅ — trx
    • desktop (linux) ✅ — trx
    • desktop (mac) ✅ — trx
  • MAUI
    • windows ✅ — trx
    • maccatalyst ✅ — trx
    • android ✅ — trx
    • ios ✅ — trx
  • WinUI
    • windows ✅ — trx
  • WinForms
    • net10 (windows) ✅ — trx
    • net10-19041 (windows) ✅ — trx
    • net462 (windows) ✅ — trx
  • WPF
    • net10 (windows) ✅ — trx
    • net10-19041 (windows) ✅ — trx
    • net462 (windows) ✅ — trx
  • Eto
    • windows ✅ — trx
    • mac ✅ — trx
  • Core
    • net8.0 ✅ — trx
    • net462 ✅ — trx
  • Snapshot
    • snapshot ✅ — trx

Code Coverage ➡️

Line Coverage
Before 80.3%
After 80.3%
Delta 0%

Aligns CorePolarLineSeries with the cartesian line/step-line variants now that
mixed-sign stacking has separate cumulative semantics. Polar line stacking
with mixed signs was a pre-existing gap — the spline only ever read .Start
and never sign-switched — but for consistency with the other line variants,
use CumulativeStart so polar stacked lines get the same continuous baseline.

Addresses Copilot review feedback on PR #2173.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@beto-rodriguez
beto-rodriguez merged commit 25e7a21 into master Apr 26, 2026
47 checks passed
@beto-rodriguez
beto-rodriguez deleted the fix/issue-2152-stacker-mixed-signs branch April 26, 2026 17:04
beto-rodriguez added a commit that referenced this pull request Apr 28, 2026
pm-kuerten pushed a commit to pm-kuerten/LiveCharts2 that referenced this pull request Jul 6, 2026
…tacker-mixed-signs

fix(stacker): correct stacking for mixed positive/negative values (Live-Charts#2073, Live-Charts#2152)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StackedRowSeries display bug StackedAreaSeries will not display correctly with Negative value

2 participants