Skip to content

fix(axes): add MinSeparators floor so auto-step keeps grids readable (#2071) - #2180

Merged
beto-rodriguez merged 3 commits into
masterfrom
fix/issue-2071-min-separators
Apr 28, 2026
Merged

fix(axes): add MinSeparators floor so auto-step keeps grids readable (#2071)#2180
beto-rodriguez merged 3 commits into
masterfrom
fix/issue-2071-min-separators

Conversation

@beto-rodriguez

Copy link
Copy Markdown
Collaborator

Summary

  • Closes Grid Separator Count #2071. The auto-step snap (1, 2, 5, 10 × magnitude) could leap a whole tier on short axes with awkward ranges, leaving only 1–2 separators visible — the exact case the issue reports.
  • Adds int MinSeparators to IPlane (default 3) implemented on CoreAxis and CorePolarAxis. After computing the nice-number tick, both GetTick overloads now walk the ladder downward (10 → 5 → 2 → 1 → 0.5 → 0.2 → …) until range / tick >= MinSeparators.
  • ForceStepToMin still wins — when the user pinned the step explicitly we don't second-guess them. Setting MinSeparators = 0 opts out entirely.

Why default to 3

Quoting the issue author: "I would prefer an ugly graph over an unreadable one." Three separators is the smallest count where the axis communicates a scale (min, mid, max) instead of a single landmark.

Test plan

  • dotnet run --project tests/CoreTests/CoreTests.csproj --framework net8.0 — all 461 pass
  • dotnet run --project tests/SnapshotTests/SnapshotTests.csproj --framework net10.0 — all 102 pass (no existing baselines shifted)
  • New snapshot tests AxesTests.MinSeparatorsFloor and AxesTests.MinSeparatorsDisabled cover the on/off behavior on the same 400×120 short chart with range = 11:
    • With the default floor: Y axis renders 0 / 5 / 10 (3 separators).
    • With MinSeparators = 0: Y axis renders only 0 (the original buggy behavior, locked in to prove opt-out).

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 27, 2026 17:52
@beto-rodriguez
beto-rodriguez force-pushed the fix/issue-2071-min-separators branch from ade2574 to b11d7a1 Compare April 27, 2026 17:55

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 addresses axis auto-tick selection on short/compact charts by introducing a minimum separator count floor, ensuring automatic step “nice-number” snapping doesn’t result in only 1–2 visible grid separators.

Changes:

  • Added MinSeparators to IPlane (default 3) and implemented it in CoreAxis and CorePolarAxis.
  • Updated Cartesian and Polar GetTick calculations to step down the “nice-number ladder” until range / tick >= MinSeparators (unless ForceStepToMin or MinSeparators <= 0).
  • Added snapshot tests and baselines covering the default floor behavior and opt-out (MinSeparators = 0).

Reviewed changes

Copilot reviewed 5 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/LiveChartsCore/Kernel/Sketches/IPlane.cs Introduces the new MinSeparators API surface on planes/axes.
src/LiveChartsCore/CoreAxis.cs Implements MinSeparators (default 3) for Cartesian axes.
src/LiveChartsCore/CorePolarAxis.cs Implements MinSeparators (default 3) for polar axes.
src/LiveChartsCore/Kernel/Extensions.cs Enforces the MinSeparators floor during tick selection for both Cartesian and Polar axes.
tests/SnapshotTests/AxesTests.cs Adds snapshot tests covering floor enabled vs disabled behavior.
tests/SnapshotTests/Snapshots/AxesTests_MinSeparatorsFloor.png New baseline image for default floor behavior.
tests/SnapshotTests/Snapshots/AxesTests_MinSeparatorsDisabled.png New baseline image for opt-out behavior (MinSeparators = 0).

Comment thread src/LiveChartsCore/Kernel/Extensions.cs Outdated
Comment thread src/LiveChartsCore/Kernel/Sketches/IPlane.cs
@livecharts

livecharts Bot commented Apr 27, 2026

Copy link
Copy Markdown

Thanks for your contribution!

Benchmark delta — ✅ 3 improvements, no regressions

Show details

Base: master — Head: 7025abc (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 11.975 12.016 +0.3% 631.4 KB 631.4 KB
BoxSeriesBench.UpdateOnePoint 12.127 12.943 +6.7% 631.5 KB 631.5 KB
CandlesticksSeriesBench.Reinvalidate 10.960 10.963 0.0% 657.3 KB 657.3 KB
CandlesticksSeriesBench.UpdateOnePoint 11.079 10.882 -1.8% 657.5 KB 657.5 KB
ColumnSeriesBench.Reinvalidate 5.299 5.289 -0.2% 524.5 KB 524.5 KB
ColumnSeriesBench.UpdateOnePoint 5.240 5.302 +1.2% 518.3 KB 518.3 KB
HeatSeriesBench.Reinvalidate 2.703 2.733 +1.1% 502.4 KB 502.4 KB
HeatSeriesBench.UpdateOnePoint 2.744 2.820 +2.8% 502.4 KB 502.4 KB
LineSeriesBench.FirstRender(PointCount: 1000) 19.630 19.806 +0.9% 3.2 MB 3.9 MB
LineSeriesBench.FirstRender(PointCount: 10000) 198.084 191.468 -3.3% 27.5 MB 27.5 MB
LineSeriesBench.Reinvalidate(PointCount: 1000) 16.630 16.563 -0.4% 801.1 KB 801.2 KB
LineSeriesBench.Reinvalidate(PointCount: 10000) 159.873 158.540 -0.8% 4.0 MB 4.0 MB
LineSeriesBench.ToggleNullGap(PointCount: 1000) 16.475 16.567 +0.6% 849.7 KB 849.7 KB
LineSeriesBench.ToggleNullGap(PointCount: 10000) 160.591 154.512 -3.8% 4.4 MB 4.4 MB
LineSeriesBench.UpdateOnePoint(PointCount: 1000) 16.741 16.664 -0.5% 801.2 KB 801.2 KB
LineSeriesBench.UpdateOnePoint(PointCount: 10000) 160.620 154.227 -4.0% 4.0 MB 4.0 MB
PieSeriesBench.Reinvalidate 0.965 0.928 -3.9% 97.2 KB 97.2 KB
PieSeriesBench.UpdateOnePoint 0.962 0.950 -1.2% 97.3 KB 97.3 KB
PolarLineSeriesBench.Reinvalidate 15.824 14.264 -9.9% 637.6 KB 637.6 KB
PolarLineSeriesBench.UpdateOnePoint 15.430 14.397 -6.7% 637.7 KB 637.6 KB
ScatterSeriesBench.Reinvalidate 6.500 5.770 🟢 -11.2% 528.0 KB 528.0 KB
ScatterSeriesBench.UpdateOnePoint 6.869 5.746 🟢 -16.3% 521.8 KB 521.8 KB
StackedAreaSeriesBench.Reinvalidate 5.980 4.997 🟢 -16.4% 1.9 MB 1.9 MB
StackedAreaSeriesBench.UpdateOnePoint 5.600 5.049 -9.8% 1.9 MB 1.9 MB
StepLineSeriesBench.Reinvalidate 17.000 16.048 -5.6% 722.8 KB 722.8 KB
StepLineSeriesBench.ToggleNullGap 16.820 16.701 -0.7% 771.2 KB 771.3 KB
StepLineSeriesBench.UpdateOnePoint 16.294 16.126 -1.0% 722.8 KB 722.8 KB

Build summary for run #359.

Packing ✅

Download the NuGet packages for this build here (dev-359). 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

Comment thread src/LiveChartsCore/Kernel/Extensions.cs Fixed
beto-rodriguez and others added 3 commits April 27, 2026 12:18
The auto-step logic snaps the calculated step up to a nice number
(1, 2, 5, 10 x magnitude). On short axes with awkward ranges this
could leap a whole tier and leave only 1-2 separators in view, which
is what issue #2071 reports. Add a MinSeparators property on IPlane
(default 3) and walk the nice-number ladder downward when the snap-up
would yield fewer separators than requested. ForceStepToMin still wins
since the user explicitly pinned the step there.

The ladder uses thresholds at the bucket midpoints (7.5, 3.5, 1.5)
rather than exact comparisons so floating-point noise on tick/magnitude
(e.g. 9.999... when both were derived from 10 * 0.1) cannot skip a tier.
The magnitude underflow guard uses !(m > 0) so NaN is also caught.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pair of tests on the same 400x120 short chart with values [0, 11]:
MinSeparatorsFloor exercises the default behavior (Y axis renders
0/5/10) and MinSeparatorsDisabled locks in the original snap-up
behavior with MinSeparators=0 (Y axis renders only 0), proving the
opt-out path stays available.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a section right after MinStep on docs/cartesianChart/axes.md
that describes the new floor on the auto-step (default 3), how to
opt out (MinSeparators = 0), and the interaction with ForceStepToMin.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 27, 2026 18:19
@beto-rodriguez
beto-rodriguez force-pushed the fix/issue-2071-min-separators branch from 3ad533c to 7025abc Compare April 27, 2026 18:19
Comment thread src/LiveChartsCore/Kernel/Extensions.cs

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

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

@beto-rodriguez
beto-rodriguez merged commit 5b52fb5 into master Apr 28, 2026
95 of 96 checks passed
@beto-rodriguez
beto-rodriguez deleted the fix/issue-2071-min-separators branch April 28, 2026 05:39
pm-kuerten pushed a commit to pm-kuerten/LiveCharts2 that referenced this pull request Jul 6, 2026
…in-separators

fix(axes): add MinSeparators floor so auto-step keeps grids readable (Live-Charts#2071)
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.

Grid Separator Count

2 participants