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

ggplot绘制饼图:如何实现标签始终居中且无重叠?

饼图标签位置偏差与重叠问题解决

数据与绘图代码

数据定义

type <- c("open", "done") 
value <- c(12889, 86383) 
share <- c(0.13, 0.87) 
data <- data.frame(type,value,share) 
rownames(data) <- c("OpenValue", "DoneValue")

饼图绘制代码

ggplot(data, aes(x = "", y = value)) + 
  geom_bar(stat="identity", aes(fill = type)) +
  coord_polar("y") + 
  theme_void() + 
  geom_text(aes(label= value), vjust = 1, hjust = 0.5, check_overlap = TRUE, color = "black", size = 3) + 
  scale_fill_manual(values = c("#0099f9", "lightskyblue1")) + 
   theme(plot.title = element_text(hjust = 0.5, size = 12, vjust = -8), 
        plot.caption = element_text(hjust = 0), 
        legend.position = "bottom") + 
  geom_label(aes(label = paste0(round(share, 2) * 100, "% of total")), 
             position = position_stack(vjust = 0.75), size = 3)

当前效果

饼图当前显示效果

问题

  1. 标签未处于各扇区中心,即使设置了hjust=0.5
  2. 若将数值与百分比标签都放在扇区中心,即便使用check_overlap=TRUE仍会出现重叠

问题根源

  • 用geom_bar+coord_polar实现饼图时,笛卡尔坐标系的hjust/vjust参数无法适配极坐标的位置逻辑,直接设置会导致定位偏差。
  • position_stack(vjust=0.75)是固定比例偏移,不是基于扇区中心的动态计算,小扇区的标签位置会严重偏离。
  • check_overlap=TRUE仅在笛卡尔坐标系下能稳定生效,极坐标下无法智能识别并避让小扇区的标签重叠。

解决方案

方案1:精准定位中心+合并标签避免重叠

通过position_stack(vjust=0.5)自动计算扇区中心,同时将数值与百分比合并为换行标签,从根源避免重叠:

library(ggplot2)

ggplot(data, aes(x = "", y = value, fill = type)) + 
  geom_bar(stat="identity") +
  coord_polar("y") + 
  theme_void() + 
  # 合并数值与百分比为换行标签,定位到扇区中心
  geom_text(aes(label = paste0(value, "\n", round(share*100), "% of total")),
            position = position_stack(vjust = 0.5),
            color = "black", size = 3) + 
  scale_fill_manual(values = c("#0099f9", "lightskyblue1")) + 
  theme(plot.title = element_text(hjust = 0.5, size = 12, vjust = -8), 
        plot.caption = element_text(hjust = 0), 
        legend.position = "bottom")

方案2:用ggrepel实现智能避让(多类别场景更适用)

如果饼图类别较多、小扇区密集,使用ggrepel包的geom_text_repel自动调整标签位置,彻底解决重叠问题:

library(ggplot2)
library(ggrepel)

# 提前计算每个扇区的中心位置
data$y_pos <- cumsum(data$value) - 0.5*data$value

ggplot(data, aes(x = "", y = value, fill = type)) + 
  geom_bar(stat="identity") +
  coord_polar("y") + 
  theme_void() + 
  geom_text_repel(aes(y = y_pos, label = paste0(value, "\n", round(share*100), "% of total")),
                  nudge_x = 0.3, # 向外偏移避免被图形遮挡
                  color = "black", size = 3) + 
  scale_fill_manual(values = c("#0099f9", "lightskyblue1")) + 
  theme(plot.title = element_text(hjust = 0.5, size = 12, vjust = -8), 
        plot.caption = element_text(hjust = 0), 
        legend.position = "bottom")

核心要点

  • position_stack(vjust=0.5)是极坐标饼图中定位扇区中心的标准方式,能适配任意大小的扇区。
  • 合并标签为换行形式,比分开两个独立标签更节省空间,从根本减少重叠概率。
  • ggrepel的智能避让逻辑能自动识别拥挤区域,调整标签位置,适合复杂的多类别饼图场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:22:43