线性与对数刻度

8

给定一条长度为X像素的线,例如:

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

如果 0 <= V <= max,在线性刻度上,V 的位置将为 X/max*V 像素。

如何计算对数刻度的像素位置,并从像素位置获取回 V 的值?

  1. 这不是作业
  2. 我想知道这个数学问题(请勿评论“使用 FOO-plotlib”)
  3. 我喜欢 Python

对数刻度的效果是放大刻度左侧。是否可以对右侧进行相同的操作?

[更新]

感谢数学课!

最终我没有使用对数。我仅使用一组值的平均值作为刻度的中心。此控件用于选择一组值的组边界百分位数,这些值将用于绘制区域地图

如果用户选择对称刻度(红色标记=平均值,绿色标记=中心,颜色深浅表示值出现的次数): enter image description here

非对称的刻度使细粒度调整更加容易: enter image description here


取所有值的对数,其余不变。注意不能出现零(log(0)为负无穷大),也不能越过符号。 - yosukesabai
@yosukesabai:如何处理max非常小的值? - Paulo Scardine
2
这是 (X/max)*V,更易读为 X * V/max - wim
你如何定义右侧缩放? - hamstergene
@hamstergene:在图表中使右侧刻度上的值更加稀疏。 - Paulo Scardine
3个回答

14

假设你有一个任意值V,并且你知道0 <= V <= Vmax。你想计算像素的x坐标,称之为X,其中你的“屏幕”具有从0到Xmax的x坐标。如你所说,要以“正常”的方式做到这一点,你需要执行:

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

我喜欢把它想象成首先通过计算 V/Vmax 来将值标准化为介于0和1之间的值,然后将此值乘以最大值以获得介于0和该最大值之间的值。

要以对数方式进行相同的操作,需要使用不同的下限值来处理 V 值。如果 V 小于等于 0,则会出现 ValueError。 因此,假设 0 Vmin <= V <= Vmax。 然后你需要找到使用哪个对数,因为有无限多个对数可以使用。 其中三个常见的对数是以2、e和10为底数的,这将导致 x 轴看起来像这样:

------|------|------|------|----      ------|------|------|------|----
    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

原则上,如果我们可以从左侧的表达式中获取幂指数,我们就可以使用与上面相同的原理来获取介于0和Xmax之间的值,这当然涉及到对数。假设您使用基数b,您可以使用这些表达式进行转换:

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

思路几乎相同,唯一不同的是你需要先确保log(somevalue, b)能得到非负值。这可以通过在log函数内部除以Vmin来实现。现在您可以除以表达式可能产生的最大值,当然这个最大值是log(Vmax / Vmin, b),您将得到一个介于0和1之间的值,与之前一样。

另一种方法是首先归一化(X / Xmax),然后再缩放(* logmax)到逆函数所期望的最大值。顺便说一下,逆函数是将b升至某个值。现在,如果X为0,b ** (logmax * X / Xmax)将等于1,因此要获得正确的下限,我们需要乘以Vmin。换句话说,由于我们从另一个方向开始时做的第一件事是除以Vmin,因此现在我们需要在最后一步乘以Vmin

要“放大”方程式的“右侧”,您只需切换方程式,使其自VX进行指数运算,并在另一侧进行对数运算。原则上,是这样的。因为您还必须处理X可能为0的情况:

logmax = log(Xmax + 1, b)
X = b ** (logmax * (V - Vmin) / (Vmax - Vmin)) - 1
V = (Vmax - Vmin) * log(X + 1, b) / logmax + Vmin

2
           Linear               Logarithmic
Forward    pos = V * X/max      pos = log(V) * X/log(max)
Reverse    V = pos * max/X      V = B^( pos * log(max)/X )

(B是对数的底)

显然,您必须确保V>=1(当V=1时,pos=0;当V=0..1时,pos=-inf..0;当V<0时,对数未定义)。


2

这个可以很容易地扩展到其他功能。我的空间度量以字符而不是像素为单位(这就是为什么max == chars(或像素))。


仅适用于正值。

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')

希望上述内容不被视为FOO-plotlib。但是该死!这就是SO!:-)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接