如何制作每个分面占比合计为100%的分面饼图?
问题描述
需要为数据集中的两个网络制作分面饼图,展示每个网络中2G、3G、4G类型的使用占比。但当前制作的图表中,所有分面的占比总和为100%,如何实现每个单独分面的占比合计为100%?
数据集来自BigQuery,表ID:bigquery-public-data.catalonian_mobile_coverage_eu.mobile_data_2015_2017,样本数据如下:
+ select(network, net, date) network net date 1 Vodafone 3G 2015-01-05 2 Vodafone 3G 2015-01-05 3 Vodafone 3G 2015-01-05 4 Vodafone 3G 2015-01-05 5 Vodafone 3G 2015-01-05 6 Vodafone 3G 2015-01-05 7 Vodafone 3G 2015-01-05 8 Vodafone 3G 2015-01-05 9 Vodafone 3G 2015-01-05 10 Vodafone 3G 2015-01-05
当前使用的代码:
bigfi %>% drop_na(net) %>% filter(grepl("2015", date), net != "") %>% ggplot(aes(x="", fill = net)) + geom_bar(position="fill", color = "white") + facet_wrap(~network) + coord_polar(theta="y", start = 0) + theme_void() + geom_text(aes(label = after_stat( percent(ave(count, x, FUN = function(x) x / sum(x))))), stat="count", position = "fill", color = "white", size=4) + labs(title = "Net Type Usage 2015") + theme(plot.title = element_text(hjust = 0.5, face = "bold", size=4))
解决方案
方法1:在ggplot中调整统计计算
问题出在ave(count, x, ...)只按x(空字符串)分组计算占比,导致全局汇总。需要把network加入分组变量,让占比按每个分面单独计算:
bigfi %>% drop_na(net) %>% filter(grepl("2015", date), net != "") %>% ggplot(aes(x="", fill = net)) + geom_bar(position="fill", color = "white") + facet_wrap(~network) + coord_polar(theta="y", start = 0) + theme_void() + # 修改ave的分组变量,加入network实现分面内单独计算占比 geom_text(aes(label = after_stat( percent(ave(count, x, network, FUN = function(x) x / sum(x))))), stat="count", position = position_fill(vjust = 0.5), color = "white", size=4) + labs(title = "Net Type Usage 2015") + theme(plot.title = element_text(hjust = 0.5, face = "bold", size=14)) # 修正原标题字号过小问题
方法2:先预处理数据(推荐,逻辑更清晰)
提前用dplyr计算每个network下各net的占比,把数据整理成适合绘图的格式,避免在ggplot中嵌套复杂计算:
library(dplyr) library(ggplot2) library(scales) # 预处理数据:按network分组计算各net的占比 summary_data <- bigfi %>% drop_na(net) %>% filter(grepl("2015", date), net != "") %>% count(network, net) %>% group_by(network) %>% mutate(percent = n / sum(n), label = percent(percent)) %>% ungroup() # 绘制分面饼图 ggplot(summary_data, aes(x="", y=percent, fill=net)) + geom_bar(stat="identity", position="fill", color="white") + geom_text(aes(label=label), position=position_fill(vjust=0.5), color="white", size=4) + facet_wrap(~network) + coord_polar(theta="y", start=0) + theme_void() + labs(title="Net Type Usage 2015") + theme(plot.title = element_text(hjust=0.5, face="bold", size=14))
说明
- 方法1通过在
ave函数中加入network分组变量,让统计计算限定在每个分面内部,确保每个network的饼图占比总和为100%。 - 方法2提前整理数据,把占比计算逻辑从绘图代码中分离,更直观易懂,也方便后续调试修改。
- 修正了原代码中标题字号
size=4的问题,该字号过小几乎无法识别,调整为size=14。
内容的提问来源于stack exchange,提问作者buuuuub
相关产品推荐
相关产品推荐

