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.
-
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.
-
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.
coulix : Thanks ! the factor = 10**math.ceil(math.log(delta,10)) did the tric ! -
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 :-)
-
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()
-
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 ????
mweerden : 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)