I need to calculate the Ticklabels and the Tickrange for charts manually.
I know the \"standard\" algorithm for nice ticks (see http://books.google.de/books?id=fvA7
Here's the C++ version. As a bonus you get a function that returns the minimum number of decimal points to display the tick labels on the axis.
The header file:
class NiceScale
{ public:
float minPoint;
float maxPoint;
float maxTicks;
float tickSpacing;
float range;
float niceMin;
float niceMax;
public:
NiceScale()
{ maxTicks = 10;
}
/**
* Instantiates a new instance of the NiceScale class.
*
* @param min the minimum data point on the axis
* @param max the maximum data point on the axis
*/
NiceScale(float min, float max)
{ minPoint = min;
maxPoint = max;
calculate();
}
/**
* Calculate and update values for tick spacing and nice
* minimum and maximum data points on the axis.
*/
void calculate() ;
/**
* Returns a "nice" number approximately equal to range Rounds
* the number if round = true Takes the ceiling if round = false.
*
* @param range the data range
* @param round whether to round the result
* @return a "nice" number to be used for the data range
*/
float niceNum(float range, boolean round) ;
/**
* Sets the minimum and maximum data points for the axis.
*
* @param minPoint the minimum data point on the axis
* @param maxPoint the maximum data point on the axis
*/
void setMinMaxPoints(float minPoint, float maxPoint) ;
/**
* Sets maximum number of tick marks we're comfortable with
*
* @param maxTicks the maximum number of tick marks for the axis
*/
void setMaxTicks(float maxTicks) ;
int decimals(void);
};
And the CPP file:
/**
* Calculate and update values for tick spacing and nice
* minimum and maximum data points on the axis.
*/
void NiceScale::calculate()
{
range = niceNum(maxPoint - minPoint, false);
tickSpacing = niceNum(range / (maxTicks - 1), true);
niceMin = floor(minPoint / tickSpacing) * tickSpacing;
niceMax = ceil(maxPoint / tickSpacing) * tickSpacing;
}
/**
* Returns a "nice" number approximately equal to range
Rounds the number if round = true Takes the ceiling if round = false.
*
* @param range the data range
* @param round whether to round the result
* @return a "nice" number to be used for the data range
*/
float NiceScale::niceNum(float range, boolean round)
{ float exponent; /** exponent of range */
float fraction; /** fractional part of range */
float niceFraction; /** nice, rounded fraction */
exponent = floor(log10(range));
fraction = range / pow(10.f, 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 * pow(10, exponent);
}
/**
* Sets the minimum and maximum data points for the axis.
*
* @param minPoint the minimum data point on the axis
* @param maxPoint the maximum data point on the axis
*/
void NiceScale::setMinMaxPoints(float minPoint, float maxPoint)
{
this->minPoint = minPoint;
this->maxPoint = maxPoint;
calculate();
}
/**
* Sets maximum number of tick marks we're comfortable with
*
* @param maxTicks the maximum number of tick marks for the axis
*/
void NiceScale::setMaxTicks(float maxTicks)
{
this->maxTicks = maxTicks;
calculate();
}
// minimum number of decimals in tick labels
// use in sprintf statement:
// sprintf(buf, "%.*f", decimals(), tickValue);
int NiceScale::decimals(void)
{
float logTickX = log10(tickSpacing);
if(logTickX >= 0)
return 0;
return (int)(abs(floor(logTickX)));
}