ggplot2对象的动态位置(特别是geom_text)?

18
使用ArcGIS制作地图时,默认情况下,该软件会使用专有算法自动推动点和多边形标签以避免重叠。他们称之为动态标注。对于点来说,ggplot2具有position_jitter非常好用(因为动态标注可能会产生系统偏差),但是对于使用geom_text的标签来说,则不太好用。
以下是一些抖动问题示例,动态标注算法可以解决这些问题:
library(ggplot2)
ggplot( mtcars,aes( x=wt, y=mpg, label=rownames(mtcars) ) ) +
  geom_point() +
  geom_text( position=position_jitter(h=1,w=1) )

jittered labels with problems noted

ggplot2中是否已经存在这样的动态标记功能?

如果没有,有哪些算法可以实现,并且在R中是否可以实现position_dynamic

4个回答

12

请查看新的软件包ggrepel。ggrepel为ggplot2提供geoms,用于排除重叠的文本标签。它适用于geom_text和geom_label。

enter image description here

该图来自这篇博客文章


9

我在处理几个绘图时遇到了类似的问题,并编写了一个基本程序包,该程序使用力场模拟来调整对象位置。虽然可以进行很多改进,包括与ggplot集成等,但似乎已经完成了任务。以下是其功能的示例:

install.packages("FField", type = "source")
install.packages("ggplot2")
install.packages("gridExtra")
library(FField)
FFieldPtRepDemo()

1
我真的很想编辑你的帖子并为你实现基于此的软件包而给你认可,但我在CRAN中还没有找到它(无论是通过R 2.15.2中的install.packages还是在CRAN网页上)。你刚刚发布了吗(如果是这种情况,我会等一两天)?感谢您编写此软件包! - Ari B. Friedman
1
“FField”软件包不可用(适用于R版本3.0.1)。这个软件包是否公开可用? - Simon MᶜKenzie
3
确实存在一些CRAN提交问题,我对早期软件包的可用性感到困惑。现在它以源代码形式提供(http://cran.r-project.org/web/packages/FField/index.html)标签排斥演示的顺序:install.packages("FField", type = "source") library(FField) install.packages("ggplot2") install.packages("gridExtra") FFieldPtRepDemo()代码相当自说明:FFieldPtRepDemo目前还没有针对各种领域和点分布的智能启发式方法,因为我希望尽快为大家提供有用的东西。 - gregk
1
现在似乎已经在CRAN上可以使用了,而且真是太棒了。我感觉这里面有一些强大的功能,但我需要花点时间阅读文档,才能完全理解它 :) - DaveRGP

8
据我所知,目前最好的是 directlabels,可以从 R-forgeCRAN 获取,并且有一个全面的示例页面
这似乎是一个很好的起点,但在我看来具有以下负面方面:
  • 与分离数据和演示的 ggplot 哲学不同,directlabels 返回 ggplot 对象而不是 geom
  • 它只适用于 group 美学,而不是单个点
我之前曾经浏览过源代码,我认为应该很容易修改代码以解决我提到的两个问题。
这个SO问题中有一个如何在 ggplot 中使用它的例子。

7
这不是直接在ggplot2中使用的内容,但是vegan包中的ordipointlabel()函数试图实现类似功能。它将数据显示为点,并尝试使用优化算法将每个点标记为适当的标签,使标签位于其点旁边,但不重叠其他标签和点。 ?ordipointlabel提到它基于maptools包中的pointlabel(),这可能是另一个寻找灵感的地方。

无论是在R还是ggplot中,没有什么是不可能的,但我同意目前ggplot的状态并不是最佳的。 - Andrie
1
Hmisc 包中的 labcurve 也可以做类似的事情,但它有更多自己的相关基础设施(即从中挖掘出来以在 ggplot 中使用会更加困难)。 - Ben Bolker
1
@Andrie,也许措辞不当。我的意思是我的回答与ggplot2没有直接关系。可以通过调整我提到的函数中的代码来查找标签的坐标,并在标准的geom_text()调用中使用它们。 - Gavin Simpson
我认为pointlabel()使用模拟退火算法。尝试基于最小化能量的算法来开始标签并根据重叠情况“排斥”它们将是非常巧妙的(但绝不是微不足道的)事情。 - Ben Bolker
@Ben 是的,它确实有用。Jari在ordipointlabel()函数上进行了建模,并且他也使用SANN。 - Gavin Simpson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接