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

如何在geom_line末端错开显示geom_flag以避免国旗重叠?

解决geom_line终点国旗重叠的方法

针对大数据集中国旗重叠难以分辨的问题,这里提供几个实用的解决方案:

方法1:给国旗的Y轴位置添加偏移量

通过对每个国家终点的Y值添加微小偏移,让国旗在垂直方向上错开。可以根据终点Y值的排序分配偏移量,保证高低不同的点偏移后不会重叠:

library(tidyverse)
library(ggflags)
set.seed(123)
data <- data.frame(iso2c = c("BT", "IN", "LK", "NP",
                             "BT", "IN", "LK", "NP"),
                   Year = c(2010, 2010, 2010, 2010, 2011, 2011, 2011, 2011),
                   degree_norm = runif(8))

data %>%
  mutate(Year = factor(Year),
         iso2c = tolower(iso2c)) %>% 
  # 按年份分组,对每个年份的Y值排名,用于计算偏移
  group_by(Year) %>%
  mutate(y_rank = rank(degree_norm)) %>%
  ungroup() %>%
  group_by(iso2c) %>%
  mutate(country_x = max(levels(Year)),
         # 根据排名添加偏移,0.02是可调整的偏移幅度
         country_y = degree_norm[country_x == Year] + (y_rank[country_x == Year] * 0.02)) %>%
  ggplot(aes(x = Year,
             y = degree_norm,
             color = iso2c,
             group = iso2c)) +
  geom_line(aes(linetype = iso2c), size = 1.25) +
  geom_flag(aes(x = country_x,
                y = country_y, 
                country = iso2c)) +
  scale_y_continuous(labels = scales::comma,
                     # 扩展Y轴上限,避免偏移后的国旗超出画布
                     expand = expansion(mult = c(0, 0.1))) +
  theme_grey() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        legend.key = element_blank()) +
  scale_color_discrete(breaks  = c("bt", "in", "lk", "np"), 
                       labels = c("Bhutan", "India", "Sri Lanka","Nepal"),
                       name="Country") + 
  scale_linetype_discrete(breaks  = c("bt", "in", "lk", "np"), 
                          labels = c("Bhutan", "India", "Sri Lanka","Nepal"),
                          name="Country") +
  theme(legend.key.width=unit(3,"line")) +
  labs(x = "Year", 
       y = "Normalised Degree Centrality",
       country = "Country", 
       color   = "Country"
  ) 

方法2:将国旗移至X轴外侧(最后一年右侧)

把所有国旗放在最后一个年份的右侧,横向排列,彻底避免垂直方向的重叠:

library(tidyverse)
library(ggflags)
set.seed(123)
data <- data.frame(iso2c = c("BT", "IN", "LK", "NP",
                             "BT", "IN", "LK", "NP"),
                   Year = c(2010, 2010, 2010, 2010, 2011, 2011, 2011, 2011),
                   degree_norm = runif(8))

data %>%
  mutate(Year = factor(Year),
         iso2c = tolower(iso2c)) %>% 
  group_by(iso2c) %>%
  mutate(country_x = max(levels(Year)),
         country_y = degree_norm[country_x == Year]) %>%
  ggplot(aes(x = Year,
             y = degree_norm,
             color = iso2c,
             group = iso2c)) +
  geom_line(aes(linetype = iso2c), size = 1.25) +
  # 将国旗X位置设为最后一年的数值+0.1(因子转数值)
  geom_flag(aes(x = as.numeric(country_x) + 0.1,
                y = country_y, 
                country = iso2c)) +
  scale_y_continuous(labels = scales::comma) +
  # 扩展X轴范围,让外侧的国旗显示完整
  scale_x_discrete(expand = expansion(add = 0.5)) +
  theme_grey() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        legend.key = element_blank()) +
  scale_color_discrete(breaks  = c("bt", "in", "lk", "np"), 
                       labels = c("Bhutan", "India", "Sri Lanka","Nepal"),
                       name="Country") + 
  scale_linetype_discrete(breaks  = c("bt", "in", "lk", "np"), 
                          labels = c("Bhutan", "India", "Sri Lanka","Nepal"),
                          name="Country") +
  theme(legend.key.width=unit(3,"line")) +
  labs(x = "Year", 
       y = "Normalised Degree Centrality",
       country = "Country", 
       color   = "Country"
  ) 

方法3:结合ggrepel实现自动避障(进阶)

如果前两种方法仍有重叠,可以借助ggrepel包的自动避障逻辑。由于geom_flag不支持直接repel,我们可以先计算国旗的目标位置,再用ggrepel的函数调整坐标:

library(tidyverse)
library(ggflags)
library(ggrepel)
set.seed(123)
data <- data.frame(iso2c = c("BT", "IN", "LK", "NP",
                             "BT", "IN", "LK", "NP"),
                   Year = c(2010, 2010, 2010, 2010, 2011, 2011, 2011, 2011),
                   degree_norm = runif(8))

# 提取终点数据
end_points <- data %>%
  mutate(Year = factor(Year),
         iso2c = tolower(iso2c)) %>% 
  group_by(iso2c) %>%
  filter(Year == max(levels(Year))) %>%
  mutate(x = as.numeric(Year),
         y = degree_norm)

# 用ggrepel计算不重叠的位置
repel_positions <- end_points %>%
  ggrepel:::compute_justifications(
    data = .,
    x = x, y = y,
    direction = "y",
    seed = 123
  ) %>%
  mutate(y_repel = y + (justification_y * 0.05))

# 合并原数据和调整后的位置
plot_data <- data %>%
  mutate(Year = factor(Year),
         iso2c = tolower(iso2c)) %>%
  left_join(repel_positions %>% select(iso2c, y_repel), by = "iso2c")

# 绘图
ggplot(plot_data, aes(x = Year,
                      y = degree_norm,
                      color = iso2c,
                      group = iso2c)) +
  geom_line(aes(linetype = iso2c), size = 1.25) +
  geom_flag(aes(x = max(levels(Year)),
                y = y_repel, 
                country = iso2c)) +
  scale_y_continuous(labels = scales::comma,
                     expand = expansion(mult = c(0, 0.1))) +
  theme_grey() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        legend.key = element_blank()) +
  scale_color_discrete(breaks  = c("bt", "in", "lk", "np"), 
                       labels = c("Bhutan", "India", "Sri Lanka","Nepal"),
                       name="Country") + 
  scale_linetype_discrete(breaks  = c("bt", "in", "lk", "np"), 
                          labels = c("Bhutan", "India", "Sri Lanka","Nepal"),
                          name="Country") +
  theme(legend.key.width=unit(3,"line")) +
  labs(x = "Year", 
       y = "Normalised Degree Centrality",
       country = "Country", 
       color   = "Country"
  ) 

注意事项

  • 偏移幅度(比如方法1中的0.02)可以根据你的数据范围调整,确保国旗既不重叠也不偏离原数据点太远。
  • 方法2中如果年份是连续数值型而非因子,直接用max(Year) + 0.1即可,无需转数值。
  • 方法3需要额外安装ggrepel包,适合数据点极多、手动偏移难以处理的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:03:30