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

R语言ggplot2 coord_polar双层环形图仅移动外环标签至外侧方法

问题说明

目前仅检索到单层饼图场景下的同类问题解决方案,基于ggplot2的coord_polar极坐标转换绘制双层环形图时,存在外环标签适配差、显示拥挤的问题,效果如下:
双层环形图标签拥挤示例
需求:

  • 保留内环标签原有显示位置不变
  • 仅将外环(第二层环)的标签移动到图表外侧,优先保证显示空间不足、无法正常展示的外环标签移至外侧
当前绘图代码
ggplot(usage.may, aes(x = Level, y = Percent, fill = Subcategory, label = Label)) +
  geom_bar(stat = "identity", color='white', show.legend = FALSE) +
  geom_text(aes(label = paste0(Label, "\n", Value, " (", Per_label, ")")),
            size = 2.5, 
            colour = "white", 
            check_overlap = TRUE, 
            position = position_stack(vjust = 0.5)) +
    coord_polar('y')  +
    scale_fill_manual(values = c("C01" = "#404688FF", 
                                 "C011" = "#3B528BFF","C012" = "#3B528BFF","C013" = "#3B528BFF","C014" = "#3B528BFF",
                                 "C02" = "#287C8EFF",
                                 "C021" = "#287C8EFF",
                                 "C03" = "#27AD81FF",
                                 "C031" = "#35B779FF","C032" = "#35B779FF","C033" = "#35B779FF",
                                 "C04" = "#8FD744FF",
                                 "C041" = "#8FD744FF","C042" = "#8FD744FF")) +
  labs(title = "Electricity Usage May 2022") + ylab("") + xlab("") +
    theme(panel.grid.major = element_blank(),
          panel.grid.minor = element_blank(),
          plot.title = element_text(hjust = 0.5),
          panel.border = element_blank(),
          panel.background = element_blank(),
          strip.background = element_blank(),
          axis.text= element_blank(),
          axis.ticks= element_blank())
可复现示例数据集
usage.may <- structure(list(Level = structure(c(2L, 3L, 3L, 3L, 3L, 2L, 3L, 
2L, 3L, 3L, 3L, 2L, 3L, 3L, 1L), levels = c("0", "1", "2"), class = "factor"), 
    Category = structure(c(2L, 2L, 2L, 2L, 2L, 3L, 3L, 4L, 4L, 
    4L, 4L, 5L, 5L, 5L, 1L), levels = c("C00", "C01", "C02", 
    "C03", "C04"), class = "factor"), Subcategory = structure(c(2L, 
    3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 
    1L), levels = c("C00", "C01", "C011", "C012", "C013", "C014", 
    "C02", "C021", "C03", "C031", "C032", "C033", "C04", "C041", 
    "C042"), class = "factor"), Colour = structure(c(2L, 3L, 
    3L, 3L, 3L, 4L, 5L, 6L, 7L, 7L, 7L, 8L, 9L, 9L, 1L), levels = c("0", 
    "1", "2", "3", "4", "5", "6", "7", "8"), class = "factor"), 
    Label = c("Cafe (R1 & R2)  ", "Non-checked ", "Spider Monkey  ", 
    "Signing-in Cabin", "Solar (cafe)", "Vet Room", "Non-checked", 
    "Butchery", "Non-checked", "Solar (lynx)", "Solar (butchery)", 
    "Tiger Block", "Farm", "Non-checked", ""), Value = c(5323L, 
    921L, 2611L, 34L, 1791L, 534L, 534L, 8479L, 6689L, 1371L, 
    419L, 3596L, 87L, 3247L, 0L), Percent = c(30L, 5L, 15L, 0L, 
    10L, 3L, 3L, 47L, 37L, 8L, 2L, 20L, 2L, 18L, 0L), Per_label = c("30%", 
    "5%", "15%", "0%", "10%", "3%", "3%", "47%", "37%", "8%", 
    "2%", "20%", "2%", "18%", "0%")), row.names = c(NA, -15L), class = "data.frame")
实现方案

核心修改逻辑是拆分内外环的文本图层,不再用同一个geom_text统一设置位置:

  • 内环(Level=1)文本保持原有参数,放在环内部居中位置
  • 外环(Level=2)单独设置文本层,将x轴位置偏移到环形外侧,自动计算每个扇区的中点位置和文本旋转角度,保证文字正向可读,避免拥挤

修改后可直接运行的完整代码:

library(ggplot2)
library(dplyr)

# 提前计算外环每个扇区的累计位置中点,用于标签对齐
outer_label_pos <- usage.may %>%
  filter(Level == 2) %>%
  arrange(desc(Subcategory)) %>%
  mutate(
    cum_y = cumsum(Percent),
    y_pos = cum_y - Percent/2
  )

ggplot(usage.may, aes(x = Level, y = Percent, fill = Subcategory)) +
  geom_bar(stat = "identity", color='white', show.legend = FALSE) +
  # 内环标签:保持原有内部显示逻辑
  geom_text(data = . %>% filter(Level == 1),
            aes(label = paste0(Label, "\n", Value, " (", Per_label, ")")),
            size = 2.5, 
            colour = "white", 
            position = position_stack(vjust = 0.5)) +
  # 外环标签:移到环外侧,自动调整角度
  geom_text(data = outer_label_pos,
            aes(x = 2.4, y = y_pos, 
                label = paste0(Label, "\n", Value, " (", Per_label, ")"),
                angle = 90 - 360*(y_pos/100)),
            size = 2.5,
            hjust = 0.5,
            colour = "black") +
  coord_polar('y')  +
  # 扩展x轴范围,给外侧标签留出显示空间
  scale_x_discrete(expand = c(0, 0.6)) +
  scale_fill_manual(values = c("C01" = "#404688FF", 
                               "C011" = "#3B528BFF","C012" = "#3B528BFF","C013" = "#3B528BFF","C014" = "#3B528BFF",
                               "C02" = "#287C8EFF",
                               "C021" = "#287C8EFF",
                               "C03" = "#27AD81FF",
                               "C031" = "#35B779FF","C032" = "#35B779FF","C033" = "#35B779FF",
                               "C04" = "#8FD744FF",
                               "C041" = "#8FD744FF","C042" = "#8FD744FF")) +
  labs(title = "Electricity Usage May 2022") + ylab("") + xlab("") +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.title = element_text(hjust = 0.5),
        panel.border = element_blank(),
        panel.background = element_blank(),
        strip.background = element_blank(),
        axis.text= element_blank(),
        axis.ticks= element_blank())

参数调整说明:

  • 修改外环geom_text中x=2.4的数值可以调整外环标签和环形的距离,数值越大距离越远
  • 如果存在占比极小的标签仍然重叠,可以把check_overlap = TRUE加到外环的geom_text参数中自动隐藏重叠标签,也可以用ggrepel包的geom_text_repel替换外环文本层,自动添加引导线避免重叠
  • scale_x_discrete(expand = c(0, 0.6))用于扩展x轴边界,避免外侧标签被画布边缘截断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 21:01:59