I am the author of the " Optimal Scaling Algorithm on the Chart Axis ". It used to be hosted on trollop.org, but recently I switched to domain / blog servers. In any case, I will post content here for easy access.
I was working on an Android graphics application for assignment and ran into a problem when it came to presenting the chart in a well-scaled format. I spent some time trying to create this algorithm myself, and came terribly close, but in the end I found an example of pseudo-code in a book called Gemstone Graphics, Volume 1 by Andrew S. Glassner. An excellent description of the problem is provided in the Nice Numbers for Graph Labels chapter:
When creating a graph using a computer, it is advisable to designate x and y with "good" numbers: simple decimal numbers. For example, if the data range is from 105 to 543, we probably want to build a range from 100 to 600 and put marks every 100 units. Or if the data range is from 2.04 to 2.16, we will probably build a range from 2.00 to 2.20 in tick steps of 0.05. People can choose such "good" numbers, but there are no simplified algorithms. The naive choice of labels the algorithm takes a range of data and divides it into n equal intervals, but usually this leads to ugly labels. Here we describe a simple way to generate bright graph labels.
The primary observation is that the "most beautiful" numbers in decimal form are 1, 2, and 5, as well as all tenfold numbers of these numbers. We will use only such numbers for the tick interval and mark ticks in multiple tick intervals ...
I used the pseudo-code example in this book to create the following class in Java:
public class NiceScale { private double minPoint; private double maxPoint; private double maxTicks = 10; private double tickSpacing; private double range; private double niceMin; private double niceMax; public NiceScale(double min, double max) { this.minPoint = min; this.maxPoint = max; calculate(); } private void calculate() { this.range = niceNum(maxPoint - minPoint, false); this.tickSpacing = niceNum(range / (maxTicks - 1), true); this.niceMin = Math.floor(minPoint / tickSpacing) * tickSpacing; this.niceMax = Math.ceil(maxPoint / tickSpacing) * tickSpacing; } private double niceNum(double range, boolean round) { double exponent; double fraction; double niceFraction; exponent = Math.floor(Math.log10(range)); fraction = range / Math.pow(10, exponent); if (round) { if (fraction < 1.5) niceFraction = 1; else if (fraction < 3) niceFraction = 2; else if (fraction < 7) niceFraction = 5; else niceFraction = 10; } else { if (fraction <= 1) niceFraction = 1; else if (fraction <= 2) niceFraction = 2; else if (fraction <= 5) niceFraction = 5; else niceFraction = 10; } return niceFraction * Math.pow(10, exponent); } public void setMinMaxPoints(double minPoint, double maxPoint) { this.minPoint = minPoint; this.maxPoint = maxPoint; calculate(); } public void setMaxTicks(double maxTicks) { this.maxTicks = maxTicks; calculate(); } }
Then we can use the above code as follows:
NiceScale numScale = new NiceScale(-0.085, 0.173); System.out.println("Tick Spacing:\t" + numScale.getTickSpacing()); System.out.println("Nice Minimum:\t" + numScale.getNiceMin()); System.out.println("Nice Maximum:\t" + numScale.getNiceMax());
which will then output beautifully formatted numbers for use in any application for which you need to create pretty scales. = D
Tick Spacing: 0.05 Nice Minimum: -0.1 Nice Maximum: 0.2