1
votes

I need to calculate the step for y-axis of the chart so that it will always have 7 ticks (generally specific number of ticks). The range of the data is not specified so the values for the y-axis may be like:

-2, 2, 3

-105, 0.5, 10

-5, 10, 80.6, 120 etc

Is there any algorithm (especially it's C# implementation) that will calculate the step that the chart would always have the same number of ticks?

F.e. for numbers:

-2, 2, 3 it will be -4.5, -3, -1.5, 0, 1.5, 3, 4.5

-105, 0.5, 10 it will be -125, -100, -75, -50, -25 ,0, 25

many thanks in advance for your help :)

1
What are the constraints on the values of the ticks? otherwise, (maxvalue-minvalue)/7 always returns the solution...Save
I have forgotten to write. There must be always one tick for value 0. It can be either on the bottom (if all values are positive), on the top (if all values are negative) or in the middle of the axis.grechut
Also the values for the ticks must be "reasonable". So f.e. if the maxValue == 90 and minValue == 10 the max tick should be 120 and step == 20. Step value should not be like 5.232324324 etcgrechut
if min = -1, max=5, do you want -1,0,1,2,3,4,5, or should it always be symmetric, so something like -6,-4,-2,-,2,4,6?Bas Swinckels
Other question: please specify your acceptable ticks spacing precisely, maybe something like 1,1.5,2,5,10? I guess you can always take your maximum value, divide by some power of 10, chose the appropriate value from the acceptable ticks and then multiply by the previously found power of 10 again.Bas Swinckels

1 Answers

0
votes

The implementation shown below is in python. Most elements of it will translate easily and directly to C# if you are skilled in both languages. A few statements may require a series of if statements or a different approach.

In the program, the last four lines are the main program. As shown, main has a loop to generate 80 test cases, with sizes increasing geometrically from 0.04 up to about 200. If you want to test more coarsely, change 40 (number of sizes) to a smaller number and 1.24 (geometric ratio) to a bigger number. For each size tested, main calls stepShow two times, first with a test range from 10% of size up to 110% of size, then with a test range from -28% to 82%. stepShow is a test routine that calls stepCalc, which is the routine that embodies an algorithm to calculate leftTick and tickSize, which are the location of the leftmost tick and the interval between ticks.

