Calculating the upper value for a chart axis
Peek inside for a generic method to calculate the upper boundary of a graph's axis.
The Problem
I’ve often required the upper value for a chart axis and usually had to calculate it to the nearest 100 or 1000.
The first problem with this method is that I have to know the order of magnitude of the chart’s points.
The second problem is that the axis is often divided into halves, quarters, fifths or tenths to give a visual guide, and these do not always render easy-to-use values. E.g. I have a maximum value of 874 on the chart, and I round it to the nearest 100 which gives me 900, but since my axis is divided into 4 parts, I get labels with the values 225, 450, 675 and 900. What I actually wanted, was the closest 250, thus 1000 as the upper value with the segments 250, 500, 750, 1000.
The third problem is that I have to redo the math every time.
The Solution
A generic method that takes the value of the biggest point on the chart as one parameter and the way you would like your axis segments displayed as a second parameter and returns the axis’ upper value.
/// <summary>
/// Calculates the ceiling for Val to the closest Div,
/// but in the same order of magnitude
/// </summary>
/// <param name="Val">Value to calculate the ceiling for</param>
/// <param name="Div">Integer that divides into 10^x without
/// remainder</param>
/// <returns>If Div=25, the first integer bigger than Val in the series
/// 25, 50, 75, 100, 250 ...</returns>
public static int CalcCeiling(int Val, int Div)
{
double val = Convert.ToDouble(Val);
double div = Convert.ToDouble(Div);
//Get orders of magnitude
int a = Convert.ToInt32(Math.Ceiling(Math.Log10(val)));
int b = Convert.ToInt32(Math.Ceiling(Math.Log10(div)));
//Calc Div with adjusted order of magnitude
var x = div * Math.Pow(10, (a - b));
//Return ceiling
return Convert.ToInt32(Math.Ceiling(val / x) * x);
}
The method takes 2 parameters, the first is the value of the maximum point on the chart and the second the size of the smallest segment divisible into 10x. E.g. CalcCeiling(874,25)
NOTE: 25 as the second parameter implies I only want a number from the series {25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, …}
Since log base 10 will return the power of 10 needed to get to value, we can use it to get the order of magnitude of the maximum point with the formula:
MaxPointOOM = Math.Ceiling(Math.Log10(MaxPoint))
We then check the order of magnitude of the smallest segment with:
SegmentOOM = Math.Ceiling(Math.Log10(Segment))
The smallest segment is then altered to be in the same order of magnitude as the maximum point with the formula:
NewSegment = Segment * Math.Pow(10,(MaxPointOOM-SegmentOOM))
This allows us to see how many segments are needed to cover the maximum point with:
SegmentsNeeded = Math.Ceiling(MaxPoint / NewSegment)
To get the upper value of the chart, we simply multiply with the segment (in the correct order of magnitude) to get the chart’s upper value:
UpperValue = SegmentsNeeded * NewSegment
Let me know if you find this useful!