Python Matplotlib 对数刻度刻度标签数字格式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21920233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 23:52:17  来源:igfitidea点击:

Matplotlib log scale tick label number formatting

pythonnumpymatplotlibgraphing

提问by Nat Dempkowski

With matplotlibwhen a log scale is specified for an axis, the default method of labeling that axis is with numbers that are 10 to a power eg. 10^6. Is there an easy way to change all of these labels to be their full numerical representation? eg. 1, 10, 100, etc.

matplotlib当对于一个轴被指定一个对数标度,标记该轴的默认方法是与是10到电源例如数字。10^6。有没有一种简单的方法可以将所有这些标签更改为它们的完整数字表示?例如。1、10、100 等

Note that I do not know what the range of powers will be and want to support an arbitrary range (negatives included).

请注意,我不知道权力的范围是多少,并希望支持任意范围(包括负数)。

采纳答案by Joe Kington

Sure, just change the formatter.

当然,只需更改格式化程序。

For example, if we have this plot:

例如,如果我们有这个图:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 100000])
ax.loglog()

plt.show()

enter image description here

在此处输入图片说明

You could set the tick labels manually, but then the tick locations and labels would be fixed when you zoom/pan/etc. Therefore, it's best to change the formatter. By default, a logarithmic scale uses a LogFormatter, which will format the values in scientific notation. To change the formatter to the default for linear axes (ScalarFormatter) use e.g.

您可以手动设置刻度标签,但是当您缩放/平移/等时,刻度位置和标签将被固定。因此,最好更改格式化程序。默认情况下,对数刻度使用LogFormatter,它将以科学记数法格式化值。要将格式化程序更改为线性轴 ( ScalarFormatter)的默认值,请使用例如

from matplotlib.ticker import ScalarFormatter
for axis in [ax.xaxis, ax.yaxis]:
    axis.set_major_formatter(ScalarFormatter())

enter image description here

在此处输入图片说明

回答by tmdavison

I've found that using ScalarFormatteris great if all your tick values are greater than or equal to 1. However, if you have a tick at a number <1, the ScalarFormatterprints the tick label as 0.

我发现,使用ScalarFormatter是伟大的,如果你所有的刻度值都大于或等于1。但是,如果你在一些有蜱<1,在ScalarFormatter打印刻度标记为0

enter image description here

在此处输入图片说明

We can use a FuncFormatterfrom the matplotlib tickermodule to fix this issue. The simplest way to do this is with a lambdafunction and the gformat specifier (thanks to @lenz in comments).

我们可以使用FuncFormattermatplotlibticker模块中的 a 来解决这个问题。最简单的方法是使用lambda函数和g格式说明符(感谢@lenz 在评论中)。

import matplotlib.ticker as ticker

ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y, _: '{:g}'.format(y)))

Note in my original answer I didn't use the gformat, instead I came up with this lambdafunction with FuncFormatterto set numbers >= 1to their integer value, and numbers <1to their decimal value, with the minimum number of decimal places required (i.e. 0.1, 0.01, 0.001, etc). It assumes that you are only setting ticks on the base10values.

请注意,在我的原始答案中,我没有使用g格式,而是提出了这个lambda函数,FuncFormatter用于将数字设置>= 1为整数值,将数字设置<1为十进制值,并具有所需的最小小数位数(即0.1, 0.01, 0.001,等)。它假设您只是在base10值上设置刻度。

import matplotlib.ticker as ticker
import numpy as np

ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y,pos: ('{{:.{:1d}f}}'.format(int(np.maximum(-np.log10(y),0)))).format(y)))

enter image description here

在此处输入图片说明

For clarity, here's that lambda function written out in a more verbose, but also more understandable, way:

为清楚起见,下面是用更冗长但也更易于理解的方式写出的 lambda 函数:

def myLogFormat(y,pos):
    # Find the number of decimal places required
    decimalplaces = int(np.maximum(-np.log10(y),0))     # =0 for numbers >=1
    # Insert that number into a format string
    formatstring = '{{:.{:1d}f}}'.format(decimalplaces)
    # Return the formatted tick label
    return formatstring.format(y)

ax.yaxis.set_major_formatter(ticker.FuncFormatter(myLogFormat))

回答by litepresence

regarding these questions

关于这些问题

What if I wanted to change the numbers to, 1, 5, 10, 20?
– aloha Jul 10 '15 at 13:26

I would like to add ticks in between, like 50,200, etc.., How can I do that? I tried, set_xticks[50.0,200.0] but that doesn't seem to work! – ThePredator Aug 3 '15 at 12:54

But with ax.axis([1, 100, 1, 100]), ScalarFormatter gives 1.0, 10.0, ... which is not what I desire. I want it to give integers... – CPBL Dec 7 '15 at 20:22

如果我想将数字更改为 1、5、10、20 怎么办?
– 阿罗哈 15 年 7 月 10 日 13:26

我想在两者之间添加刻度,例如 50,200 等,我该怎么做?我试过, set_xticks[50.0,200.0] 但这似乎不起作用!– ThePredator 2015 年 8 月 3 日 12:54

但是使用 ax.axis([1, 100, 1, 100]),ScalarFormatter 给出 1.0, 10.0, ... 这不是我想要的。我希望它给出整数... – CPBL 2015 年 12 月 7 日 20:22