stepCalc begins with span = max(hiVal,0) - min(loVal,0) which ensures that x=0 will fit into the span of ticks. Then decade = 10**(math.log(span/6.0)//math.log(10)) computes the greatest power of 10 not greater than 1/6 of the span. (Python's // operator returns an integer result and ** represents exponentiation.) multis = (1,1.5,2,3,5,10) if decade==1 else (1,2,5,10) sets the tuple multis to (1,1.5,2,3,5,10) if tick size is likely to be between 1 and 10, but otherwise sets it to (1,2,5,10). Code in the loop for m in multis: computes tickSize and leftTick values; when they are big enough, it breaks out of the loop and returns them.

In the output of this program, the two test cases for each size will ordinarily have the same tickSize, but of course leftTick is zero for the first case and negative for the second. Here are a few example lines. (Full output is shown after the program.) Each 5-number group includes values of leftTick, loVal, hiVal, rightTick, tickSize.

0.000   0.101   1.109   1.200   0.200    -0.500  -0.282   0.826   2.500   0.500 
0.000   0.238   2.621   3.000   0.500    -1.000  -0.667   1.954   2.000   0.500 
0.000   0.295   3.250   6.000   1.000    -1.000  -0.827   2.423   5.000   1.000 
0.000   0.563   6.197   9.000   1.500    -3.000  -1.577   4.619   6.000   1.500 
0.000   0.866   9.528  12.000   2.000    -4.000  -2.425   7.103   8.000   2.000 
0.000   1.074  11.815  12.000   2.000    -6.000  -3.007   8.807  12.000   3.000 

For some sizes, tickSize differs between the two cases, as in the first and last of the example lines above. Although the overall span is the same in both test cases, 110% of size, a larger tickSize value is needed when the 0 tick is not at the end of the range if loVal or hiVal no longer both fit into the span covered by the smaller tickSize value. Including 10 in the multis tuple handles this case.

def stepCalc(loVal, hiVal):
    import math
    span = max(hiVal,0) - min(loVal,0)  # have to have 0 in span
    decade = 10**(math.log(span/6.0)//math.log(10))
    multis = (1,1.5,2,3,5,10) if decade==1 else (1,2,5,10)
    for m in multis:
        tickSize = m * decade
        cover = 6.0 * tickSize;
        leftTick = 0 if loVal >= 0 else -cover if hiVal <= 0 else (loVal//tickSize)*tickSize
        if leftTick+cover >= hiVal: break
    return (leftTick, tickSize)

def stepShow(loVal, hiVal):
    (leftTick, tickSize) = stepCalc(loVal, hiVal)
    return ' {:7.3f} {:7.3f} {:7.3f} {:7.3f} {:7.3f} '.format(leftTick, loVal, hiVal, leftTick+6*tickSize, tickSize)

size = 0.04
for i in range(40):
    print stepShow(0.1*size, 1.1*size), stepShow(-0.28*size, 0.82*size)
    size *= 1.24

The code shown above does not try to symmetrize the location of the ticks. If you want to do that, you could add code before return (leftTick, tickSize) to decrease leftTick by multiples of tickSize while there are more multiples of tickSize above hiVal than below loVal.

Program Output:

0.000   0.004   0.044   0.060   0.010    -0.020  -0.011   0.033   0.040   0.010 
0.000   0.005   0.055   0.060   0.010    -0.020  -0.014   0.041   0.040   0.010 
0.000   0.006   0.068   0.120   0.020    -0.020  -0.017   0.050   0.100   0.020 
0.000   0.008   0.084   0.120   0.020    -0.040  -0.021   0.063   0.080   0.020 
0.000   0.009   0.104   0.120   0.020    -0.040  -0.026   0.078   0.080   0.020 
0.000   0.012   0.129   0.300   0.050    -0.050  -0.033   0.096   0.250   0.050 
0.000   0.015   0.160   0.300   0.050    -0.050  -0.041   0.119   0.250   0.050 
0.000   0.018   0.198   0.300   0.050    -0.100  -0.050   0.148   0.200   0.050 
0.000   0.022   0.246   0.300   0.050    -0.100  -0.063   0.183   0.200   0.050 
0.000   0.028   0.305   0.600   0.100    -0.100  -0.078   0.227   0.500   0.100 
0.000   0.034   0.378   0.600   0.100    -0.100  -0.096   0.282   0.500   0.100 
0.000   0.043   0.469   0.600   0.100    -0.200  -0.119   0.350   0.400   0.100 
0.000   0.053   0.581   0.600   0.100    -0.200  -0.148   0.433   0.400   0.100 
0.000   0.066   0.721   1.200   0.200    -0.200  -0.184   0.537   1.000   0.200 
0.000   0.081   0.894   1.200   0.200    -0.400  -0.228   0.666   0.800   0.200 
0.000   0.101   1.109   1.200   0.200    -0.500  -0.282   0.826   2.500   0.500 
0.000   0.125   1.375   3.000   0.500    -0.500  -0.350   1.025   2.500   0.500 
0.000   0.155   1.705   3.000   0.500    -0.500  -0.434   1.271   2.500   0.500 
0.000   0.192   2.114   3.000   0.500    -1.000  -0.538   1.576   2.000   0.500 
0.000   0.238   2.621   3.000   0.500    -1.000  -0.667   1.954   2.000   0.500 
0.000   0.295   3.250   6.000   1.000    -1.000  -0.827   2.423   5.000   1.000 
0.000   0.366   4.030   6.000   1.000    -2.000  -1.026   3.004   4.000   1.000 
0.000   0.454   4.997   6.000   1.000    -2.000  -1.272   3.725   4.000   1.000 
0.000   0.563   6.197   9.000   1.500    -3.000  -1.577   4.619   6.000   1.500 
0.000   0.699   7.684   9.000   1.500    -3.000  -1.956   5.728   6.000   1.500 
0.000   0.866   9.528  12.000   2.000    -4.000  -2.425   7.103   8.000   2.000 
0.000   1.074  11.815  12.000   2.000    -6.000  -3.007   8.807  12.000   3.000 
0.000   1.332  14.650  18.000   3.000    -6.000  -3.729  10.921  12.000   3.000 
0.000   1.651  18.166  30.000   5.000    -5.000  -4.624  13.542  25.000   5.000 
0.000   2.048  22.526  30.000   5.000   -10.000  -5.734  16.792  20.000   5.000 
0.000   2.539  27.932  30.000   5.000   -10.000  -7.110  20.822  50.000  10.000 
0.000   3.149  34.636  60.000  10.000   -10.000  -8.816  25.819  50.000  10.000 
0.000   3.904  42.948  60.000  10.000   -20.000 -10.932  32.016  40.000  10.000 
0.000   4.841  53.256  60.000  10.000   -20.000 -13.556  39.700  40.000  10.000 
0.000   6.003  66.037 120.000  20.000   -20.000 -16.810  49.228 100.000  20.000 
0.000   7.444  81.886 120.000  20.000   -40.000 -20.844  61.043  80.000  20.000 
0.000   9.231 101.539 120.000  20.000   -40.000 -25.846  75.693  80.000  20.000 
0.000  11.446 125.908 300.000  50.000   -50.000 -32.049  93.859 250.000  50.000 
0.000  14.193 156.127 300.000  50.000   -50.000 -39.741 116.385 250.000  50.000 
0.000  17.600 193.597 300.000  50.000   -50.000 -49.279 144.318 250.000  50.000