将文本框固定在角落并正确对齐

7 投票
1 回答
9317 浏览
提问于 2025-04-20 22:30

我正在尝试模仿 matplotlib.pyplot 中的 legend 方法,想要使用 loc='lower right' 来固定并正确对齐图例框的位置,无论坐标轴和框内的内容是什么。

使用 text 方法不行,因为这需要手动输入坐标,我想要的是自动化的解决方案。

我尝试过使用 annotate,这让我走了一半的路,但还是不太对劲。

这是我目前的代码:

import matplotlib.pyplot as plt

# Define some names and variables to go in the text box.
xn, yn, cod = 'r', 'p', 'abc'
prec = 2
ccl = [546.35642, 6785.35416]
ect = [12.5235, 13.643241]

fig = plt.figure()
ax = fig.add_subplot(111)
plt.xlim(-1., 10.)
plt.ylim(-1., 1.)

# Generate text to write.
text1 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(xn, ccl[0],
    ect[0], c=cod, p=prec)
text2 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(yn, ccl[1],
    ect[1], c=cod, p=prec)
text = text1 + '\n' + text2

ax.annotate(text, xy=(0.75, 0.9), xycoords='axes fraction', fontsize=10,
    bbox=dict(facecolor='white', alpha=0.8),
    horizontalalignment='left', verticalalignment='bottom')

plt.savefig('annotate_test.png', dpi=150)

运行结果是:

enter image description here

这个方法在坐标轴范围变化时能够正确缩放,但问题是:1- 如果坐标轴设置为 ax.set_aspect('equal'),它就会出错:

enter image description here

还有2- 如果文本太长(在上面的简单示例中我设置了 prec=5),它也会出错:

enter image description here

我该如何告诉 matplotlib 始终将文本框放在右上角并正确对齐,以确保它不会超出图像范围(也就是 legendloc 的作用)?

1 个回答

14

一种简单粗暴的方法是使用右对齐和顶部对齐的文本,并将其放置在离坐标轴角落固定的点数偏移位置:

import matplotlib.pyplot as plt

# Define some names and variables to go in the text box.
xn, yn, cod = 'r', 'p', 'abc'
prec = 2
ccl = [546.35642, 6785.35416]
ect = [12.5235, 13.643241]

fig = plt.figure()
ax = fig.add_subplot(111)
ax.axis([-1, 10, -1, 1])

# Generate text to write.
text1 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(xn, ccl[0],
    ect[0], c=cod, p=prec)
text2 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(yn, ccl[1],
    ect[1], c=cod, p=prec)
text = text1 + '\n' + text2

ax.annotate(text, xy=(1, 1), xytext=(-15, -15), fontsize=10,
    xycoords='axes fraction', textcoords='offset points',
    bbox=dict(facecolor='white', alpha=0.8),
    horizontalalignment='right', verticalalignment='top')

plt.show()

enter image description here

因为我们指定了顶部和右侧对齐,所以它能很好地处理你的两个边缘情况:

enter image description here

enter image description here


不过,这样的缺点是文本是右对齐的。理想情况下,你希望文本的对齐方式和框的对齐方式是分开的。matplotlib.offsetbox模块有很多方法可以处理这种情况。

如果你想模仿一个图例框(包括位置代码),可以看看matplotlib.offsetbox.AnchoredText。注意,你可以通过padborderpad这些参数来调整内边距等设置:http://matplotlib.org/api/offsetbox_api.html#matplotlib.offsetbox.AnchoredOffsetbox

import matplotlib.pyplot as plt
import matplotlib.offsetbox as offsetbox

# Define some names and variables to go in the text box.
xn, yn, cod = 'r', 'p', 'abc'
prec = 5
ccl = [546.35642, 6785.35416]
ect = [12.5235, 13.643241]

fig = plt.figure()
ax = fig.add_subplot(111)
ax.axis([-1, 10, -1, 1])

# Generate text to write.
text1 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(xn, ccl[0],
    ect[0], c=cod, p=prec)
text2 = "${}_{{t}} = {:.{p}f} \pm {:.{p}f}\; {c}$".format(yn, ccl[1],
    ect[1], c=cod, p=prec)
text = text1 + '\n' + text2

ob = offsetbox.AnchoredText(text, loc=1)
ax.add_artist(ob)

plt.show()

enter image description here

这种方法的一个缺点是,调整字体和框的参数有点不太直观。AnchoredText接受一个字体参数的字典作为prop参数。框可以在初始化后通过patch属性进行调整。举个简单的例子:

ob = offsetbox.AnchoredText(text, loc=1,
                    prop=dict(color='white', size=20))
ob.patch.set(boxstyle='round', color='blue', alpha=0.5)
ax.add_artist(ob)

enter image description here

撰写回答