如果我用 matplotlib 制作散点图:
plt.scatter(randn(100),randn(100))
# set x, y lims
plt.xlim([...])
plt.ylim([...])
我想用指向给定点 (x, y)
的箭头和标签来注释它。我知道这可以通过注释来完成,但我希望箭头及其标签以“最佳”方式放置,如果可能的话(给定当前轴比例/限制)箭头和标签不与其他点重叠。例如,如果您想标记异常点。有办法做到这一点吗?它不必是完美的,而只是箭头/标签的智能放置,仅给出要标记的点的 (x,y)
坐标。谢谢。
if I make a scatter plot with matplotlib:
plt.scatter(randn(100),randn(100))
# set x, y lims
plt.xlim([...])
plt.ylim([...])
I'd like to annotate a given point (x, y)
with an arrow pointing to it and a label. I know this can be done with annotate
, but I'd like the arrow and its label to be placed "optimally" in such a way that if it's possible (given the current axis scales/limits) that the arrow and the label do not overlap with the other points. eg if you wanted to label an outlier point. is there a way to do this? it doesn't have to be perfect, but just an intelligent placement of the arrow/label, given only the (x,y)
coordinates of the point to be labeled. thanks.
发布评论
评论(3)
基本上,不,没有。
处理与此类似的地图标签放置的布局引擎非常复杂,超出了 matplotlib 的范围。 (边界框交叉实际上是决定标签放置位置的一种相当糟糕的方法。为只能在 1000 种情况中的一种情况下工作的东西编写大量代码有什么意义?)
除此之外,由于复杂的数量matplotlib 所做的文本渲染(例如 Latex),如果不先完全渲染文本,就不可能确定文本的范围(这相当慢)。
然而,在许多情况下,您会发现在带有注释的标签后面使用透明框是一个合适的解决方法。
例如
Basically, no, there isn't.
Layout engines that handle placing map labels similar to this are surprisingly complex and beyond the scope of matplotlib. (Bounding box intersections are actually a rather poor way of deciding where to place labels. What's the point in writing a ton of code for something that will only work in one case out of 1000?)
Other than that, due to the amount of complex text rendering that matplotlib does (e.g. latex), it's impossible to determine the extent of text without fully rendering it first (which is rather slow).
However, in many cases, you'll find that using a transparent box behind your label placed with annotate is a suitable workaround.
E.g.
使用 adjustText (完全公开,我写的)。
让我们标记前 10 个点。我更改的唯一参数是降低点的排斥力,因为点的数量太多,我们希望算法花费更多时间并更仔细地放置注释。
这并不理想,但这里的点非常密集,有时无法将文本放置在目标附近而不与其中任何一个重叠。但这都是自动的且易于使用,并且不会让标签相互重叠。
聚苯乙烯
它使用边界框交叉点,但我想说相当成功!
Use adjustText (full disclosure, I wrote it).
Let's label the first 10 points. The only parameter I changed was lowering the force of repelling from the points, since there is so many of them and we want the algorithm to take a bit more time and place the annotations more carefully.
It's not ideal, but the points are really dense here and sometimes there is no way to place the text near to its target without overlapping any of them. But it's all automatic and easy to use, and also doesn't let labels overlap each other.
PS
It uses bounding box intersections, but rather successfully I'd say!
另一个使用基于 Phlya 包的示例/latest/Examples.html#Now-a-classical-mtcars-dataset;-example-from-ggrepel-package-for-R" rel="nofollow noreferrer">调整Text_mtcars:
Another example using awesome Phlya's package based on adjustText_mtcars: