绘图中文本框的智能自动定位

Smart automatic positioning of text box in plot

我正在按照 Joe Kington in this answer 给出的方法使用 matplotlib.offsetbox.AnchoredText() 模块将文本框放置在图的一角。

如果我知道要将文本框放置在何处,这将非常有效,但是如果我希望文本框自行定位,以便它 与绘制在同一位置的内容的最小可能部分重叠怎么办?图?

这需要尽可能普遍地工作,所以假设我事先不知道绘制的内容是什么以及它在图中的位置。

我查看了 documentation,但似乎没有可用的 smart 选项。位置代码是:

'upper right'  : 1,
'upper left'   : 2,
'lower left'   : 3,
'lower right'  : 4,
'right'        : 5,
'center left'  : 6,
'center right' : 7,
'lower center' : 8,
'upper center' : 9,
'center'       : 10,

例如,在这种情况下(下面的 MWE):

更好的位置是左上角(或左下角),但由于我通过loc=1手动固定了位置,文本框与绘制的内容重叠。

有什么方法可以检测图中哪里有更多可用的空 space 并将框放在那里?


MWE:

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([0, 5, 0, 1])

import random
pointx = [3. + random.random() for i in xrange(1000)]
pointy = [random.random() for i in xrange(1000)]
plt.scatter(pointx , pointy)

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

3 年多后,解决方案如下:代替 offsetbox,只需使用 plt.legend() 并利用它默认将文本框定位在 "best" 位置的能力.

import matplotlib.pyplot as plt

# 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([0, 5, 0, 1])

import random
pointx = [3. + random.random() for i in xrange(1000)]
pointy = [random.random() for i in xrange(1000)]
plt.scatter(pointx , pointy)

# 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

# Create an empty plot with the required text.
plt.plot([], label=text)
# Remove the handle from the legend box.
plt.legend(handlelength=0)

plt.show()