如何使用matplotlib指数缩放Y轴

uoifb46i  于 2023-05-18  发布在  其他
关注(0)|答案(7)|浏览(175)

我试图创建一个matplotlib图与指数(?Y轴就像我在下面模拟的假的一样。对于我的数据,我想在它们接近最大Y值时将值展开。当Y接近零时,我想压缩这些值。
所有正常的'log'示例都是相反的:它们会在数值远离零时压缩数值。当然,这就是“日志”所做的。如何创建指数(?)缩放代替?

mefy6pfw

mefy6pfw1#

从matplotlib 3.1开始,您可以通过以下方式轻松地定义任何自定义比例

ax.set_yscale('function', functions=(forward, inverse))

参见https://matplotlib.org/3.1.1/gallery/scales/scales.html
在这种情况下,例如:

from functools import partial

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(1, 40, 100)
y = np.linspace(1, 4, 100)

fig, ax = plt.subplots()
ax.plot(x, y)

# Set y scale to exponential
ax.set_yscale('function', functions=(partial(np.power, 10.0), np.log10))
ax.set(xlim=(1,40), ylim=(1,4))
ax.set_yticks([1, 3, 3.5, 3.75, 4.0])

plt.show()

5gfr0r5j

5gfr0r5j2#

我不认为它直接可能。当然,你总是可以尝试作弊。在我的例子中,我只是在标签中写了一些其他的东西:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(1, 40, 100);
y = np.linspace(1, 4, 100);

# Actually plot the exponential values
plt.plot(x, np.e**y)
ax = plt.gca()

# Set x logaritmic
ax.set_xscale('log')

# Rewrite the y labels
y_labels = np.linspace(min(y), max(y), 4)
ax.set_yticks(np.e**y_labels)
ax.set_yticklabels(y_labels)

plt.show()

其结果为:

n8ghc7c1

n8ghc7c13#

这不是完全通用的,因为定位器是硬编码为我的情况。但这对我很有效。我必须创建一个新的标度,称为ExponentialScale,使用基数为1.1的ma.power。对于看似简单的事情来说太复杂了:

class ExponentialScale(mscale.ScaleBase):
    name = 'expo'
    base = 1.1
    logbase = math.log(base)

def __init__(self, axis, **kwargs):
    mscale.ScaleBase.__init__(self)
    self.thresh = None #thresh

def get_transform(self):
    return self.ExponentialTransform(self.thresh)

def set_default_locators_and_formatters(self, axis):
    # I could not get LogLocator to do what I wanted. I don't understand
    # the docs about "subs" and the source was not clear to me.
    # So I just spell out the lines I want:
    major = [1, 5, 10, 12, 14, 16, 18, 20, 25, 28, 30] + range(31,60)
    axis.set_major_locator(ticker.FixedLocator(major))

class ExponentialTransform(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):
        res = ma.power(ExponentialScale.base, a)
        return res

    def inverted(self):
        return ExponentialScale.InvertedExponentialTransform(self.thresh)

class InvertedExponentialTransform(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):
        denom = np.repeat(ExponentialScale.logbase, len(a))
        return np.log(a) / denom

    def inverted(self):
        return ExponentialScale.ExponentialTransform(self.thresh)
wwodge7n

wwodge7n4#

只需将此添加到日志缩放代码中即可:

plt.figure()
ax = plt.subplot(111)
ax.set_yscale('log')

但如果你确实想要一个指数尺度,这个问题可以回答:link to question

cnh2zyt3

cnh2zyt36#

指数缩放意味着什么?

在对数轴上,幂关系y=x**a将产生斜率a的直线。这是因为我们绘制了log(y) = log(x**a) = a log(x)
对于指数轴,关系y=log(a x)应产生斜率a的直线:exp(y) = exp[log(a x)] = a x

如何简单的处理

只需自己取指数并标记轴以指示此操作已完成。

plt.plot(np.exp(your_x_data), np.exp(your_y_data))
plt.xlabel('exp(x)')
plt.xlabel('exp(y)')
dwbf0jvd

dwbf0jvd7#

我假设你指的是X轴,因为在模拟图中,X轴是指数的,而不是Y轴。
你可以这样做:

...
ax = plt.subplot(111)
ax.plot(Xs,Ys,color='blue',linewidth=2)
....
xlabs = [pow(10,i) for i in range(0,6)]
ax.set_xticklabels(xlabs)
ax.set_xticks(xlabs)

我在这里做的是手动创建一个由6个X组成的列表,其中每个X由10^i表示,即10^1,10^2,...。这将在[1, 10, 100, 1000, 10000, 100000]处放置X个刻度线,并正确标记它们。如果需要更多标签,请更改6

相关问题