you can solve those issue like this with MINOR formatter:

您可以使用 MINOR 格式化程序解决这些问题:

ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
ax.set_yticks([0.00000025, 0.00000015, 0.00000035])

in my application I'm using this format scheme, which I think solves most issues related to log scalar formatting; the same could be done for data > 1.0 or x axis formatting:

在我的应用程序中,我使用了这种格式方案,我认为它解决了与日志标量格式相关的大多数问题;对于数据 > 1.0 或 x 轴格式也可以这样做:

plt.ylabel('LOGARITHMIC PRICE SCALE')
plt.yscale('log')
ax.yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_major_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
#####################################################
#force 'autoscale'
#####################################################
yd = [] #matrix of y values from all lines on plot
for n in range(len(plt.gca().get_lines())):
        line = plt.gca().get_lines()[n]
        yd.append((line.get_ydata()).tolist())
yd = [item for sublist in yd for item in sublist]
ymin, ymax = np.min(yd), np.max(yd)
ax.set_ylim([0.9*ymin, 1.1*ymax])
#####################################################
z = []
for i in [0.0000001, 0.00000015, 0.00000025, 0.00000035,
          0.000001, 0.0000015, 0.0000025, 0.0000035,
          0.00001,  0.000015, 0.000025, 0.000035,
          0.0001, 0.00015, 0.00025, 0.00035,
          0.001, 0.0015, 0.0025, 0.0035,
          0.01, 0.015, 0.025, 0.035,
          0.1, 0.15, 0.25, 0.35]:

    if ymin<i<ymax:
        z.append(i)
        ax.set_yticks(z)                

for comments on "force autoscale" see:Python matplotlib logarithmic autoscale

有关“强制自动缩放”的评论,请参阅:Python matplotlib logarithmic autoscale

which yields:

产生:

enter image description here

在此处输入图片说明

then to create a general use machine:

然后创建一个通用机器:

# user controls
#####################################################
sub_ticks = [10,11,12,14,16,18,22,25,35,45] # fill these midpoints
sub_range = [-8,8] # from 100000000 to 0.000000001
format = "%.8f" # standard float string formatting

# set scalar and string format floats
#####################################################
ax.yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_major_formatter(matplotlib.ticker.FormatStrFormatter(format))
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter(format))

#force 'autoscale'
#####################################################
yd = [] #matrix of y values from all lines on plot
for n in range(len(plt.gca().get_lines())):
        line = plt.gca().get_lines()[n]
        yd.append((line.get_ydata()).tolist())
yd = [item for sublist in yd for item in sublist]
ymin, ymax = np.min(yd), np.max(yd)
ax.set_ylim([0.9*ymin, 1.1*ymax])

# add sub minor ticks
#####################################################
set_sub_formatter=[]
for i in sub_ticks:
    for j in range(sub_range[0],sub_range[1]):
        set_sub_formatter.append(i*10**j)
k = []
for l in set_sub_formatter:
    if ymin<l<ymax:
        k.append(l)
ax.set_yticks(k)
#####################################################

yields:

产量:

enter image description here

在此处输入图片说明

回答by Don Kirkby

I found Joe'sand Tom'sanswers very helpful, but there are a lot of useful details in the comments on those answers. Here's a summary of the two scenarios:

我发现JoeTom 的答案非常有帮助,但在这些答案的评论中有很多有用的细节。以下是两种情况的摘要:

Ranges above 1

范围大于 1

Here's the example code like Joe's, but with a higher range:

这是类似于 Joe 的示例代码,但范围更大:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 1000000])
ax.loglog()

plt.show()

That shows a plot like this, using scientific notation: Default plot with scientific notation

这显示了这样的图,使用科学记数法: 带科学记数法的默认图

As in Joe's answer, I use a ScalarFormatter, but I also call set_scientific(False). That's necessary when the scale goes up to 1000000 or above.

就像乔的回答一样,我使用了ScalarFormatter,但我也调用了set_scientific(False)。当规模达到 1000000 或更高时,这是必要的。

import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter

fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
    formatter = ScalarFormatter()
    formatter.set_scientific(False)
    axis.set_major_formatter(formatter)

plt.show()

Plot with integer ticks

用整数刻度绘图

Ranges below 1

低于 1 的范围

As in Tom's answer, here's what happens when the range goes below 1:

正如汤姆的回答,当范围低于 1 时会发生以下情况:

import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter

fig, ax = plt.subplots()
ax.axis([0.01, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
    formatter = ScalarFormatter()
    formatter.set_scientific(False)
    axis.set_major_formatter(formatter)

plt.show()

That displays the first two ticks on the x axis as zeroes.

这将 x 轴上的前两个刻度显示为零。

Plot with ticks labelled as zero

标有零刻度的绘图

Switching to a FuncFormatterhandles that. Again, I had problems with numbers 1000000 or higher, but adding a precision to the format string solved it.

切换到FuncFormatter处理那个。再次,我遇到了数字 1000000 或更高的问题,但向格式字符串添加精度解决了它。

import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

fig, ax = plt.subplots()
ax.axis([0.01, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
    formatter = FuncFormatter(lambda y, _: '{:.16g}'.format(y))
    axis.set_major_formatter(formatter)

plt.show()

enter image description here

在此处输入图片说明