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)
当前效果

问题
- 标签未处于各扇区中心,即使设置了
hjust=0.5 - 若将数值与百分比标签都放在扇区中心,即便使用
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
相关产品推荐
相关产品推荐

