如何用ggplot2制作复合饼图?支持添加第三层饼图更佳
R实现复合饼图(Pie of Pie)及多层扩展方案
一、用plotrix包快速实现双层复合饼图
plotrix是R中专门用于绘制特殊饼图的工具包,自带pieOfPie()函数,可直接将主饼图中的指定类别拆分为第二层子饼图,操作简单高效。
步骤1:安装并加载包
install.packages("plotrix") library(plotrix)
步骤2:准备数据
# 主饼图数据:A、B、C为常规大类,D为需要拆分的类别 main_data <- c(A=20, B=30, C=25, D=25) # D类的细分数据 sub_data <- c(D1=10, D2=8, D3=7)
步骤3:绘制双层复合饼图
pieOfPie(main_data, sub_data, main_labels = names(main_data), sub_labels = names(sub_data), main_col = c("#FF9999", "#99FF99", "#9999FF", "#FFCC99"), sub_col = c("#FF6666", "#66FF66", "#6666FF"), main_title = "双层复合饼图示例")
main_data/sub_data:分别传入主饼、子饼的数值数据main_col/sub_col:自定义主、子饼的填充色- 函数会自动将主饼中的D类替换为子饼,并通过线段连接对应扇区
二、扩展实现三层复合饼图
若需要从多个主扇区延伸出子饼(比如同时拆分B和D类),plotrix没有直接的封装函数,但可以通过手动定位绘制的方式实现:
library(plotrix) # 数据准备 main_data <- c(A=20, B=15, C=25, D=40) # D类的细分 sub_d_data <- c(D1=15, D2=12, D3=13) # B类的细分 sub_b_data <- c(B1=8, B2=7) # 绘制主饼图,获取各扇区的结束角度(用于定位子饼) pie_angle <- pie(main_data, col = c("#FF9999", "#99FF99", "#9999FF", "#FFCC99"), labels = names(main_data), main = "三层复合饼图示例") # 计算需要拆分的扇区中心角度(取扇区起始和结束角度的平均值) d_center_angle <- (pie_angle[3] + pie_angle[4]) / 2 b_center_angle <- (pie_angle[1] + pie_angle[2]) / 2 # 绘制D类的子饼(右侧位置) draw.pie(sub_d_data, x = 1.8, y = 0, radius = 0.3, col = c("#FF6666", "#66FF66", "#6666FF"), labels = names(sub_d_data)) # 用线段连接主饼D扇区和子饼 segments(x0 = cos(d_center_angle * pi/180), y0 = sin(d_center_angle * pi/180), x1 = 1.8 + cos(d_center_angle * pi/180)*0.3, y1 = 0 + sin(d_center_angle * pi/180)*0.3) # 绘制B类的子饼(左上位置) draw.pie(sub_b_data, x = -1.5, y = 1.2, radius = 0.25, col = c("#CCFF99", "#99FFCC"), labels = names(sub_b_data)) # 用线段连接主饼B扇区和子饼 segments(x0 = cos(b_center_angle * pi/180), y0 = sin(b_center_angle * pi/180), x1 = -1.5 + cos(b_center_angle * pi/180)*0.25, y1 = 1.2 + sin(b_center_angle * pi/180)*0.25)
- 通过
pie()返回的角度信息,精准定位子饼的位置 draw.pie()用于在指定坐标绘制子饼,segments()绘制连接线,实现多层嵌套效果
三、用ggplot2实现复合饼图
如果习惯使用ggplot2,可以通过分层绘制+极坐标转换的方式实现,核心是给主饼和子饼设置不同的x轴坐标,再添加连接线:
library(ggplot2) library(dplyr) # 构造嵌套数据:包含主类别和子类别 data <- tibble( level1 = c(rep("A",20), rep("B",30), rep("C",25), rep("D",10), rep("D",8), rep("D",7)), level2 = c(rep("A",20), rep("B",30), rep("C",25), rep("D1",10), rep("D2",8), rep("D3",7)) ) # 计算主类别占比 main_summary <- data %>% count(level1) %>% mutate(prop = n/sum(n), type = "main") # 计算D类的子类别占比(基于总数据的占比) sub_summary <- data %>% filter(level1 == "D") %>% count(level2) %>% mutate(prop = n/sum(main_summary$n[main_summary$level1=="D"]) * main_summary$prop[main_summary$level1=="D"], x = 1.5) # 设置子饼的x轴偏移量 # 绘制复合饼图 ggplot() + # 主饼图 geom_bar(data = main_summary, aes(x = 1, y = prop, fill = level1), stat = "identity", width = 1) + # 子饼图 geom_bar(data = sub_summary, aes(x = x, y = prop, fill = level2), stat = "identity", width = 1) + # 添加连接线(对应子饼的每个扇区) geom_segment(aes(x = 1, xend = 1.5, y = sum(main_summary$prop[main_summary$level1 %in% c("A","B","C")]), yend = sum(sub_summary$prop)), color = "black") + geom_segment(aes(x = 1, xend = 1.5, y = sum(main_summary$prop[main_summary$level1 %in% c("A","B")]), yend = sum(sub_summary$prop[1:2])), color = "black") + geom_segment(aes(x = 1, xend = 1.5, y = sum(main_summary$prop[main_summary$level1 == "A"]), yend = sub_summary$prop[1]), color = "black") + # 转换为极坐标 coord_polar(theta = "y") + # 清理主题,保留必要元素 theme_void() + labs(title = "ggplot2双层复合饼图")
- 若要添加第三层,只需新增一组子类别数据,设置更大的x轴偏移量(比如x=2),再补充对应的连接线即可
内容的提问来源于stack exchange,提问作者lre1234
相关产品推荐
相关产品推荐

