Linear X Logarithmic scale

For row X pixels are long as:

 0-------|---V---|-------|-------|-------max 

If 0 <= V <= max , on a linear scale the position of V will be X/max*V pixels.

How can I calculate the pixel position for a logarithmic scale and starting from the pixel position, how can I return the value of V?

  • This is not homework.
  • I want to know the math (no comments "use FOO-plotlib", please)
  • I like python

The logarithmic scale has the effect of "scaling" the left side of the scale. Is it possible to do the same for the right side?

[UPDATE]

Thanks for the math lessons!

I ended up not using logarithms. I just used the average value (in the set of values) as the center of the scale. This control is used to select group percentiles for the set of values ​​that will be used to draw the chopopleth chart .

If the user selects a symmetric scale (red mark = middle, green mark = center, darkness represents the number of occurrences of the value): enter image description here

Asymmetric scale facilitates fine-grained settings: enter image description here

+7
source share
3 answers

So, you have an arbitrary value of V , and you know that 0 <= V <= Vmax . You want to calculate the x-coordinate of a pixel, name it X , where your β€œscreen” has x-coordinates from 0 to Xmax . As you say, to do this in the β€œnormal” way, you would do

 X = Xmax * V / Vmax V = Vmax * X / Xmax 

I like to think about it, as if I first normalize the value to lie between 0 and 1, calculating V / Vmax , and then I multiply that value by a maximum to get a value from 0 to this maximum.

To do the same logarithmically, you will need a different lower limit for the value of V If V is always <= 0, you get a ValueError . So, let's say 0 < Vmin <= V <= Vmax . Then you need to figure out which logarithm to use, since there are infinitely many of them. Usually there are three, those with a base of 2, e and 10, which leads to the X axis, which looks like this:

 ------|------|------|------|---- ------|------|------|------|---- 2^-1 2^0 2^1 2^2 == 0.5 1 2 4 ------|------|------|------|---- ------|------|------|------|---- e^-1 e^0 e^1 e^2 == 0.4 1 2.7 7.4 ------|------|------|------|---- ------|------|------|------|---- 10^-1 10^0 10^1 10^2 == 0.1 1 10 100 

So, in principle, if we can get exponents from expressions to the left, we can use the same principle as above to get a value from 0 to Xmax , and this, of course, is where the journal goes. Assuming you are using base b , you can use these expressions to convert back and forth:

 from math import log logmax = log(Vmax / Vmin, b) X = Xmax * log(V / Vmin, b) / logmax V = Vmin * b ** (logmax * X / Xmax) 

This is almost the same way of thinking, except that you need to first make sure that log(somevalue, b) will provide you with a non-negative value. You do this by dividing by Vmin inside the log function. Now you can divide by the maximum value that the expression can give, which, of course, is log(Vmax / Vmin, b) , and you will get a value from 0 to 1, as before.

In another way, we first need to normalize ( X / Xmax ), and then scale again ( * logmax ) to the maximum value expected using the inverse functional. By the way, the opposite is to raise b to a certain value. Now, if X is 0, b ** (logmax * X / Xmax) will be 1, so to get the correct lower limit, multiply by Vmin . Or, to put it another way, since the first thing we did in a different way was to divide by Vmin , we need to multiply by Vmin as the last thing we are doing now.

To "increase" the "right side" of the equation, all you have to do is switch the equations, so you increase the speed from V to X and move on to the logarithm going the other way. In principle, this is so. Because you also need to do something with the fact that X may be 0:

 logmax = log(Xmax + 1, b) X = b ** (logmax * (V - Vmin) / (Vmax - Vmin)) - 1 V = (Vmax - Vmin) * log(X + 1, b) / logmax + Vmin 
+13
source
  Linear Logarithmic Forward pos = V * X/max pos = log(V) * X/log(max) Reverse V = pos * max/XV = B^( pos * log(max)/X ) 

(B - logarithmic base)

Obviously, you must make sure that V> = 1 (V = 1 will correspond to pos = 0, V = 0..1 corresponds to -inf..0, and for V <0 the logarithm is not defined).

+2
source

It can be easily expanded for other functions. My measure of space is given in characters instead of pixels (that's why max == chars (or pixels)).
Only for positive values.

 import math def scale(myval, mode='lin'): steps = 7 chars = max = 10 * steps if mode=='log': val = 10 * math.log10(myval) else: val = myval coord = [] count = 0 not_yet = True for i in range(steps): for j in range(10): count += 1 if val <= count and not_yet: coord.append('V') not_yet = False pos = count elif j==9: coord.append('|') else: coord.append('*') graph = ''.join(coord) text = 'graph %s\n\n%s\nvalue = %5.1f rel.pos. = %5.2f\n' print text % (mode, graph, myval, chars * pos/max) scale(50, 'lin') scale(50, 'log') 

enter image description here

We hope that the above is not considered a FOO-plotlib. But hell! This is true!: -)

+2
source

All Articles