如何在symlog规模上放置小蜱?

Dav*_*ker 12 python matplotlib

我使用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()
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不会产生我想要的东西:

在此输入图像描述

请注意,在0附近有许多小的刻度,这可能是由于LogLocator.此外,负轴上没有小的刻度.

如果我使用而AutoLocator不是出现轻微的刻度.该AutoMinorLocator不会只支持按比例均匀轴.我的问题是如何实现所需的刻度位置?

Dav*_*ker 13

深入研究这个问题,我注意到很难找到一个通用的解决方案.幸运的是,我可以假设我的数据受到一些限制,因此定制的类足以解决问题:

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()
Run Code Online (Sandbox Code Playgroud)

这产生了

在此输入图像描述

请注意,此方法仅在主要刻度之间放置刻度.如果您缩放并平移图像,这将变得明显.此外,线性阈值必须明确地提供给类,因为我发现无法从轴本身轻松而稳健地读取它.


Mat*_*kin 6

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))
Run Code Online (Sandbox Code Playgroud)