You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ggrepel在ggtern三元图中失效,求替代标签避让方案

解决方案:三元图标签避让的替代方法

针对你在Shiny应用中使用ggtern绘制三元图时,geom_text_repel标签消失、geom_label_repel不兼容的问题,提供两种可行方案:

方案一:手动微调标签位置(适合少量重叠点)

如果重叠点数量不多,直接给标签对应的三元坐标添加微小偏移即可让标签自然分开,这种方法简单直接,适合Shiny中动态点数量较少的场景:

require(ggplot2)
require(ggtern)
require(dplyr)

# 原始数据处理
USDA.LAB <- USDA %>%  
  dplyr::group_by(Label) %>%  
  dplyr::summarise(
    Clay = mean(Clay),
    Sand = mean(Sand),
    Silt = mean(Silt)
  )

USDA.LAB$Angle = 0 
USDA.LAB$Angle[which(USDA.LAB$Label == 'Loamy Sand')] = -35

# 给重叠点添加坐标偏移
df <- data.frame(
  HORIZON = c("A", "B"), 
  Sand = c(5, 5), 
  Silt = c(5, 5), 
  Clay = c(80, 80)
) %>% 
  # 给两个点的Sand和Silt分别加减偏移量,避免标签重叠
  mutate(
    Sand = Sand + c(2, -2),
    Silt = Silt + c(2, -2)
  )

# 绘制三元图
base <-  ggplot(data = USDA, aes(y=Clay, x=Sand, z=Silt)) +
  coord_tern(L="x",T="y",R="z") +
  geom_polygon(alpha = 0.75, size = 0.5, color = 'black',
               aes(color=Label, fill=Label)) +
  geom_text(data = USDA.LAB,
            aes(label = Label, angle = Angle),
            color = 'black',
            size = 3.5) +
  theme_rgbw() +
  theme_showsecondary() +
  theme_showarrows() +
  custom_percent("Percent") +
  theme(legend.justification = c(0, 1),
        legend.position      = c(0, 1),
        axis.tern.padding    = unit(0.15, 'npc')) +
  labs(title = 'USDA Textural Classification Chart',
       fill  = 'Textural Class',
       color = 'Textural Class') +  
  geom_point(data=df, size=3) + 
  # 使用偏移后的坐标绘制标签
  geom_text(data=df, aes(label = HORIZON), size=4)

base

方案二:结合ggrepel坐标计算与三元坐标转换(适合多重叠点)

如果需要智能避让大量重叠点,可以利用ggrepel的底层计算函数,先将三元坐标转换为笛卡尔坐标计算避让位置,再转回三元坐标:

require(ggplot2)
require(ggtern)
require(dplyr)
require(ggrepel)

# 原始数据处理
USDA.LAB <- USDA %>%  
  dplyr::group_by(Label) %>%  
  dplyr::summarise(
    Clay = mean(Clay),
    Sand = mean(Sand),
    Silt = mean(Silt)
  )

USDA.LAB$Angle = 0 
USDA.LAB$Angle[which(USDA.LAB$Label == 'Loamy Sand')] = -35

df <- data.frame(
  HORIZON = c("A", "B"), 
  Sand = c(5, 5), 
  Silt = c(5, 5), 
  Clay = c(80, 80)
)

# 1. 将三元坐标转换为笛卡尔坐标
cart_coords <- tern2cart(
  x = df$Sand, y = df$Clay, z = df$Silt,
  L="x", T="y", R="z"
)
df_cart <- data.frame(
  x = cart_coords$x, 
  y = cart_coords$y, 
  HORIZON = df$HORIZON
)

# 2. 用ggrepel计算避让后的笛卡尔坐标位置
repel_result <- repel_boxes(
  data = df_cart,
  x = x, y = y,
  labels = HORIZON,
  point.size = 3,
  label.size = 4,
  force = 5  # 调整避让力度,数值越大避让越明显
)

# 3. 将避让后的笛卡尔坐标转回三元坐标
tern_coords <- cart2tern(
  x = repel_result$x, y = repel_result$y,
  L="x", T="y", R="z"
)
df_repel <- df %>% 
  mutate(
    Sand = tern_coords$x,
    Clay = tern_coords$y,
    Silt = tern_coords$z
  )

# 绘制三元图
base <-  ggplot(data = USDA, aes(y=Clay, x=Sand, z=Silt)) +
  coord_tern(L="x",T="y",R="z") +
  geom_polygon(alpha = 0.75, size = 0.5, color = 'black',
               aes(color=Label, fill=Label)) +
  geom_text(data = USDA.LAB,
            aes(label = Label, angle = Angle),
            color = 'black',
            size = 3.5) +
  theme_rgbw() +
  theme_showsecondary() +
  theme_showarrows() +
  custom_percent("Percent") +
  theme(legend.justification = c(0, 1),
        legend.position      = c(0, 1),
        axis.tern.padding    = unit(0.15, 'npc')) +
  labs(title = 'USDA Textural Classification Chart',
       fill  = 'Textural Class',
       color = 'Textural Class') +  
  geom_point(data=df, size=3) + 
  # 使用避让后的三元坐标绘制标签
  geom_text(data=df_repel, aes(label = HORIZON), size=4)

base

注意事项

  • 方案二中的force参数可以调整标签避让的力度,根据实际点的密度调整数值;
  • 确保Shiny应用中加载了所有依赖包:ggplot2、ggtern、dplyr、ggrepel;
  • 如果点落在坐标轴上,可以在坐标转换后额外添加少量偏移,避免标签超出图范围。

内容的提问来源于stack exchange,提问作者Kerry Kuntz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:55:57