【问题标题】:How to produce an exponentially scaled axis?如何产生一个指数比例的轴?
【发布时间】:2011-02-04 15:09:14
【问题描述】:

考虑以下代码:

from numpy import log2
import matplotlib.pyplot as plt

xdata = [log2(x)*(10/log2(10)) for x in range(1,11)]
ydata = range(10)
plt.plot(xdata, ydata)
plt.show()

这将产生以下图: 我的问题是,我该如何修改它,以便具有与输入完全相同的数据的图显示为一条直线?这基本上需要适当地缩放 x 轴,但我不知道如何做到这一点。这样做的原因是我显示的函数在开始时变化很小,但在有效间隔结束时开始波动更大,所以我希望在结束时有更高的水平分辨率。如果有人可以提出我的方法的替代解决方案,请随时这样做!

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    这里是how,它完成了。一个很好的example 可以关注。您只需继承 ScaleBase 类。

    这是你的变换。当您削减所有自定义格式化程序和东西时,它并不太复杂。只是有点冗长。

    from numpy import log2
    import matplotlib.pyplot as plt
    
    from matplotlib import scale as mscale
    from matplotlib import transforms as mtransforms
    
    class CustomScale(mscale.ScaleBase):
        name = 'custom'
    
        def __init__(self, axis, **kwargs):
            mscale.ScaleBase.__init__(self)
            self.thresh = None #thresh
    
        def get_transform(self):
            return self.CustomTransform(self.thresh)
    
        def set_default_locators_and_formatters(self, axis):
            pass
    
        class CustomTransform(mtransforms.Transform):
            input_dims = 1
            output_dims = 1
            is_separable = True
    
            def __init__(self, thresh):
                mtransforms.Transform.__init__(self)
                self.thresh = thresh
    
            def transform_non_affine(self, a):
                return 10**(a/10)
    
            def inverted(self):
                return CustomScale.InvertedCustomTransform(self.thresh)
    
        class InvertedCustomTransform(mtransforms.Transform):
            input_dims = 1
            output_dims = 1
            is_separable = True
    
            def __init__(self, thresh):
                mtransforms.Transform.__init__(self)
                self.thresh = thresh
    
            def transform_non_affine(self, a):
                return log2(a)*(10/log2(10))
    
            def inverted(self):
                return CustomScale.CustomTransform(self.thresh)
    
    
    mscale.register_scale(CustomScale)
    
    xdata = [log2(x)*(10/log2(10)) for x in range(1,11)]
    ydata = range(10)
    plt.plot(xdata, ydata)
    
    plt.gca().set_xscale('custom')
    plt.show()
    

    【讨论】:

    • 实际上,您应该能够在不定义新比例和变换的情况下进行猴子修补... ax.xaxis._scale._transform = ax.xaxis._scale._transform.inverted() 这由于某种原因不起作用...(或者,更确切地说,在您绘制数据之前它一直有效...)显然,您的示例有效,尽管相当冗长!
    • 谢谢!我自己发现了这个例子,但我有点希望有更简单的方法。
    【解决方案2】:

    最简单的方法是使用semilogy

    from numpy import log2
    import matplotlib.pyplot as plt
    
    xdata = log2(range(1,11)) * (10/log2(10))
    ydata = range(10)
    plt.semilogy(xdata, ydata)
    plt.show()
    

    【讨论】:

    • 这有一个问题是它不显示小于 1 的 y 值。此外,它违背了为高 x 值提供更高水平分辨率的目的。
    • 它肯定会显示低于 1 的值! (即 0.001 --> 10^-3)不过,它不会显示等于或低于 0 的值。我对“高x值的更高水平分辨率”的意思有点困惑......你的意思是你的实际情节的分辨率(即线段的数量)还是你的xticks在哪里......或者,你可能只是有一个断轴......
    • 啊!我刚刚意识到你想要做什么......你实际上想要一个 semilog-xaxis 的反向,对吧? IE。您希望 x 轴呈指数增长,而不是对数增长? (当然,这基本上就是你在最初的问题中所说的,只是花了一段时间才通过我厚厚的头骨......)
    • 你现在就知道了!我看了看,似乎可以通过创建自定义转换来实现,但这似乎相当复杂,我将不得不研究它。不过还是希望有一个更简单的解决方案。
    • 最简单的方法是更改​​您的数据并在轴上放置自定义标签,但这会使交互式绘图在鼠标选择和其他方面出现错误。我认为正确的唯一方法是使用自定义转换。 (我为你做的——见我的编辑。)
    猜你喜欢
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多