geom_tile() 用矩形色块表示二维网格中的观测。x 和 y 决定色块位置,fill 用颜色表达第三个变量,因此它适合画表达量、频数、评分和其他二维离散组合的数据。
它画出来可能像热图,但职责只是绘制色块:不会替你把矩阵转成长表,也不会自动聚类、标准化或添加复杂注释。
数据应当是什么形状
geom_tile() 最自然的输入是长格式数据,每行对应一个网格单元:
library(dplyr)
library(ggplot2)
library(tibble)
set.seed(42)
tiles <- expand_grid(
sample = LETTERS[1:5],
gene = paste0("G", 1:5)
) |>
mutate(expression = runif(n(), 0, 10))
tiles
数据包含三类变量:
| 变量 | 图形角色 |
|---|---|
gene |
横轴位置 |
sample |
纵轴位置 |
expression |
色块填充色 |
如果数据当前是一个行名为基因、列名为样本的矩阵,需要先整理成长格式,再交给 ggplot2。
绘制基础色块图
ggplot(tiles, aes(x = gene, y = sample, fill = expression)) +
geom_tile()
这里的 fill = expression 放在 aes() 内,表示颜色随数据变化。若将 fill 写在 aes() 外,则所有色块使用同一种固定颜色。
设置边框与连续色标
为色块增加细边框,可以让网格边界更清楚:
ggplot(tiles, aes(gene, sample, fill = expression)) +
geom_tile(color = "white", linewidth = 0.4) +
scale_fill_gradient(low = "white", high = "red") +
theme_minimal()
边框属于图层的固定外观,所以写在 aes() 外。连续数值可使用连续 fill scale;类别变量则应使用离散色标。
色标需要表达变量含义,而不只是装饰。例如以零为中心的正负变化,通常需要能区分方向的发散色标:
ggplot(tiles, aes(gene, sample, fill = expression - 5)) +
geom_tile() +
scale_fill_gradient2(
low = "#3B4CC0",
mid = "white",
high = "#B40426",
midpoint = 0,
name = "Change"
)
控制行列顺序
离散坐标轴的顺序由变量的 levels 决定。需要特定顺序时,应在数据中明确设置因子,而不是依赖字符的默认排序:
tiles <- tiles |>
mutate(
gene = factor(gene, levels = paste0("G", 1:5)),
sample = factor(sample, levels = rev(LETTERS[1:5]))
)
ggplot(tiles, aes(gene, sample, fill = expression)) +
geom_tile()
这会同时控制坐标轴标签与色块位置。只修改数据行顺序并不能可靠改变离散坐标轴顺序。
在色块上叠加数值
网格较小时,可以使用 geom_text() 显示具体数值:
ggplot(tiles, aes(gene, sample, fill = expression)) +
geom_tile(color = "white") +
geom_text(aes(label = round(expression, 1)), color = "black") +
scale_fill_gradient(low = "white", high = "red")
文字本身也是一个独立图层。label 随数据变化,所以放在 aes() 内;固定的文字颜色放在外面。
如果网格很密,逐格标注会遮挡色块并制造视觉噪声。此时应保留色标,或只标注需要强调的子集。
保持色块比例
当横纵轴都是等间距类别时,使用相同的坐标比例可以避免方格被拉成长方形:
ggplot(tiles, aes(gene, sample, fill = expression)) +
geom_tile() +
coord_equal()
如果横轴和纵轴本来具有不同物理单位或间距,则不应为了得到正方形而强行使用相同比例。
设置色块宽度与高度
x、y 表示每个 tile 的中心位置,width 和 height 控制尺寸:
ggplot(tiles, aes(gene, sample, fill = expression)) +
geom_tile(width = 0.9, height = 0.9)
略小于默认尺寸会在色块之间留下缝隙。对于规则的离散网格,通常无需手动设置;在连续坐标或单元格间距具有含义时,才需要明确控制。
缺失组合与缺失值
geom_tile() 只绘制数据中实际存在的行。某个 gene × sample 组合没有对应记录时,图上会留下空位;记录存在但 fill 为 NA 时,则由色标的 na.value 控制颜色。
ggplot(tiles, aes(gene, sample, fill = expression)) +
geom_tile() +
scale_fill_gradient(
low = "white",
high = "red",
na.value = "grey80"
)
“组合不存在”和“组合存在但值缺失”是不同的数据状态。如果所有组合理论上都应存在,可以在绘图前补全组合;否则空白可能被误读为零值。
突出部分色块
需要强调满足条件的网格时,可以叠加第二个 tile 图层:
ggplot(tiles, aes(gene, sample, fill = expression)) +
geom_tile() +
geom_tile(
data = filter(tiles, expression > 8),
fill = NA,
color = "black",
linewidth = 0.8
)
第二层不重新填充颜色,只给高值色块增加边框。保留完整底图再叠加强调层,比删除其他观测更能维持上下文。
什么时候选择其他工具
geom_tile() 适合已经是长表、网格规模适中、需要继续叠加 ggplot2 图层的场景。
如果目标是带行列聚类、注释条和多个矩阵联动的表达热图,专门的热图工具更合适;如果规则网格非常大且无需分别控制色块尺寸,栅格化的绘制方式通常更高效。
关键不是图看起来是否像热图,而是数据是否已经形成一个由 x、y 和 fill 定义的二维网格,以及后续是否需要使用 ggplot2 的图层语法继续组合。