如何在符号刻度上放置小刻度?

2024-10-01 17:26:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用matplotlib的symlog比例尺来覆盖大量参数,这些参数可以扩展到正方向和负方向。不幸的是,symlog尺度不是很直观,也可能不是很常用。因此,我希望通过在主刻度之间放置次要刻度,使所使用的缩放更加明显。在刻度的对数部分,我想把刻度放在[2,3,…,9]*10^e,其中e是附近的主要刻度。此外,0到0.1之间的范围应该覆盖均匀放置的小记号,它们之间的间隔为0.01。我尝试使用matplotlib.ticker API来使用以下代码得出这样的节拍:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import LogLocator, AutoLocator

x = np.linspace(-5, 5, 100)
y = x

plt.plot(x, y)
plt.yscale('symlog', linthreshy=1e-1)

yaxis = plt.gca().yaxis
yaxis.set_minor_locator(LogLocator(subs=np.arange(2, 10)))

plt.show()

不幸的是,这并不能产生我想要的:

enter image description here

请注意,在0附近有很多小刻度,这可能是由于LogLocator。此外,负轴上没有小记号。在

如果我改用and AutoLocator,则不会出现小记号。AutoMinorLocator只支持均匀缩放的轴。因此,我的问题是如何实现所需的勾号位置?在


Tags: import参数matplotlibasnpplt方向ticker
3条回答

OPs解决方案工作良好,但如果刻度线不是线性阈值的倍数,则不会在轴的边缘生成刻度线。我已经破解了OPsMinorSymLogLocator()类,给出了以下内容(在设置次要记号位置时,通过添加临时的主要记号位置来填充边缘):

class MinorSymLogLocator(Locator):
    """
    Dynamically find minor tick positions based on the positions of
    major ticks for a symlog scaling.
    """
    def __init__(self, linthresh, nints=10):
        """
        Ticks will be placed between the major ticks.
        The placement is linear for x between -linthresh and linthresh,
        otherwise its logarithmically. nints gives the number of
        intervals that will be bounded by the minor ticks.
        """
        self.linthresh = linthresh
        self.nintervals = nints

    def __call__(self):
        # Return the locations of the ticks
        majorlocs = self.axis.get_majorticklocs()

        if len(majorlocs) == 1:
            return self.raise_if_exceeds(np.array([]))

        # add temporary major tick locs at either end of the current range
        # to fill in minor tick gaps
        dmlower = majorlocs[1] - majorlocs[0]    # major tick difference at lower end
        dmupper = majorlocs[-1] - majorlocs[-2]  # major tick difference at upper end

        # add temporary major tick location at the lower end
        if majorlocs[0] != 0. and ((majorlocs[0] != self.linthresh and dmlower > self.linthresh) or (dmlower == self.linthresh and majorlocs[0] < 0)):
            majorlocs = np.insert(majorlocs, 0, majorlocs[0]*10.)
        else:
            majorlocs = np.insert(majorlocs, 0, majorlocs[0]-self.linthresh)

        # add temporary major tick location at the upper end
        if majorlocs[-1] != 0. and ((np.abs(majorlocs[-1]) != self.linthresh and dmupper > self.linthresh) or (dmupper == self.linthresh and majorlocs[-1] > 0)):
            majorlocs = np.append(majorlocs, majorlocs[-1]*10.)
        else:
            majorlocs = np.append(majorlocs, majorlocs[-1]+self.linthresh)

        # iterate through minor locs
        minorlocs = []

        # handle the lowest part
        for i in xrange(1, len(majorlocs)):
            majorstep = majorlocs[i] - majorlocs[i-1]
            if abs(majorlocs[i-1] + majorstep/2) < self.linthresh:
                ndivs = self.nintervals
            else:
                ndivs = self.nintervals - 1.

            minorstep = majorstep / ndivs
            locs = np.arange(majorlocs[i-1], majorlocs[i], minorstep)[1:]
            minorlocs.extend(locs)

        return self.raise_if_exceeds(np.array(minorlocs))

    def tick_values(self, vmin, vmax):
        raise NotImplementedError('Cannot get tick locations for a '
                          '%s type.' % type(self))

在这个问题上再深入一点,我发现很难找到一个普遍的解决办法。幸运的是,我可以假设对我的数据有一些限制,因此定制类就足以解决问题:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import Locator


class MinorSymLogLocator(Locator):
    """
    Dynamically find minor tick positions based on the positions of
    major ticks for a symlog scaling.
    """
    def __init__(self, linthresh):
        """
        Ticks will be placed between the major ticks.
        The placement is linear for x between -linthresh and linthresh,
        otherwise its logarithmically
        """
        self.linthresh = linthresh

    def __call__(self):
        'Return the locations of the ticks'
        majorlocs = self.axis.get_majorticklocs()

        # iterate through minor locs
        minorlocs = []

        # handle the lowest part
        for i in xrange(1, len(majorlocs)):
            majorstep = majorlocs[i] - majorlocs[i-1]
            if abs(majorlocs[i-1] + majorstep/2) < self.linthresh:
                ndivs = 10
            else:
                ndivs = 9
            minorstep = majorstep / ndivs
            locs = np.arange(majorlocs[i-1], majorlocs[i], minorstep)[1:]
            minorlocs.extend(locs)

        return self.raise_if_exceeds(np.array(minorlocs))

    def tick_values(self, vmin, vmax):
        raise NotImplementedError('Cannot get tick locations for a '
                                  '%s type.' % type(self))


x = np.linspace(-5, 5, 100)
y = x

plt.plot(x, y)
plt.yscale('symlog', linthreshy=1e-1)

yaxis = plt.gca().yaxis
yaxis.set_minor_locator(MinorSymLogLocator(1e-1))

plt.show()

这就产生了

enter image description here

请注意,此方法只在主要刻度之间放置刻度。如果您缩放和平移图像,这将变得明显。此外,线性阈值必须显式地提供给类,因为我找不到从轴本身轻松可靠地读取它的方法。在

我找到了一种更简单的方法,可能适用于:

我用了斧头组方法,其输出来自以下函数

def gen_tick_positions(scale_start=100, scale_max=10000):

    start, finish = np.floor(np.log10((scale_start, scale_max)))
    finish += 1
    majors = [10 ** x for x in np.arange(start, finish)]
    minors = []
    for idx, major in enumerate(majors[:-1]):
        minor_list = np.arange(majors[idx], majors[idx+1], major)
        minors.extend(minor_list[1:])
    return minors, majors

例如,你可以从这个区域推断出线性区域斧头。去拿钥匙()(即大约为零的值,不是10个不同的系数0-1/10)

^{pr2}$

然后给您一个开始值来放入上面的函数中,scale_max是您喜欢的任何值,例如total_scale[-1]。在

您可以使用first_log的正负区域来生成线性记号,然后合并列表。在

lin_ticks = list(np.linspace(first_log * -1, first_log, 21))
pos_log_ticks_minors, pos_log_ticks_majors = gen_tick_positions(first_log, scale_max)
neg_log_ticks_minors = [x * -1 for x in pos_log_ticks_minors]
neg_log_ticks_majors = [x * -1 for x in pos_log_ticks_majors]

final_scale_minors = neg_log_ticks_minors + lin_ticks + pos_log_ticks_minors

The merged list can then be passed into e.g.

ax.set_yticks(final_scale_minors, minor=True)

虽然我觉得你不需要从曲线图上或者从轴上读取线性阈值,因为当你应用“symlog”时,它被指定为一个参数。在

相关问题 更多 >

    热门问题