如何用geom_tile实现单瓦片多颜色填充的矩阵图?
解决geom_tile同一瓦片多数据的分块填充问题
我使用geom_tile创建矩阵图时,发现同一瓦片对应多行数据,导致颜色叠加。希望为每个瓦片填充其对应的多种颜色,理想效果为矩形分块填充。
当前代码
# Create color palette par(mar=c(0,0,1,0)) coul <- brewer.pal(9, "Set3") ggplot(plot_data, aes(x = from, y = to, fill = agreement_num)) + geom_tile() + scale_fill_manual(values = coul) + theme_bw() + scale_x_discrete(drop = FALSE) + scale_y_discrete(drop = FALSE) + theme( axis.text.x = element_text(size = 9,angle = 270, hjust = 0,vjust=0), axis.text.y = element_text(size = 9), aspect.ratio = 1)
可复现数据
plot_data <- structure(list(from = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, NA, NA, NA, NA), levels = c("Afghanistan", "Kazakhstan", "Kyrgyzstan", "Tajikistan", "Turkmenistan", "Uzbekistan" ), class = "factor"), to = structure(c(1L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 5L, 5L, 6L, 6L, 2L, 6L, NA, NA, NA, NA), levels = c("Afghanistan", "Kazakhstan", "Kyrgyzstan", "Tajikistan", "Turkmenistan", "Uzbekistan" ), class = "factor"), weight = c(1291072130433.34, 480160896152.234, 480160896152.234, 480160896152.234, 480160896152.234, 480160896152.234, 480160896152.234, 3474907531417.02, 3474907531417.02, 3474907531417.02, 867103764128.709, 867103764128.709, 7791981051421.92, 7791981051421.92, 133799551.098735, 1102379004.66647, NA, NA, NA, NA), agreement_num = structure(c(NA, 1L, 5L, 2L, 6L, 3L, 4L, 2L, 1L, 6L, 1L, 6L, 1L, 6L, NA, NA, NA, NA, NA, NA), levels = c("51", "58", "133", "135", "176", "224" ), class = "factor")), row.names = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "NA", "NA.1", "NA.2", "NA.3"), class = "data.frame")
解决方案
要实现瓦片内的分块填充,需将单个瓦片拆分为对应数量的小矩形,每个小矩形对应一个agreement_num。以下是完整实现代码:
library(ggplot2) library(dplyr) library(RColorBrewer) # 清理数据:移除含NA的行 clean_data <- plot_data %>% filter(!is.na(from), !is.na(to), !is.na(agreement_num)) %>% # 按from和to分组,给每个组内的条目分配顺序 group_by(from, to) %>% mutate( group_size = n(), tile_width = 1 / group_size, # 将离散的from转换为数值,计算每个小矩形的x范围 x_num = as.integer(from), xmin = x_num - 0.5 + (row_number() - 1) * tile_width, xmax = x_num - 0.5 + row_number() * tile_width, # y轴同理转换为数值,保持整个瓦片的y范围 y_num = as.integer(to), ymin = y_num - 0.5, ymax = y_num + 0.5 ) %>% ungroup() # 创建调色板 coul <- brewer.pal(9, "Set3") # 绘制分块矩阵图 ggplot(clean_data) + geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = agreement_num)) + # 设置x、y轴的刻度和标签,还原离散分类 scale_x_continuous( breaks = 1:length(levels(plot_data$from)), labels = levels(plot_data$from), expand = c(0, 0) ) + scale_y_continuous( breaks = 1:length(levels(plot_data$to)), labels = levels(plot_data$to), expand = c(0, 0) ) + scale_fill_manual(values = coul, na.value = "white") + theme_bw() + theme( axis.text.x = element_text(size = 9, angle = 270, hjust = 0, vjust = 0), axis.text.y = element_text(size = 9), aspect.ratio = 1 )
代码说明
- 数据处理:先过滤无效的NA行,再按
from和to分组,计算每个瓦片内的条目数量,进而得到每个小矩形的宽度比例。将离散的分类轴转换为数值,计算每个小矩形的边界坐标。 - 绘图逻辑:用
geom_rect替代geom_tile,直接绘制每个小分块,确保每个agreement_num对应独立的矩形区域,避免颜色叠加。 - 轴设置:通过
scale_x_continuous和scale_y_continuous还原离散分类的标签和刻度,保持原矩阵图的外观。
内容的提问来源于stack exchange,提问作者MoonS
相关产品推荐
相关产品推荐

