在matplotlib轴上设置科学限制后调整指数文本

2024-04-25 04:15:36 发布

您现在位置:Python中文网/ 问答频道 /正文

目前,如果我将matplotlib y轴tickleables设置为科学模式,它会在表单的y轴顶部给出一个指数1e-5

我想把它调整成r'$\mathregular{10^{-5}}$'这样它就能很好地打印出来。

下面是我的示例代码:

# Create a figure and axis
fig, ax = plt.subplots()

# Plot 100 random points 
# the y values of which are very small
ax.scatter(np.random.rand(100), np.random.rand(100)/100000.0)

# Set the y limits appropriately
ax.set_ylim(0, 1/100000.0)

# Change the y ticklabel format to scientific format
ax.ticklabel_format(axis='y', style='sci', scilimits=(-2, 2))

# Get the offset value
offset = ax.yaxis.get_offset_text()

# Print it out
print '1st offset printout: {}'.format(offset)

# Run plt.tight_layout()
plt.tight_layout()

# Print out offset again - you can see the value now!
print '2nd offset printout: {}'.format(offset)

# Change it to latex format
offset.set_text(r'$\mathregular{10^{-5}}$')

# Print it out
print '3rd offset printout: {}'.format(offset)

# Add some text to the middle of the figure just to 
# check that it isn't the latex format that's the problem
ax.text(0.5, 0.5/100000.0, r'$\mathregular{10^{-2}}$')

# And show the figure
plt.show()

我的输出如下:

1st offset printout: Text(0,0.5,u'')
2nd offset printout: Text(0,636.933,u'1e\u22125')
3rd offset printout: Text(0,636.933,u'$\\mathregular{10^{-5}}$')

enter image description here

您可以找到代码并输出图here

有两个奇怪的地方:一个是我不能覆盖y轴顶部的1e-5(这是目标),另一个是我必须运行plt.tight_layout()才能看到unicode值作为偏移量。

有人能告诉我哪里出错了吗?

谢谢你

编辑:最初的问题没有说明我想自动检测当前由ticklabel_format计算的指数。因此,与其将设置字符串传递给偏移文本,不如自动检测该值并相应地调整乳胶字符串。


Tags: thetotextformatitpltrandomax
3条回答

基于@edsmith的答案,我想做的一个可能的工作是获取偏移文本,将其转换为乳胶字符串,关闭偏移并在轴的顶部添加该字符串。

def format_exponent(ax, axis='y'):

    # Change the ticklabel format to scientific format
    ax.ticklabel_format(axis=axis, style='sci', scilimits=(-2, 2))

    # Get the appropriate axis
    if axis == 'y':
        ax_axis = ax.yaxis
        x_pos = 0.0
        y_pos = 1.0
        horizontalalignment='left'
        verticalalignment='bottom'
    else:
        ax_axis = ax.xaxis
        x_pos = 1.0
        y_pos = -0.05
        horizontalalignment='right'
        verticalalignment='top'

    # Run plt.tight_layout() because otherwise the offset text doesn't update
    plt.tight_layout()
    ##### THIS IS A BUG 
    ##### Well, at least it's sub-optimal because you might not
    ##### want to use tight_layout(). If anyone has a better way of 
    ##### ensuring the offset text is updated appropriately
    ##### please comment!

    # Get the offset value
    offset = ax_axis.get_offset_text().get_text()

    if len(offset) > 0:
        # Get that exponent value and change it into latex format
        minus_sign = u'\u2212'
        expo = np.float(offset.replace(minus_sign, '-').split('e')[-1])
        offset_text = r'x$\mathregular{10^{%d}}$' %expo

        # Turn off the offset text that's calculated automatically
        ax_axis.offsetText.set_visible(False)

        # Add in a text box at the top of the y axis
        ax.text(x_pos, y_pos, offset_text, transform=ax.transAxes,
               horizontalalignment=horizontalalignment,
               verticalalignment=verticalalignment)
    return ax

注意,您应该可以通过调用pos = ax_axis.get_offset_text().get_position()来使用偏移文本的位置,但是这些值不是以轴为单位(它们可能是像素单位-谢谢@EdSmith-因此不是很有用)。因此,我只是根据我们所看到的轴来设置x_posy_pos值。

我还编写了一个小函数来自动检测适当的x和y限制(尽管我知道matplotlib有很多奇特的方法可以做到这一点)。

def get_min_max(x, pad=0.05):
    '''
    Find min and max values such that
    all the data lies within 90% of
    of the axis range
    '''
    r = np.max(x) - np.min(x)
    x_min = np.min(x) - pad * r
    x_max = np.max(x) + pad * r
    return x_min, x_max

因此,要根据问题更新我的示例(稍微更改一下,使两个轴都需要指数):

import matplotlib.pylab as plt
import numpy as np

# Create a figure and axis
fig, ax = plt.subplots()

# Plot 100 random points that are very small
x = np.random.rand(100)/100000.0
y = np.random.rand(100)/100000.0
ax.scatter(x, y)

# Set the x and y limits
x_min, x_max = get_min_max(x)
ax.set_xlim(x_min, x_max)
y_min, y_max = get_min_max(y)    
ax.set_ylim(y_min, y_max)

# Format the exponents nicely
ax = format_exponent(ax, axis='x')
ax = format_exponent(ax, axis='y')

# And show the figure
plt.show()

enter image description here

一个带有ipython笔记本的显示代码输出的要点是可用的here

我希望这能有帮助!

您得到offset并设置文本值,但似乎没有办法将其实际应用于轴。。。即使调用ax.yaxis.offsetText.set_text(offset)也不会更新显示的偏移量。解决方法是删除偏移文本并替换为轴标签上的括号

ax.yaxis.offsetText.set_visible(False)
ax.set_ylabel("datalabel " +  r'$\left(\mathregular{10^{-5}}\right)$')

或者替换为手动文本框,作为一个最小的例子

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# Create a figure and axis
fig, ax = plt.subplots()
mpl.rc('text', usetex = True)

# Plot 100 random points 
# the y values of which are very small
large = 100000.0
x = np.random.rand(100)
y = np.random.rand(100)/large

ax.scatter(x,y)

# Set the y limits appropriately
ax.set_ylim(0, 1/large)

# Change the y ticklabel format to scientific format
ax.ticklabel_format(axis='y', style='sci', scilimits=(-2, 2))

#print(ax.yaxis.offsetText.get_position())
ax.yaxis.offsetText.set_visible(False)
ax.text(-0.21, 1.01/large, r'$\mathregular{10^{-2}}$')

# And show the figure
plt.show()

我知道这是不理想的,但可能是偏移文本不能手动更改或只能与数值一致。。。

似乎plt.ticklabel_format无法正常工作。但是,如果您自己定义ScalarFormatter并将科学符号的限制设置为formatter,则可以自动以mathtext格式获得偏移量,如下所示:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker

x = np.linspace(3,5)
y = np.sin(np.linspace(0,6*np.pi))*1e5

plt.plot(x,y)

mf = matplotlib.ticker.ScalarFormatter(useMathText=True)
mf.set_powerlimits((-2,2))
plt.gca().yaxis.set_major_formatter(mf)

plt.show()

enter image description here

相关问题 更多 >