Algorithm for “nice” grid line intervals on a graph

前端 未结 14 1232
长发绾君心
长发绾君心 2020-11-28 01:45

I need a reasonably smart algorithm to come up with \"nice\" grid lines for a graph (chart).

For example, assume a bar chart with values of 10, 30, 72 and 60. You k

14条回答
  •  無奈伤痛
    2020-11-28 02:05

    I wrote an objective-c method to return a nice axis scale and nice ticks for given min- and max values of your data set:

    - (NSArray*)niceAxis:(double)minValue :(double)maxValue
    {
        double min_ = 0, max_ = 0, min = minValue, max = maxValue, power = 0, factor = 0, tickWidth, minAxisValue = 0, maxAxisValue = 0;
        NSArray *factorArray = [NSArray arrayWithObjects:@"0.0f",@"1.2f",@"2.5f",@"5.0f",@"10.0f",nil];
        NSArray *scalarArray = [NSArray arrayWithObjects:@"0.2f",@"0.2f",@"0.5f",@"1.0f",@"2.0f",nil];
    
        // calculate x-axis nice scale and ticks
        // 1. min_
        if (min == 0) {
            min_ = 0;
        }
        else if (min > 0) {
            min_ = MAX(0, min-(max-min)/100);
        }
        else {
            min_ = min-(max-min)/100;
        }
    
        // 2. max_
        if (max == 0) {
            if (min == 0) {
                max_ = 1;
            }
            else {
                max_ = 0;
            }
        }
        else if (max < 0) {
            max_ = MIN(0, max+(max-min)/100);
        }
        else {
            max_ = max+(max-min)/100;
        }
    
        // 3. power
        power = log(max_ - min_) / log(10);
    
        // 4. factor
        factor = pow(10, power - floor(power));
    
        // 5. nice ticks
        for (NSInteger i = 0; factor > [[factorArray objectAtIndex:i]doubleValue] ; i++) {
            tickWidth = [[scalarArray objectAtIndex:i]doubleValue] * pow(10, floor(power));
        }
    
        // 6. min-axisValues
        minAxisValue = tickWidth * floor(min_/tickWidth);
    
        // 7. min-axisValues
        maxAxisValue = tickWidth * floor((max_/tickWidth)+1);
    
        // 8. create NSArray to return
        NSArray *niceAxisValues = [NSArray arrayWithObjects:[NSNumber numberWithDouble:minAxisValue], [NSNumber numberWithDouble:maxAxisValue],[NSNumber numberWithDouble:tickWidth], nil];
    
        return niceAxisValues;
    }
    

    You can call the method like this:

    NSArray *niceYAxisValues = [self niceAxis:-maxy :maxy];
    

    and get you axis setup:

    double minYAxisValue = [[niceYAxisValues objectAtIndex:0]doubleValue];
    double maxYAxisValue = [[niceYAxisValues objectAtIndex:1]doubleValue];
    double ticksYAxis = [[niceYAxisValues objectAtIndex:2]doubleValue];
    

    Just in case you want to limit the number of axis ticks do this:

    NSInteger maxNumberOfTicks = 9;
    NSInteger numberOfTicks = valueXRange / ticksXAxis;
    NSInteger newNumberOfTicks = floor(numberOfTicks / (1 + floor(numberOfTicks/(maxNumberOfTicks+0.5))));
    double newTicksXAxis = ticksXAxis * (1 + floor(numberOfTicks/(maxNumberOfTicks+0.5)));
    

    The first part of the code is based on the calculation I found here to calculate nice graph axis scale and ticks similar to excel graphs. It works excellent for all kind of data sets. Here is an example of an iPhone implementation:

    enter image description here

提交回复
热议问题