ggrepel 如何让标签避开 ggplot2 多图层中的点和标签?
数据小许
结论
geom_text_repel() 只使用当前图层的数据计算避让。其他 geom_point() 或 geom_label() 图层不会自动参与碰撞计算。因此,把 site_scores、sp_scores 和质心分别放在其他图层中绘制,无法让物种标签自动避开这些点和标签。
可以将需要参与避让的点位和标签合并到同一份数据中。需要显示的物种保留标签文本,其他物种得分和站点得分的 label 设为空字符串 ""。ggrepel 会隐藏空标签,但这些数据点仍会参与非空标签的避让计算。geom_text_repel() 文档示例和示例说明展示了这种用法。
合并避让数据
下面假设 sp_scores2 是从 sp_scores 中挑出的、需要显示标签的物种,且两张表可以通过 species 对应。centroids_tree 按题目提供的 dput() 使用 group 列作为标签;如果实际列名是 tree_species,请相应替换。
library(dplyr)
library(ggrepel)
# 所有物种得分都参与避让;只为 sp_scores2 中的物种显示标签
species_repel <- sp_scores |>
select(CCA1, CCA2, species) |>
left_join(
sp_scores2 |> select(species, label),
by = "species"
) |>
mutate(label = coalesce(label, "")) |>
select(CCA1, CCA2, label)
# 站点点位参与避让,但不显示文字
sites_repel <- site_scores |>
transmute(CCA1, CCA2, label = "")
# 若物种标签也要避开质心标签,把质心文字放进同一个 repel 图层
centroids_repel <- centroids_tree |>
transmute(CCA1, CCA2, label = group)
repel_data <- bind_rows(
species_repel,
sites_repel,
centroids_repel
)
将原来的独立 geom_text_repel() 和 geom_label() 合并为一个使用这份数据的 repel 图层:
ggplot() +
geom_point(
data = site_scores,
aes(x = CCA1, y = CCA2, colour = tree_species),
size = 6,
alpha = 0.8
) +
geom_point(
data = sp_scores,
aes(x = CCA1, y = CCA2),
shape = 15,
size = 6,
alpha = 0.8
) +
geom_text_repel(
data = repel_data,
aes(x = CCA1, y = CCA2, label = label),
inherit.aes = FALSE,
size = 5,
fontface = "bold",
box.padding = 0.25,
point.padding = 0.4,
force = 1,
max.overlaps = Inf
)
这样,站点和物种得分会参与点位避让,物种标签与质心文字也会在同一层内互相避让。示例使用 geom_text_repel() 绘制质心文字,因此不会保留原先 geom_label() 的标签框效果。若要保留标签框,可以把合并数据用于 geom_label_repel();它会为所有非空标签绘制框。
注意事项
- 空标签应设为
""。如果设为NA,数据可能会被当作缺失值移除,无法让这些点参与避让。 max.overlaps = Inf可以避免标签因重叠过多而被丢弃,但不能保证所有标签都完全避开点或其他标签。空间不足时,标签仍可能重叠。point.padding控制标签与对应点之间的间距,box.padding控制标签之间的间距。可根据图形尺寸调整,并检查不同输出尺寸下的效果。- 题目中的
dput(centroids_tree)显示列名是group,示例绘图代码使用的则是tree_species。请确认实际数据列名一致,否则aes(label = tree_species)会找不到对应列。
备注:内容仅供参考。
