开发者

How to determine Y Axis values on a chart

I'm working on a charting algorithm that will give me a set n array of y axis values I would use on my graph.

The main problem is that I also want to calculate the number of number of steps to use and also use nice numbers for them. It must be able to take integers and doubles and be able to handle small ranges (under 1) and large ranges (over 10000 etc).

For example, if I was given a range of 0.1 - 0.9, ideally i would have values of 0, 0.2, 0.4, 0.6, 0.8, 1 but if I were given 0.3 to 0.7 I might use 0.3, 0.4, 0.5, 0.6, 0.7

This is what I have so far, it works well with small ranges, but terribly in large ranges, and doesn't give me nice numbers

-(double*)yAxisValues:(double)min (开发者_运维知识库double):max {

    double diff = max - min;
    double divisor = 1.0;

    if (diff > 1) {
        while (diff > 1) {
            diff /= 10;
            divisor *= 10;
        }
    } else {
        while (diff < 1) {
            diff *= 10;
            divisor *= 10;
        }
    }

    double newMin = round(min * divisor) / divisor;
    double newMax = round(max * divisor) / divisor;

    if (newMin > min) {
        newMin -= 1.0/divisor;
    }
    if (newMax < max) {
        newMax += 1.0/divisor;
    }

    int test2 = round((newMax - newMin) * divisor); 
    if (test2 >= 7) {
        while (test2 % 6 != 0 && test2 % 5 != 0 && test2 % 4 != 0 && test2 % 3 != 0) {
            test2++;
            newMax += 1.0/divisor;
        }
    }

    if (test2 % 6 == 0) {
        test2 = 6;
    } else if (test2 % 5 == 0) {
        test2 = 5;
    } else if (test2 % 4 == 0 || test2 == 2) {
        test2 = 4;
    } else if (test2 % 3 == 0) {
        test2 = 3;
    }

    double *values = malloc(sizeof(double) * (test2 + 1));
    for (int i = 0; i < test2 + 1; i++) {
        values[i] = newMin + (newMax - newMin) * i / test2;
    }
    return values;
}

Any suggestions?


Here's a snippet of code that does something similar, though has a slightly different approach. The "units" refer to what your are plotting on the graph. So if your scale is so that one unit on your graph should be 20 pixels on screen, this function would return how many units each step should be. With that information you can then easily calculate what the axis values are and where to draw them.

- (float)unitsPerMajorGridLine:(float)pixelsPerUnit {
    float amountAtMinimum, orderOfMagnitude, fraction;

    amountAtMinimum = [[self minimumPixelsPerMajorGridLine] floatValue]/pixelsPerUnit;  
    orderOfMagnitude = floor(log10(amountAtMinimum));
    fraction = amountAtMinimum / pow(10.0, orderOfMagnitude);

    if (fraction <= 2) {
        return 2 * pow(10.0, orderOfMagnitude);
    } else if (fraction <= 5) {
        return 5 * pow(10.0, orderOfMagnitude);
    } else {
        return 10 * pow(10.0, orderOfMagnitude);
    }
}


Simple adaptation for JavaScript (thanks a lot to Johan Kool for source)

const step = (() => {let pixelPerUnit = height / (end - size)
, amountAtMinimum = minimumPixelsPerMajorGridLine / pixelPerUnit
, orderOfMagnitude = Math.floor(Math.log10(amountAtMinimum))
, fraction = amountAtMinimum / Math.pow(10.0, orderOfMagnitude);

let result;
if (fraction <= 2) {
    result = 2 * Math.pow(10.0, orderOfMagnitude);
} else if (fraction <= 5) {
    result = 5 * Math.pow(10.0, orderOfMagnitude);
} else {
    result = 10 * Math.pow(10.0, orderOfMagnitude);
}})();

let arr = [];
arr.push(start);
let curVal = start - start % step + step
, pxRatio = height / (end - start);

while (curVal < end) {
    arr.push(curVal);
    curVal += step;
}
arr.push(end);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