Matplotlib日志刻度刻度标签编号格式

时间:2014-02-20 21:42:24

标签: python numpy matplotlib graphing

在为轴指定对数刻度时使用matplotlib,标记该轴的默认方法是使用10到一个幂的数字,例如。 10 ^ 6。是否有一种简单的方法可以将所有这些标签更改为完整的数字表示?例如。 1,10,100等

请注意,我不知道功率范围是什么,并且想要支持任意范围(包括负数)。

4 个答案:

答案 0 :(得分:50)

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

例如,如果我们有这个情节:

import matplotlib.pyplot as plt

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

plt.show()

enter image description here

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

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

enter image description here

答案 1 :(得分:31)

我发现如果您的所有刻度值都大于或等于1,则使用ScalarFormatter非常有用。但是,如果您勾选了数字<1ScalarFormatter 1}}将刻度标签打印为0

enter image description here

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

import matplotlib.ticker as ticker

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

请注意,在我的原始回答中,我没有使用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

为清楚起见,这里的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))

答案 2 :(得分:6)

我发现Joe'sTom's答案非常有用,但在这些答案的评论中有很多有用的细节。以下是两种情景的摘要:

超过1

的范围

以下是像Joe这样的示例代码,但范围更广:

import matplotlib.pyplot as plt

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

plt.show()

使用科学记数法显示这样的情节: Default plot with scientific notation

在Joe的回答中,我使用了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

低于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()

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

Plot with ticks labelled as zero

切换到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

答案 3 :(得分:5)

关于这些问题

  

如果我想将数字更改为1,5,10,20,该怎么办?    - aloha 2015年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

您可以使用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])

在我的应用程序中我正在使用这种格式方案,我认为这解决了与日志标量格式相关的大多数问题;可以对数据进行相同的操作&gt; 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)                

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

产生:

enter image description here

然后创建一个通用机器:

# 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)
#####################################################

的产率:

enter image description here