Skip to content

fix(charts): grouped bars emanate from the zero baseline#200

Merged
DemchaAV merged 2 commits into
developfrom
fix/grouped-bar-zero-baseline
Jun 16, 2026
Merged

fix(charts): grouped bars emanate from the zero baseline#200
DemchaAV merged 2 commits into
developfrom
fix/grouped-bar-zero-baseline

Conversation

@DemchaAV

Copy link
Copy Markdown
Owner

Why

Grouped (non-stacked) bar charts measured each bar's height from the axis
nice-floor rather than zero. On an axis that crosses zero this rendered a
negative value as a short upward column anchored at the floor — visually
indistinguishable from a small positive — and let positive bars overshoot
below zero. Stacked bars were already pinned to zero, so the two groupings
disagreed.

What changed

BarChartLayout now anchors both orientations to the zero baseline, clamped
into the visible range by the new baselineValue(NiceScale) helper
(max(niceMin, min(0, niceMax))):

  • Positive bars grow away from zero; negative bars hang back across it; the two
    meet exactly at the zero line (heights proportional to |value|).
  • When zero is off-scale — an explicit non-zero valueAxis().min(...) or
    baselineAtZero(false) over a range that excludes zero — the baseline clamps
    to the nearest visible bound, so a deliberately zoomed axis still anchors its
    bars at the plot floor (explicitAxisBoundsAreHonored keeps passing).
  • Value labels follow the bar's far end: above/right for positive, below/left
    for negative.
  • The stacked path is untouched. Charts with positive data on a zero-based axis
    are byte-identical.

ChartShowcaseExample gains a mixed +/- net-cash-flow card; the committed
assets/readme/chart-showcase.{pdf,png} previews are regenerated.

Verification

  • ./mvnw test -pl . → BUILD SUCCESS, 1384 tests, 0 failures.
  • ChartLayoutResolverTest: rewrote the negative-grouped case to assert bars
    meet at zero with heights proportional to |value|; added horizontal,
    positive-min-clamp, and OUTSIDE-label-side cases. Mutation-checked — copying
    either negative value-label arm into its positive counterpart turns the new
    label tests red.

Lane: canonical (document.chart). No public API change (baselineValue is
package-private); japicmp unaffected.

DemchaAV added 2 commits June 16, 2026 23:18
Grouped (non-stacked) bars measured their height from the axis nice-floor,
so on an axis that crossed zero a negative value rendered as a short upward
column anchored at the floor — visually indistinguishable from a small
positive — and positive bars overshot below zero.

BarChartLayout now anchors both orientations to the zero baseline (clamped
into the visible range via the new baselineValue helper): positive bars grow
away from zero, negatives hang back across it, and value labels sit past the
bar's far end. When zero is off-scale — an explicit non-zero valueAxis().min()
or baselineAtZero(false) over a range that excludes zero — the baseline clamps
to the nearest visible bound, so a deliberately zoomed axis still anchors its
bars at the plot floor. Charts with positive data on a zero-based axis are
byte-identical.

Tests: ChartLayoutResolverTest rewrites the negative grouped case to assert
the positive and negative bars meet at zero with heights proportional to
|value|, and adds horizontal and positive-min-clamp cases; ChartShowcaseExample
gains a mixed +/- net-cash-flow card. ./mvnw test -pl . green (1382).
The grouped-bar value-label arms had no test pairing ValueLabelMode.OUTSIDE
with a negative value, so a label rendered on the wrong side of a negative
bar would still pass. Add a vertical case (positive label above the top,
negative below the bottom) and a horizontal case (positive past the right
end, negative past the left end). Both fail if either negative arm is
collapsed into its positive counterpart.
@DemchaAV DemchaAV merged commit fd5ba32 into develop Jun 16, 2026
11 checks passed
@DemchaAV DemchaAV deleted the fix/grouped-bar-zero-baseline branch June 16, 2026 22:54
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.

1 participant