3 September 2007
Overview of axis rounding
(A pdf version of this discussion with equations, and source code with documentation are available. Alternatively, just the documentation is available on-line.)
Update There were some problems with the original code, but they are all solved now. There were just silly bugs: one variable was a unsigned and should have been an int etc.
I have been quite bored recently so in a search for something to do that was potential useful I ‘wrote up’ some of my recent experiments with rounding axis values. The main problem to solve is how to place tic marks at nice interval along the axis, if your axis doesn’t start with nice rounded numbers. The solution, I hear you say, is to round the the axis start and top values. However this can only be done once the axis spacing is known! Moreover, we cannot find out how to round the axis start and stop values with out knowledge of how we have rounded them!
Axis Definitions
Before we continue let’s make some definitions:

The range is clearly the end minus the start value, NB this is assumed to always be positive, so start must always be less than stop. The spacing is the separation, in axis units, between tic marks. The interval is the number of tic marks placed along the axis.
We can then generate equations which describe; the axis spacing as a function of the range and interval number; and the number of intervals as a function of range and spacing. This is the interdependency that I refereed to previously.
Rounding
The example axis above is fortunate because we started with rounded values. However, what happens if the start value was 0.2 and the stop value was 3.7? We would still want exactly the same spacing. That is, we would want 0.2 to rounded down to 0 and 3.7 to be rounded up to 4.
This can be achieved using ceil() and floor() functions from math.h, along with a guess value for the axis spacing.
Algorithm to find spacing
The number of axis intervals should be some manageable mount, a number less than 4 is too few, while more than 11 is overkill. The basis for finding the rounded axis spacing is to try a few guess spacing and see which one produce intervals in the desired range. There are also a few clues that we can use to quickly find the spacing, and when this is done it takes no more than 6 iteration to acquire the result.
AxisRounding Source Code
The above algorithm is used below in the function MakeSpacing(). Here we get clues for the guess value from looking at the decade of the axis range,

Now we set the guess values. The trick is to scale the guess values to the same range as the axis. The axis decade has been rounded down using floor() and as such we start our search in the lower decade and then more through to the higher one. This range will cover all possible solutions that fall into our tic mark range.

Finally, calculate the number of intervals for the current guess spacing. If this falls into the our desired range for the number of intervals, we return the value.

Please find the source code and documentation of how to use the axis spacing functions in the links above.
Example Use
double start = 400;
double stop = 800;
double spacing = MakeSpacing(start, stop);
unsigned interval = MakeInterval(start, stop);
PrintDescription(start, stop, spacing, interval);
/*
Axis Description:
start = 400
stop = 800
spacing = 50
interval = 9
(400, 450, 500, 550, 600, 650, 700, 750, 800)
*/

