【问题标题】:Python - matplotlib - Custom ticks label in scientific notation while using log scale?Python - matplotlib - 使用对数刻度时以科学计数法自定义刻度标签?
【发布时间】:2020-07-29 18:25:09
【问题描述】:

我在使用 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.:抱歉可能出现的英语错误,这不是我的母语。

【问题讨论】:

    标签: python matplotlib logarithm scientific-notation ticker


    【解决方案1】:

    已解决,基于您上面的代码。这个简单多了。您需要使用 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 $10^{'  +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)
    

    【讨论】:

    • 首先,感谢您的回答。但是,您的解决方案是否不符合我的期望,无论我不明白,我很抱歉。事实上,我想要的是使用“十的指数幂”而不是“%X.Ye”格式来保存科学记数法。我编辑了自己的答案并放了想要的结果的图像。
    • 更新为您想要的确切形式。我想你会发现这个解决方案要简单得多。
    【解决方案2】:

    很抱歉重复发布,但我提出了一个解决方案,即使 不满意,也可能对其他人有用。

    我发现我的解决方案不令人满意,因为它涉及使用我的以下功能“手动”转换格式(我不是 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)
    

    这给出了想要的输出:

    它可以工作,但它太复杂了……我很确定我错过了一个更简单的功能。你怎么看?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-22
      • 2018-11-22
      • 2012-05-08
      • 2017-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多