Python - matplotlib - 使用对数刻度时以科学计数法自定义刻度标签?
Python - matplotlib - Custom ticks label in scientific notation while using log scale?
我在使用 matplotlib(版本 3.1.3)时遇到问题:我想在对数刻度轴上添加自定义刻度和刻度标签,同时保留科学记数法。
换句话说:我想在对数刻度轴上添加自定义刻度并使用老式的“%1.1e”(或任何数字)格式标记它们,但是,例如,而不是“ 2.5e-02',我想要'2.5 x 10^-2'(或乳胶中的'2.5 \times 10^{-2}')。
所以我从没有自定义刻度的最小工作代码开始:
import matplotlib as mpl
import matplotlib.pyplot as plt
print('MATPLOTLIB VERSION : %s' % mpl.__version__)
plt.style.use("default")
# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x
fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
path = ax.plot(x, y)
plt.savefig('test.png')
给出:
不错,但正如我所说,我想在 x 轴上添加自定义刻度。更准确地说,我想限制轴并在这些限制之间定义对数间隔相等的标签。假设我想要 4 个刻度;它给出了以下代码:
import matplotlib as mpl
import matplotlib.pyplot as plt
print('MATPLOTLIB VERSION : %s' % mpl.__version__)
plt.style.use("default")
# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x
xmin = min(x)
xmax = max(x)
ymin = min(y)
ymax = max(y)
# XTICKS
nbdiv = 4
xTicks = []
k = pow((xmin/xmax),1./(nbdiv-1.))
for i in range(0,nbdiv):
xTicks.append(xmax*pow(k,i))
# PLOT
fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
plt.axis([xmin,xmax,ymin,ymax])
plt.xticks(xTicks)
path = ax.plot(x, y)
plt.savefig('test_working_4.png')
提供了以下情节:
这就是我想要得到的结果。但是,如果滴答数 (nbdiv) 发生变化,例如变为等于 5,我会得到:
这次只标记了第一个和最后一个刻度。似乎只有等于(或至少接近)十(10^n)的整数次方的数字才被标记。我试图用 matplot.ticker.ScalarFormatter 更改默认的刻度格式,但我没能调整它来解决这个问题。我还尝试了 LogFormatterMathText 和 LogFormatterSciNotation,但并没有更好。
这个问题本身对我来说似乎并不难,所以我不明白为什么我遇到这么多麻烦......我做错了什么?有人有钥匙让我明白我的错误吗?
无论如何,感谢您的阅读,并提前感谢您的回复。
P.S.: 抱歉可能有英文错误,这不是我的母语。
抱歉重复发帖,但我提出了一个解决方案,即使 不令人满意,也可能对其他人有用。
我发现我的解决方案并不令人满意,因为它涉及到使用我的以下功能转换格式 "by hand"(我不是 Python 方面的专家,所以我确定它可能是 simplified/optimized ):
def convert_e_format_to_latex(numberAsStr):
# CONVERTS THE STRING numberAsStr IN FORMAT '%X.Ye' TO A LATEX 'X \times 10^{Y}'
baseStr = list(numberAsStr)
ind = 0
i = 0
flag = True
nStr = len(baseStr)
while (i < nStr and flag):
if (baseStr[i] == 'e' or baseStr[i] == 'E'): # NOT USING FIND BECAUSE 'e' CAN ALSO BE CAPITAL
ind = i
flag = False
i += 1
if (flag):
print('ERROR: badly formatted input number')
return ''
else:
expo = str(int(''.join(baseStr[ind+1:nStr]))) # GET RID OF POTENTIAL ZEROS
root = ''.join(baseStr[0:ind])
indP = root.find('.')
integerPart = int(root[0:indP]) #integer
decimalPart = root[indP+1:ind] #string
if (integerPart == 1): #DETECTING IF THE ROOT IS ONE (positive value)
x = ''.center(ind-(indP+1),'0')
if (decimalPart == x):
return '^{'+expo+'}$'
else:
return '$'+str(integerPart)+'.'+decimalPart+' \times 10^{'+expo+'}$'
elif (integerPart== -1): #DETECTING IF THE ROOT IS ONE (positive value)
x = ''.center(ind-(indP+1),'0')
if (decimalPart == x):
return '$-10^{'+expo+'}$'
else:
return '$'+str(integerPart)+'.'+decimalPart+' \times 10^{'+expo+'}$'
else:
return '$'+str(integerPart)+'.'+decimalPart+' \times 10^{'+expo+'}$'
然后我在之前的代码中添加:
for i in range(0,nbdiv):
xTicksStr.append(convert_e_format_to_latex('%1.1e'%xTicks[i]))
然后我更改了图中的 xticks 指令,它变成了:
plt.xticks(xTicks,xTicksStr)
这给出了想要的输出:
它可以工作,但是太复杂了...我很确定我错过了一个更简单的功能。你怎么看?
已解决,基于您上面的代码。这个要简单得多。你需要使用 xticklabels.
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
from sympy import pretty_print as pp, latex
print('MATPLOTLIB VERSION : %s' % mpl.__version__)
plt.style.use("default")
# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x
xmin = min(x)
xmax = max(x)
ymin = min(y)
ymax = max(y)
# XTICKS
nbdiv = 5
xTicks = []
xticklabels = []
k = pow((xmin/xmax),1./(nbdiv-1.))
for i in range(0,nbdiv):
xTicks.append(xmax*pow(k,i))
printstr = '{:.2e}'.format(xmax*pow(k,i))
ls = printstr.split('e')
xticklabels.append((ls[0]+' x ^{' +ls[1] + '}$'))
# PLOT
fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
plt.axis([xmin,xmax,ymin,ymax])
plt.xticks(xTicks)
path = ax.plot(x, y)
plt.savefig('test_working_4.png')
ax.set_xticklabels(xticklabels)
我在使用 matplotlib(版本 3.1.3)时遇到问题:我想在对数刻度轴上添加自定义刻度和刻度标签,同时保留科学记数法。
换句话说:我想在对数刻度轴上添加自定义刻度并使用老式的“%1.1e”(或任何数字)格式标记它们,但是,例如,而不是“ 2.5e-02',我想要'2.5 x 10^-2'(或乳胶中的'2.5 \times 10^{-2}')。
所以我从没有自定义刻度的最小工作代码开始:
import matplotlib as mpl
import matplotlib.pyplot as plt
print('MATPLOTLIB VERSION : %s' % mpl.__version__)
plt.style.use("default")
# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x
fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
path = ax.plot(x, y)
plt.savefig('test.png')
给出:
不错,但正如我所说,我想在 x 轴上添加自定义刻度。更准确地说,我想限制轴并在这些限制之间定义对数间隔相等的标签。假设我想要 4 个刻度;它给出了以下代码:
import matplotlib as mpl
import matplotlib.pyplot as plt
print('MATPLOTLIB VERSION : %s' % mpl.__version__)
plt.style.use("default")
# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x
xmin = min(x)
xmax = max(x)
ymin = min(y)
ymax = max(y)
# XTICKS
nbdiv = 4
xTicks = []
k = pow((xmin/xmax),1./(nbdiv-1.))
for i in range(0,nbdiv):
xTicks.append(xmax*pow(k,i))
# PLOT
fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
plt.axis([xmin,xmax,ymin,ymax])
plt.xticks(xTicks)
path = ax.plot(x, y)
plt.savefig('test_working_4.png')
提供了以下情节:
这就是我想要得到的结果。但是,如果滴答数 (nbdiv) 发生变化,例如变为等于 5,我会得到:
这次只标记了第一个和最后一个刻度。似乎只有等于(或至少接近)十(10^n)的整数次方的数字才被标记。我试图用 matplot.ticker.ScalarFormatter 更改默认的刻度格式,但我没能调整它来解决这个问题。我还尝试了 LogFormatterMathText 和 LogFormatterSciNotation,但并没有更好。
这个问题本身对我来说似乎并不难,所以我不明白为什么我遇到这么多麻烦......我做错了什么?有人有钥匙让我明白我的错误吗?
无论如何,感谢您的阅读,并提前感谢您的回复。
P.S.: 抱歉可能有英文错误,这不是我的母语。
抱歉重复发帖,但我提出了一个解决方案,即使 不令人满意,也可能对其他人有用。
我发现我的解决方案并不令人满意,因为它涉及到使用我的以下功能转换格式 "by hand"(我不是 Python 方面的专家,所以我确定它可能是 simplified/optimized ):
def convert_e_format_to_latex(numberAsStr):
# CONVERTS THE STRING numberAsStr IN FORMAT '%X.Ye' TO A LATEX 'X \times 10^{Y}'
baseStr = list(numberAsStr)
ind = 0
i = 0
flag = True
nStr = len(baseStr)
while (i < nStr and flag):
if (baseStr[i] == 'e' or baseStr[i] == 'E'): # NOT USING FIND BECAUSE 'e' CAN ALSO BE CAPITAL
ind = i
flag = False
i += 1
if (flag):
print('ERROR: badly formatted input number')
return ''
else:
expo = str(int(''.join(baseStr[ind+1:nStr]))) # GET RID OF POTENTIAL ZEROS
root = ''.join(baseStr[0:ind])
indP = root.find('.')
integerPart = int(root[0:indP]) #integer
decimalPart = root[indP+1:ind] #string
if (integerPart == 1): #DETECTING IF THE ROOT IS ONE (positive value)
x = ''.center(ind-(indP+1),'0')
if (decimalPart == x):
return '^{'+expo+'}$'
else:
return '$'+str(integerPart)+'.'+decimalPart+' \times 10^{'+expo+'}$'
elif (integerPart== -1): #DETECTING IF THE ROOT IS ONE (positive value)
x = ''.center(ind-(indP+1),'0')
if (decimalPart == x):
return '$-10^{'+expo+'}$'
else:
return '$'+str(integerPart)+'.'+decimalPart+' \times 10^{'+expo+'}$'
else:
return '$'+str(integerPart)+'.'+decimalPart+' \times 10^{'+expo+'}$'
然后我在之前的代码中添加:
for i in range(0,nbdiv):
xTicksStr.append(convert_e_format_to_latex('%1.1e'%xTicks[i]))
然后我更改了图中的 xticks 指令,它变成了:
plt.xticks(xTicks,xTicksStr)
这给出了想要的输出:
它可以工作,但是太复杂了...我很确定我错过了一个更简单的功能。你怎么看?
已解决,基于您上面的代码。这个要简单得多。你需要使用 xticklabels.
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
from sympy import pretty_print as pp, latex
print('MATPLOTLIB VERSION : %s' % mpl.__version__)
plt.style.use("default")
# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x
xmin = min(x)
xmax = max(x)
ymin = min(y)
ymax = max(y)
# XTICKS
nbdiv = 5
xTicks = []
xticklabels = []
k = pow((xmin/xmax),1./(nbdiv-1.))
for i in range(0,nbdiv):
xTicks.append(xmax*pow(k,i))
printstr = '{:.2e}'.format(xmax*pow(k,i))
ls = printstr.split('e')
xticklabels.append((ls[0]+' x ^{' +ls[1] + '}$'))
# PLOT
fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
plt.axis([xmin,xmax,ymin,ymax])
plt.xticks(xTicks)
path = ax.plot(x, y)
plt.savefig('test_working_4.png')
ax.set_xticklabels(xticklabels)