Algorithm for nice grid line intervals on a graph
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Good grid lines make a chart feel obvious. Readers can estimate values quickly because the axis labels land on familiar numbers instead of awkward steps such as 37 or 83.
The usual goal is not to force an exact number of lines. It is to choose spacing that covers the data range, keeps the chart uncluttered, and uses values that people can scan without doing mental arithmetic.
What Makes an Interval "Nice"
Most graphing systems build tick intervals from a small set of values scaled by powers of ten. Common candidates are , , , , and times .
That produces steps such as 0.1, 0.2, 0.5, 1, 2, 5, 20, 50, and 200. These values are easy to label and easy to compare, which is why chart libraries and plotting tools tend to favor them.
If you divide a range directly by a target tick count, you usually get a raw step that is mathematically correct but visually annoying. For a range from 32 to 258 with about 6 ticks, the raw step is:
That is a reasonable intermediate value, but it is not a good label spacing. An axis labeled 32, 77.2, 122.4, 167.6 is much harder to read than one labeled in clean multiples of 50.
The Core Algorithm
The standard solution is a small rounding algorithm.
First, compute the raw step from the requested number of ticks:
Next, find the power-of-ten scale of that number:
Then normalize the raw step into a fraction between and :
Now pick the nearest nice fraction from your candidate set. In a common implementation, a fraction near 4.52 rounds to 5. The final step becomes:
With the earlier example, the raw step is 45.2, so and the normalized fraction is 4.52. Rounding that to the nice fraction 5 gives a final step of 50.
The last step is expanding the visible axis so the first and last grid lines also land on clean multiples:
For 32 through 258 with a step of 50, that gives 0 through 300. The chart becomes slightly wider than the raw data range, but the labels are far easier to interpret.
JavaScript Example
The following implementation is small enough to drop into a plotting utility or use before rendering an SVG or canvas chart.
The two important details are that niceNumber can either round or expand, and that toFixed keeps floating-point noise out of the labels.
If you want denser labels, increase targetTicks. If you want a tighter fit, you can use a richer candidate set, but the axis may stop looking familiar.
Why This Works Well in Practice
This algorithm is popular because it behaves consistently across wildly different scales. It works for values around 0.003, around 250, and around 3,000,000 without needing separate rules for each range.
It also reflects how people read charts. Viewers generally do not care whether the mathematical optimum step is 43.8 or 47.1. They care whether they can glance at the axis and understand the chart immediately. Nice intervals optimize for that human requirement.
Common Pitfalls
One common mistake is treating the requested tick count as a hard requirement. In practice it is only a hint. A chart with seven clean ticks is usually better than a chart with exactly six ugly ones.
Another mistake is using ordinary decimal rounding on the raw step. That can produce intervals such as 40 or 37.5. Those may be acceptable in special domains, but they are not part of the standard nice-number progression most graphing tools use.
Floating-point drift is another source of confusion. Repeated addition can produce values like 0.30000000000000004, which is why it is worth rounding tick values before display.
Finally, this algorithm is for linear axes. Logarithmic axes are a different problem because their ticks are based on multiplicative jumps rather than additive ones.
Summary
- Nice grid intervals usually come from a small set of values scaled by powers of ten.
- Start with a raw step, normalize it, and round it to a nearby nice fraction.
- Expand the axis bounds to clean multiples of the final step so the whole range is covered.
- The target number of ticks is a guideline, not a strict promise.
- A short implementation can generate readable axis labels consistently across many datasets.

