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

基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 11:05:11