我在使用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')
给出:
很好,但是,正如我所说,我想在xaxis上添加自定义刻度。更准确地说,我想对轴设置限制,并在这些限制之间定义均等的日志分隔标签。假设我要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 .:对不起,潜在的英语错误,这不是我的母语。
已解决,根据您上面的代码。这个简单得多。您需要使用xticklabels。
%matplotlib inline
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 = []
xticklabels = []
k = pow((xmin/xmax),1./(nbdiv-1.))
for i in range(0,nbdiv):
xTicks.append(xmax*pow(k,i))
xticklabels.append( '{:.3g}'.format(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')
ax.set_xticklabels(xticklabels)
很抱歉重复发表文章,但我提供了一个解决方案,即使不令人满意,该解决方案也可能对他人有用。
我发现我的解决方案不尽人意,因为它涉及使用以下功能转换“手工”格式(我不是Python的专家,所以我敢肯定它可以简化/优化):
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 '$10^{'+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)
这给出了所需的输出:
它可以工作,但是它是如此复杂...我很确定我错过了一个更简单的功能。你怎么看?