如何用base R或ggplot2制作含水平数据条的交叉分类数据表格?
实现单元格内嵌水平条形图的表格(ggplot2/base R方案)
针对你提到的formattable依赖phantomjs导致保存、输出像素化的问题,这里提供两个纯R原生/ggplot2的解决方案,完全避免额外依赖,且输出高清可自定义。
ggplot2方案(推荐,灵活性高)
用分面功能模拟表格结构,每个分面单元格绘制水平条形图,代码示例如下:
library(ggplot2) # 构造模拟数据(替换成你的真实数据) set.seed(123) df <- expand.grid( Group = c("对照组", "实验组1", "实验组2"), # 行分类变量 Category = c("指标1", "指标2", "指标3", "指标4") # 列分类变量 ) df$Value <- sample(20:95, nrow(df), replace = TRUE) # 连续数值 # 绘制带内嵌条形图的表格 ggplot(df, aes(x = Value, y = 1)) + geom_col(fill = "#2E86AB", alpha = 0.8, width = 0.6) + # 水平条形 geom_text(aes(label = paste0(Value, "%")), hjust = -0.1, size = 3.8, color = "#333333") + # 数值标签 facet_grid(Group ~ Category, switch = "y") + # 按行/列分类分面 theme_minimal(base_size = 10) + theme( # 隐藏冗余坐标轴 axis.title = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank(), # 调整表格样式 panel.grid = element_blank(), strip.text.y.left = element_text(angle = 0, face = "bold", color = "#222222"), # 行标签 strip.text.x = element_text(face = "bold", color = "#222222"), # 列标签 strip.background = element_rect(fill = "#F0F0F0", color = "#CCCCCC"), panel.border = element_rect(color = "#CCCCCC", fill = NA), panel.spacing = unit(0, "mm") # 去掉单元格间隙 ) + scale_x_continuous(expand = expansion(mult = c(0, 0.2))) + # 给数值标签留空间 scale_y_discrete(expand = c(0, 0))
自定义技巧
- 调整条形颜色:修改
geom_col的fill参数,支持hex色码或R内置色名 - 数值标签:调整
hjust控制位置(0在条形右侧,-0.1在条形外),修改size/color改变样式 - 保存高清输出:用
ggsave("table_plot.pdf", width = 10, height = 6, dpi = 300)保存为PDF(矢量图无像素化)或PNG
Base R方案(无额外依赖)
如果不想用ggplot2,可通过layout手动划分单元格绘制,适合轻量场景:
# 使用上面的df数据 row_cats <- unique(df$Group) col_cats <- unique(df$Category) n_rows <- length(row_cats) n_cols <- length(col_cats) max_val <- max(df$Value) # 设置布局:顶部列标题+左侧行标题+单元格区域 layout(matrix( c(0, rep(2, n_cols), rep(1, n_rows), 3:(3 + n_rows*n_cols - 1)), nrow = n_rows + 1, ncol = n_cols + 1 ), widths = c(3, rep(6, n_cols)), heights = c(2, rep(5, n_rows))) # 绘制顶部列标题 par(mar = c(0, 0, 0, 0)) plot(0, 0, type = "n", axes = FALSE, xlab = "", ylab = "") for (i in 1:n_cols) { text(i/n_cols, 0.5, col_cats[i], font = 2, cex = 1.1) } # 绘制左侧行标题 par(mar = c(0, 0, 0, 0)) plot(0, 0, type = "n", axes = FALSE, xlab = "", ylab = "") for (i in 1:n_rows) { text(0.5, (n_rows - i + 1)/n_rows, row_cats[i], font = 2, cex = 1.1) } # 逐个绘制单元格的条形图 par(mar = c(0.5, 0.5, 0.5, 0.5)) for (r in 1:n_rows) { for (c in 1:n_cols) { current_val <- df$Value[df$Group == row_cats[r] & df$Category == col_cats[c]] # 初始化空画布 plot(0, 0, xlim = c(0, max_val), ylim = c(0, 1), type = "n", axes = FALSE, xlab = "", ylab = "") # 绘制条形 rect(0, 0.3, current_val, 0.7, col = "#2E86AB", border = "#AAAAAA") # 绘制数值标签 text(current_val + max_val*0.03, 0.5, paste0(current_val, "%"), cex = 0.9) # 绘制单元格边框 box() } }
这个方案完全不需要任何第三方包,直接用base R绘图函数实现,缺点是样式自定义需要逐个调整参数,不如ggplot2便捷。
内容的提问来源于stack exchange,提问作者whv20
相关产品推荐
相关产品推荐

