如何绘制以饼图为单元格的类热图可视化?
饼图矩阵替代热图的优化实现建议
我想用多个饼图组成的可视化替代常规矩阵热图来优化数据展示,目前已有基础实现,但还需要完善百分比标注、行列间距等功能,以下是现有代码和生成效果,求改进建议或更优实现方法:
现有实现代码
library(ggplot2) library(gridExtra) # 用于排列图形 library(dplyr) library(plyr) # 模拟数据 set.seed(123) data <- expand.grid(X = factor(1:20), Y = factor(1:18)) data$Category <- rep(c("A", "B", "C"), each = 120) data$Value <- runif(360) # 查看数据 print(data) # 绘制单个饼图的函数 plot_pie <- function(data_subset) { ggplot(data_subset, aes(x = "", y = Value, fill = Category)) + geom_bar(width = 1, stat = "identity") + coord_polar(theta = "y") + theme_void() + theme(legend.position = "none") } # 按X和Y分组生成饼图列表 plots <- dlply(data, .(X, Y), plot_pie) # 使用gridExtra排列图形 grid.arrange(grobs = plots, ncol = 20) # 也可以用patchwork排列 library(patchwork) plot_layout <- wrap_plots(plots, ncol = 20) plot_layout
现有生成效果

改进建议与优化实现方案
1. 添加百分比标注
先在数据预处理阶段计算每个(X,Y)组内各分类的占比,再在饼图上添加文本标注,确保标注位置准确:
# 预处理数据:计算每组内的百分比与标注位置 data_processed <- data %>% group_by(X, Y) %>% mutate(Percent = Value / sum(Value) * 100, # 计算饼图标注的中心角度位置 Position = cumsum(Value) - 0.5 * Value) %>% ungroup() # 更新饼图绘制函数,添加百分比标注 plot_pie_with_label <- function(data_subset) { ggplot(data_subset, aes(x = "", y = Value, fill = Category)) + geom_bar(width = 1, stat = "identity") + # 添加保留1位小数的百分比标注 geom_text(aes(y = Position, label = sprintf("%.1f%%", Percent)), size = 2) + # 根据饼图尺寸调整字号 coord_polar(theta = "y") + theme_void() + theme(legend.position = "none", # 调整小图边距,避免标注溢出 plot.margin = margin(1, 1, 1, 1, "mm"), # 固定饼图宽高比,保证所有饼图形状一致 aspect.ratio = 1) }
2. 调整行列间距与统一布局
使用patchwork更灵活地控制行列间距、整体布局,同时提取统一图例避免重复:
library(patchwork) library(purrr) # 用dplyr+ purrr替代plyr生成饼图列表,性能更优 plots_list <- data_processed %>% group_by(X, Y) %>% group_split() %>% map(plot_pie_with_label) # 创建单独的统一图例 legend_plot <- ggplot(data_processed, aes(fill = Category)) + geom_bar(show.legend = TRUE) + scale_fill_manual(values = c("A" = "#1f77b4", "B" = "#ff7f0e", "C" = "#2ca02c")) + theme_void() + theme(legend.position = "right") + guides(fill = guide_legend(title = "分类")) # 排列饼图矩阵,调整行列间距并整合图例 final_plot <- wrap_plots(plots_list, ncol = 20) + plot_layout(guides = "collect", # 收集统一图例 heights = rep(1, 18), # 统一每行高度 widths = rep(1, 20)) + # 统一每列宽度 plot_annotation(title = "饼图矩阵可视化", subtitle = "替代常规热图展示多分类占比") + theme(plot.title = element_text(hjust = 0.5, size = 14), plot.subtitle = element_text(hjust = 0.5, size = 12)) # 合并图例与主图 final_plot + legend_plot + plot_layout(widths = c(10, 1))
3. 添加行列标题
通过grid包添加自定义行列标签,提升可读性:
library(grid) # 生成X/Y轴标签文本 x_labels <- paste0("X", 1:20) y_labels <- paste0("Y", 1:18) # 给主图添加行列标签 final_plot_with_labels <- final_plot + # 添加X轴顶部标签 annotation_custom(textGrob(paste(x_labels, collapse = " "), gp = gpar(fontsize = 8)), ymin = -0.1, ymax = -0.1, xmin = 0, xmax = 1) + # 添加Y轴左侧旋转标签 annotation_custom(textGrob(paste(y_labels, collapse = "\n"), rot = 90, gp = gpar(fontsize = 8)), xmin = -0.05, xmax = -0.05, ymin = 0, ymax = 1) + # 调整绘图区域边距,给标签预留空间 theme(plot.margin = margin(10, 10, 20, 20, "mm"))
4. 其他优化点
- 颜色一致性:提前定义分类颜色,避免ggplot自动分配颜色出现偏差
- 性能优化:数据量较大时,优先使用
dplyr+purrr的组合替代plyr::dlply,处理效率更高 - 标注适配:如果饼图过小,可隐藏小占比分类的标注,避免重叠混乱
内容的提问来源于stack exchange,提问作者Charité Learner
相关产品推荐
相关产品推荐

