views:

155

answers:

5

Hello everyone,

I am trying to figure out the following problem. I am building Yet another math function grapher, The function is drawn on its predefined x,y range, that's all good.

Now I am working on the background and the ticking of X, Y axes (if any axes are shown).

I worked out the following. I have a fixed width of 250 p The tick gap should be between 12.5 and 50p.

The ticks should indicate either unit or half unit range, by that i mean the following.

x range (-5, 5): one tick = 1

x range (-1, 1): one tick = 0.5 or 0.1 depending on the gap that each of this option would generate.

x range (0.1, 0.3): 0.05

Given a Xrange How would you get the number of ticks between either full or half unit range ?

Or maybe there are other way to approach this type of problems.

A: 

Using deltaX

if deltax between 2 and 10 half increment if deltax between 10 and 20 unit increment if smaller than 2 we multiply by 10 and test again if larger than 20 we divide Then we get the position of the first unit or half increment on the width using xmin.

I still need to test this solution.

coulix
+4  A: 

One way to do this would be to "normalise" the difference between the minimum and maximum and do a case distinction on that value. In python:

delta = maximum - minimum
factor = 10**math.ceil(math.log(delta,10))  # smallest power of 10 greater than delta
normalised_delta = delta / factor           # 0.1 <= normalised_delta < 1
if normalised_delta/5 >= 0.1:
  step_size = 0.1
elif normalised_delta/5 >= 0.05:
  step_size = 0.05
elif normalised_delta/20 <= 0.01:
  step_size = 0.01
step_size = step_size * factor

The above code assumes you want the biggest possible gap. For the smallest you would use the following if:

if normalised_delta/20 == 0.005:
  step_size = 0.005
elif normalised_delta/20 <= 0.01:
  step_size = 0.01
elif normalised_delta/5 >= 0.05:
  step_size = 0.05

Besides the possibility that there are more than one suitable values, there is also the somewhat worrisome possibility that there are none. Take for example the range [0,24] where a gap of 12.5p would give a step size of 1.2 and a gap of 50p would give step size 4.8. There is no "unit" or "half unit" in between. The problem is that the difference between a gap of 12.5p and one of 50p is a factor 4 while the difference between 0.01 and 0.05 is a factor 5. So you will have to widen the range of allowable gaps a bit and adjust the code accordingly.

Clarification of some of the magic numbers: divisions by 20 and 5 correspond to the number of segments with the minimal and maximal gap size, respectively (ie. 250/12.5 and 250/50). As the normalised delta is in the range [0.1,1), you get that dividing it by 20 and 5 gives you [0.005,0.05) and [0.02,0.2), respectively. These ranges result in the possible (normalised) step sizes of 0.005 and 0.01 for the first range and 0.05 and 0.1 for the second.

mweerden
Thanks ! the factor = 10**math.ceil(math.log(delta,10)) did the tric !
coulix
A: 

You might want to take a look at Jgraph, which solves a complementary problem: it is a data grapher rather than a function grapher. But there are a lot of things in common such as dealing with major and minor tick marks, axis labels, and so on and so forth. I find the input language a little verbose for my taste, but Jgraph produces really nice technical graphs. There are a lot of examples on the web site and probably some good ideas you could steal.

And you know what they say: talent imitates, but genius steals :-)

Norman Ramsey
A: 

This seems to do what i was expecting.

import math

def main(): getTickGap(-1,1.5)

def next_multiple(x, y): return math.ceil(x/y)*y

def getTickGap(xmin, xmax): xdelta = xmax -xmin width = 250 # smallest power of 10 greater than delta factor = 10**math.ceil(math.log(xdelta,10)) # 0.1 <= normalised_delta < 1 normalised_delta = xdelta / factor print("normalised_delta", normalised_delta)

# we want largest gap
if normalised_delta/4 >= 0.1:
  step_size = 0.1
elif normalised_delta/4 >= 0.05:
  step_size = 0.05
elif normalised_delta/20 <= 0.01:
  step_size = 0.01
step_size = step_size * factor


##    if normalised_delta/20 == 0.005:
##      step_size = 0.005
##    elif normalised_delta/20 <= 0.01:
##      step_size = 0.01
##    elif normalised_delta/4 >= 0.05:
##      step_size = 0.05
##    step_size = step_size * factor
print("step_size", step_size)
totalsteps = xdelta/step_size
print("Total steps", totalsteps)
print("Range [", xmin, ",", xmax, "]")

firstInc = next_multiple(xmin, step_size)
count = (250/xdelta)*(firstInc - xmin)
print("firstInc ", firstInc, 'tick at ', count)
print("start at ", firstInc - xmin, (width/totalsteps)*(firstInc - xmin))
inc = firstInc

while (inc <xmax):
    inc += step_size
    count += (width/totalsteps)
    print(" inc", inc, "tick at ", count)

if name == "main": main()

coulix
A: 

On range -1, 0

i get

normalised_delta 1.0
step_size 0.1
Total steps 10.0
Range [ -1 , 0 ]
firstInc  -1.0 tick at  0.0
start at  0.0 0.0
 inc -0.9 tick at  25.0
 inc -0.8 tick at  50.0
 inc -0.7 tick at  75.0
 inc -0.6 tick at  100.0
 inc -0.5 tick at  125.0
 inc -0.4 tick at  150.0
 inc -0.3 tick at  175.0
 inc -0.2 tick at  200.0
 inc -0.1 tick at  225.0
 inc -1.38777878078e-16 tick at  250.0
 inc 0.1 tick at  275.0

How come the second line from bottom get this number ????

coulix
This is due to the inaccuracies of floating-point numbers and operations on computers. Specifically, 0.1 does not have a precise representation and with + you keep adding the error. If you use -1.0+9*0.1 the error is much smaller. (See http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems)
mweerden