簡體   English   中英

Matplotlib 對數刻度刻度標簽數字格式

[英]Matplotlib log scale tick label number formatting

當為軸指定對數刻度時,使用matplotlib標記該軸的默認方法是使用 10 次方的數字,例如。 10^6。 有沒有一種簡單的方法可以將所有這些標簽更改為它們的完整數字表示? 例如。 1、10、100 等

請注意,我不知道權力范圍是多少,並且希望支持任意范圍(包括負數)。

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

例如,如果我們有這個情節:

import matplotlib.pyplot as plt

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

plt.show()

在此處輸入圖像描述

您可以手動設置刻度標簽,但是當您縮放/平移/等時,刻度位置和標簽將被固定。 因此,最好更改格式化程序。 默認情況下,對數刻度使用LogFormatter ,它將以科學計數法格式化值。 要將格式化程序更改為線性軸的默認值( ScalarFormatter ),請使用例如

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

在此處輸入圖像描述

我發現如果您的所有刻度值都大於或等於 1,則使用ScalarFormatter非常好。但是,如果您在數字<1處有刻度,則ScalarFormatter將刻度標簽打印為0

在此處輸入圖像描述

我們可以使用 matplotlib ticker模塊中的FuncFormatter來解決這個問題。 最簡單的方法是使用lambda函數和g格式說明符(感謝注釋中的@lenz)。

import matplotlib.ticker as ticker

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

請注意,在我的原始答案中,我沒有使用g格式,而是使用FuncFormatter提出了這個lambda函數,將數字>= 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)))

在此處輸入圖像描述

為清楚起見,這里的 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))

我發現JoeTom 的答案非常有幫助,但在這些答案的評論中有很多有用的細節。 以下是兩種情況的摘要:

范圍大於 1

這是類似於 Joe 的示例代碼,但范圍更大:

import matplotlib.pyplot as plt

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

plt.show()

這顯示了這樣的情節,使用科學記數法: 帶有科學計數法的默認繪圖

正如喬的回答一樣,我使用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()

用整數刻度繪圖

范圍低於 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 軸上的前兩個刻度顯示為零。

繪制標記為零的刻度

切換到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()

在此處輸入圖像描述

關於這些問題

如果我想將數字更改為 1、5、10、20 怎么辦?
– aloha 2015 年 7 月 10 日 13:26

我想在兩者之間添加刻度,例如 50,200 等,我該怎么做? 我試過了, set_xticks[50.0,200.0] 但這似乎不起作用! – 捕食者 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])

在我的應用程序中,我使用了這種格式方案,我認為它可以解決與日志標量格式相關的大多數問題; 數據 > 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

產生:

在此處輸入圖像描述

然后創建一個通用機器:

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

產量:

在此處輸入圖像描述

接受的答案中概述的機器效果很好,但有時簡單的手動覆蓋更容易。 例如,要獲得 1、10、100、1000 的刻度,您可以說:

ticks = 10**np.arange(4)
plt.xticks(ticks, ticks)

請注意,指定位置和標簽至關重要,否則 matplotlib 將忽略您。

此機制可用於獲取任意格式。 例如:

plt.xticks(ticks, [ f"{x:.0f}" for x in ticks ])

或者

plt.xticks(ticks, [ f"10^{int(np.log10(x))}" for x in ticks ])

或者

plt.xticks(ticks, [ romannumerals(x) for x in ticks ])

(其中romannumerals是將其參數轉換為羅馬數字的想象函數)。

順便說一句,如果您希望以任意間隔進行刻度,此技術也適用,例如,

ticks = [1, 2, 5, 10, 20, 50, 100]

等等

import matplotlib.pyplot as plt

plt.rcParams['axes.formatter.min_exponent'] = 2
plt.xlim(1e-5, 1e5)
plt.loglog()

plt.show()

這將成為會話中所有繪圖的默認設置。

另請參閱: LogFormatter 標記科學格式限制

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM