目前,如果我将matplotlib 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}}$')
您可以找到代码和输出图here。
有两个奇怪的地方:一个是我不能覆盖y轴顶部的1e-5(这是目标),另一个是我必须按顺序运行plt.tight_layout()
甚至将unicode值视为偏移量。
谁能告诉我哪里出错了?
谢谢
编辑:原始问题没有明确表示我想自动检测当前由ticklabel_format
计算的指数。因此,不应将设置字符串传递给偏移文本,而应自动检测该值并相应地调整乳胶字符串。
答案 0 :(得分: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_pos
和y_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()
有一个显示代码输出的ipython笔记本的要点here。
我希望有所帮助!
答案 1 :(得分:2)
你得到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()
我知道这不太理想,但可能是偏移文字无法手动更改或只能与数值一致...
答案 2 :(得分:2)
似乎plt.ticklabel_format
无效。但是,如果您自己定义ScalarFormatter 和将科学记数法的限制设置为格式化程序,则可以使用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()
答案 3 :(得分:0)
在代码中添加两行
import matplotlib.ticker as ptick
ax.yaxis.set_major_formatter(ptick.ScalarFormatter(useMathText=True))
答案 4 :(得分:0)
在@KirstieJane's solution的基础上,我发现了一种更好的方法,它也不需要调用tight_layout
也可以工作,尤其是对于使用constrained_layout
的图形也可以工作。设置文本仅需调用ax.get_tightbbox(renderer)
。这是MWE:
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.tight_layout import get_renderer
from matplotlib.backends.backend_qt5agg import \
FigureCanvasQTAgg as FigureCanvas
# from matplotlib.transforms import Bbox
# from mpl_toolkits.axes_grid1 import make_axes_locatable
from PyQt5.QtWidgets import QDialog, QApplication, QGridLayout
class MainWindow(QDialog):
def __init__(self):
super().__init__()
fig, ax = plt.subplots(constrained_layout=True)
canvas = FigureCanvas(fig)
lay = QGridLayout(self)
lay.addWidget(canvas)
self.setLayout(lay)
image = np.random.uniform(10000000, 100000000, (100, 100))
image_artist = ax.imshow(image)
colorbar = fig.colorbar(image_artist)
colorbar.ax.ticklabel_format()
renderer = get_renderer(fig)
colorbar.ax.get_tightbbox(renderer)
colorbar.ax.yaxis.offsetText.set_visible(False)
offset_text = colorbar.ax.yaxis.get_offset_text()
exp = offset_text.get_text().split('e')[1].replace('+', '')
colorbar.ax.set_ylabel(rf'Parameter [U${{\times}}10^{{{exp}}}$]')
canvas.draw_idle()
if __name__ == '__main__':
app = QApplication(sys.argv)
GUI = MainWindow()
GUI.show()
sys.exit(app.exec_())
有关该解决方案的详细讨论,请参见我的回答here。