【问题标题】:Matplotlib: log scale for values too small for floating pointMatplotlib:对浮点值太小的日志比例
【发布时间】:2017-10-27 21:47:24
【问题描述】:

我想用 matplotlib 绘制一个值非常小的图,以对数刻度显示。这工作正常,直到数字变得太小并且不适合浮点数。

我使用 SymPy 任意精度浮点数表示值,但这些显然在 matplotlib 内部转换为 Python 或 NumPy 机器浮点数。

例如

>>> import sympy
>>> import matplotlib.pyplot as plt
>>> plt.plot([0, 1, 2], [sympy.Float('1e-20'), sympy.Float('1e-100'), sympy.Float('1e-700')])
[<matplotlib.lines.Line2D object at 0x11ac0c208>]
>>> plt.yscale('log')

产生

它应该显示的是 10^-700 处的第三个值(不是负无穷大)。

现在我几乎没有希望让 matplotlib 在内部使用 SymPy Floats(如果可能,请告诉我)。我想做的是为 matplotlib 提供值的对数,我可以自己计算得很好,但仍然在 y 轴上以对数刻度显示该值的指数。

【问题讨论】:

    标签: python matplotlib plot floating-point sympy


    【解决方案1】:

    你可以做log计算然后绘制数据,如果你想要相同的刻度标签,你可以使用FuncFormatter

    import sympy
    import matplotlib.pyplot as plt
    from matplotlib.ticker import FuncFormatter
    
    x = [0, 1, 2]
    y = [sympy.Float('1e-20'), sympy.Float('1e-100'), sympy.Float('1e-700')]
    
    def log_formatter(x, pos):
        return "$10^{{{:d}}}$".format(int(x))
    
    formatter = FuncFormatter(log_formatter)
    
    fig, ax = plt.subplots()
    
    y2 = list(map(lambda x:sympy.log(x, 10), y))
    ax.plot(x, y2)
    ax.yaxis.set_major_formatter(formatter)
    ax.grid();
    

    编辑

    要添加对数刻度的次要刻度,您可以创建一个Locator

    import sympy
    import matplotlib.pyplot as plt
    from matplotlib.ticker import FuncFormatter, Locator
    
    x = [0, 1, 2]
    y = [sympy.Float('1e-20'), sympy.Float('1e-100'), sympy.Float('1e-700')]
    
    def log_formatter(x, pos):
        return "$10^{{{:d}}}$".format(int(x))
    
    class LogMinorLocator(Locator):
        def __call__(self):
            majorlocs = self.axis.get_majorticklocs()
            step = majorlocs[1] - majorlocs[0]
            res = majorlocs[:, None] + np.log10(np.linspace(1, 0.1, 10)) * step
            return res.ravel()
    
    formatter = FuncFormatter(log_formatter)
    
    fig, ax = plt.subplots(figsize=(12, 8))
    y2 = list(map(lambda x:sympy.log(x, 10), y))
    ax.plot(x, y2)
    ax.minorticks_on()
    ax.yaxis.set_major_formatter(formatter)
    ax.yaxis.set_minor_locator(LogMinorLocator())
    ax.grid();
    

    这是输出:

    【讨论】:

    • 好玩的技巧,你可以用@FuncFormatter装饰log_formatter,然后直接传递给set_major_formatter
    • 这是否像普通对数轴一样使用对数子刻度?
    猜你喜欢
    • 2015-06-10
    • 2020-10-31
    • 1970-01-01
    • 2022-08-10
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多