基于ggplot2实现两种自定义饼图布局的技术问询
分面饼图的两种自定义布局实现
先整理原始数据处理代码(含中文注释):
library(dplyr) library(tidyverse) library(ggplot2) library(gridExtra) # 用于布局拼接(需求1) library(patchwork) # 用于环绕布局(需求2) # 构造并处理数据集 df <- data.frame( Subjects = c("Literature", "Geography", "Physics", "Arts", "Overall"), Sex = rep(c("Boys", "Girls"), 5), N = c(22, 17, 16, 24, 77, 20, 14, 17, 25, 78) ) %>% group_by(Subjects) %>% mutate(pct = proportions(N) * 100) %>% # 计算分组占比 mutate(pct = round(pct, 1)) %>% # 保留1位小数 ungroup()
需求1:将“Overall”饼图置于其余四个右侧,与Physics、Arts垂直对齐
通过拆分图表+网格拼接的方式实现,把四个学科饼图排成2×2网格,将Overall饼图放在右侧,与网格下半部分垂直对齐:
# 生成四个学科的饼图(排除Overall) plot_subjects <- df %>% filter(Subjects != "Overall") %>% ggplot(aes(x = "", y = pct, fill = Sex)) + geom_bar(stat = "identity", width = 1, color = "white") + coord_polar("y", start = 0) + facet_wrap(~fct_reorder(Subjects, N), ncol = 2) + geom_text(aes(y = pct, label = paste0(pct, "%")), size = 5, position = position_stack(vjust = 0.5)) + theme_void() + theme(legend.position = "none", # 隐藏子图图例,统一用Overall的 strip.text = element_text(size = 12)) + scale_fill_brewer(palette = "Pastel1") # 生成Overall饼图 plot_overall <- df %>% filter(Subjects == "Overall") %>% ggplot(aes(x = "", y = pct, fill = Sex)) + geom_bar(stat = "identity", width = 1, color = "white") + coord_polar("y", start = 0) + geom_text(aes(y = pct, label = paste0(pct, "%")), size = 5, position = position_stack(vjust = 0.5)) + theme_void() + theme(legend.title = element_blank(), strip.text = element_text(size = 12), legend.text = element_text(size = 12), legend.spacing.y = unit(0.2, 'cm'), legend.box.spacing = unit(1, "cm")) + scale_fill_brewer(palette = "Pastel1") # 拼接布局:左侧2×2子图 + 右侧Overall(垂直居中) grid.arrange(plot_subjects, plot_overall, ncol = 2, widths = c(2, 1), # 控制左右宽度比例 heights = c(1))
需求2:将“Overall”饼图放在中心,其余四个环绕分布
使用patchwork包拆分单个图表,拼接成中心+环绕的布局:
# 拆分生成四个学科的独立饼图 plot_lit <- df %>% filter(Subjects == "Literature") %>% ggplot(aes(x = "", y = pct, fill = Sex)) + geom_bar(stat = "identity", width = 1, color = "white") + coord_polar("y", start = 0) + geom_text(aes(y = pct, label = paste0(pct, "%")), size = 4, position = position_stack(vjust = 0.5)) + theme_void() + theme(strip.text = element_text(size = 10), legend.position = "none") + scale_fill_brewer(palette = "Pastel1") + labs(title = "Literature") plot_geo <- df %>% filter(Subjects == "Geography") %>% ggplot(aes(x = "", y = pct, fill = Sex)) + geom_bar(stat = "identity", width = 1, color = "white") + coord_polar("y", start = 0) + geom_text(aes(y = pct, label = paste0(pct, "%")), size = 4, position = position_stack(vjust = 0.5)) + theme_void() + theme(strip.text = element_text(size = 10), legend.position = "none") + scale_fill_brewer(palette = "Pastel1") + labs(title = "Geography") plot_phy <- df %>% filter(Subjects == "Physics") %>% ggplot(aes(x = "", y = pct, fill = Sex)) + geom_bar(stat = "identity", width = 1, color = "white") + coord_polar("y", start = 0) + geom_text(aes(y = pct, label = paste0(pct, "%")), size = 4, position = position_stack(vjust = 0.5)) + theme_void() + theme(strip.text = element_text(size = 10), legend.position = "none") + scale_fill_brewer(palette = "Pastel1") + labs(title = "Physics") plot_arts <- df %>% filter(Subjects == "Arts") %>% ggplot(aes(x = "", y = pct, fill = Sex)) + geom_bar(stat = "identity", width = 1, color = "white") + coord_polar("y", start = 0) + geom_text(aes(y = pct, label = paste0(pct, "%")), size = 4, position = position_stack(vjust = 0.5)) + theme_void() + theme(strip.text = element_text(size = 10), legend.position = "none") + scale_fill_brewer(palette = "Pastel1") + labs(title = "Arts") # 生成中心的Overall饼图(适当放大) plot_center <- df %>% filter(Subjects == "Overall") %>% ggplot(aes(x = "", y = pct, fill = Sex)) + geom_bar(stat = "identity", width = 1, color = "white") + coord_polar("y", start = 0) + geom_text(aes(y = pct, label = paste0(pct, "%")), size = 5, position = position_stack(vjust = 0.5)) + theme_void() + theme(legend.title = element_blank(), legend.text = element_text(size = 12), legend.spacing.y = unit(0.2, 'cm')) + scale_fill_brewer(palette = "Pastel1") + labs(title = "Overall") # 拼接成环绕布局:上方左右两个学科,中心Overall,下方左右两个学科 (plot_lit + plot_geo) / (plot_center + plot_phy + plot_arts) + plot_layout(ncol = 3, widths = c(1, 2, 1), heights = c(1, 2)) + plot_annotation(theme = theme(plot.margin = margin(10,10,10,10)))
可通过调整widths和heights的比例,修改中心图与环绕图的大小关系;也可调整拼接顺序,改变环绕的位置。
内容的提问来源于stack exchange,提问作者always.learning
相关产品推荐
相关产品推荐

