跳到主要内容

R 数据整理与 ggplot2 可视化

R 在组学分析中最常用的场景有两个:整理表格数据,画出能解释结果的图。对 BioF3 来说,本章不是追求完整覆盖 R 语言,而是让你掌握最常用、最容易迁移到真实项目的能力。

学习目标

完成本章后,你应该能够:

  • 理解 R 中向量、数据框和列表的基本用途
  • 用 dplyr 完成筛选、排序、分组和汇总
  • 理解 ggplot2 的图形语法
  • 选择适合生信问题的图表类型
  • 保存可复现的高质量图片
  • 用 AI 辅助改图,但能自己判断图是否合理

R 在 BioF3 中承担什么角色

R 不是唯一选择,但它在生信里非常重要:

  • Seurat 是单细胞分析的主流工具之一
  • Bioconductor 提供大量组学分析包
  • ggplot2 和 ComplexHeatmap 适合发表级可视化
  • R Markdown / Quarto 适合生成分析报告

学习 R 的重点不是背语法,而是知道数据对象长什么样、函数需要什么输入、结果如何保存。

最小 R 基础

向量

向量是 R 中最基础的数据结构。

genes <- c("TP53", "BRCA1", "EGFR", "MYC")
expression <- c(5.2, 3.8, 7.1, 4.5)

genes[1]
expression > 5
mean(expression)

数据框

数据框类似表格,是生信分析中最常见的数据形态。

gene_data <- data.frame(
gene = c("TP53", "BRCA1", "EGFR", "MYC"),
expression = c(5.2, 3.8, 7.1, 4.5),
chromosome = c("17", "17", "7", "8")
)

head(gene_data)
str(gene_data)
summary(gene_data)

访问列:

gene_data$gene
gene_data[["expression"]]

筛选行:

high_expr <- gene_data[gene_data$expression > 5, ]

列表

很多 R 包会把复杂结果放在列表里。Seurat 对象、差异分析结果和富集分析结果都可能包含多层信息。

analysis_result <- list(
genes = genes,
expression = expression,
metadata = gene_data
)

analysis_result$metadata

dplyr:表格整理的基本动作

先加载包:

library(dplyr)

准备示例数据:

gene_data <- data.frame(
gene = c("TP53", "BRCA1", "EGFR", "MYC", "KRAS"),
expression = c(5.2, 3.8, 7.1, 4.5, 6.3),
pvalue = c(0.001, 0.05, 0.0001, 0.1, 0.002),
chromosome = c("17", "17", "7", "8", "12")
)

常用操作:

gene_data %>%
filter(expression > 5) %>%
arrange(desc(expression)) %>%
mutate(
log_expression = log2(expression + 1),
significant = pvalue < 0.05
)

分组汇总:

chromosome_summary <- gene_data %>%
group_by(chromosome) %>%
summarise(
mean_expression = mean(expression),
n_genes = n(),
.groups = "drop"
)

在真实项目中,大部分绘图问题都先是数据整理问题。图画不好,常常不是 ggplot2 不会用,而是表格没有整理成合适的长格式。

ggplot2 的核心思想

ggplot2 使用“图形语法”。你可以把一张图理解成几层:

  • data:使用哪个数据框
  • aes:哪些列映射到 x、y、颜色、形状、大小
  • geom:用什么几何对象展示数据
  • scale:坐标轴和颜色如何转换
  • theme:图的外观
  • labs:标题、坐标轴和图例文字

最小示例:

library(ggplot2)

ggplot(gene_data, aes(x = gene, y = expression)) +
geom_col(fill = "#3B82F6") +
labs(x = "Gene", y = "Expression") +
theme_classic()

Bar plot - Gene expression levels

图 1:柱状图适合展示少量分类的数值比较。真实项目中,如果每组有多个样本,优先展示均值和误差,或直接展示每个样本点。

生信常用图表

散点图:看两个变量的关系

set.seed(123)

cell_data <- data.frame(
cell_id = paste0("Cell_", 1:80),
gene_a = rnorm(80, mean = 5, sd = 1.5),
gene_b = rnorm(80, mean = 6, sd = 1.2)
)

ggplot(cell_data, aes(x = gene_a, y = gene_b)) +
geom_point(color = "#2563EB", alpha = 0.7, size = 2) +
geom_smooth(method = "lm", se = TRUE, color = "#111827") +
labs(x = "Gene A expression", y = "Gene B expression") +
theme_classic()

Scatter plot - Gene correlation

图 2:散点图适合观察两个连续变量的关系。是否添加回归线取决于你的问题,不能因为线显得专业就默认添加。

箱线图:比较分组分布

set.seed(123)

expression_data <- data.frame(
condition = rep(c("Control", "Treatment"), each = 40),
expression = c(
rnorm(40, mean = 5, sd = 1),
rnorm(40, mean = 6.5, sd = 1.2)
)
)

ggplot(expression_data, aes(x = condition, y = expression, fill = condition)) +
geom_boxplot(width = 0.5, outlier.shape = NA, alpha = 0.8) +
geom_jitter(width = 0.12, alpha = 0.45, size = 1.4) +
scale_fill_manual(values = c("#93C5FD", "#FCA5A5")) +
labs(x = NULL, y = "Expression") +
theme_classic() +
theme(legend.position = "none")

Box plot - Condition comparison

图 3:箱线图展示中位数、四分位数和离群点。样本数较少时,建议叠加每个样本点,避免隐藏数据分布。

直方图:看整体分布

set.seed(123)

gene_counts <- data.frame(
counts = rpois(1000, lambda = 10)
)

ggplot(gene_counts, aes(x = counts)) +
geom_histogram(bins = 30, fill = "#60A5FA", color = "white") +
labs(x = "Counts", y = "Frequency") +
theme_classic()

Histogram - Count distribution

图 4:直方图适合观察测序计数、基因表达、QC 指标等连续变量的分布。

小提琴图:看分布形状

ggplot(expression_data, aes(x = condition, y = expression, fill = condition)) +
geom_violin(trim = FALSE, alpha = 0.7) +
geom_boxplot(width = 0.12, fill = "white", outlier.shape = NA) +
scale_fill_manual(values = c("#93C5FD", "#FCA5A5")) +
labs(x = NULL, y = "Expression") +
theme_classic() +
theme(legend.position = "none")

Violin plot - Distribution comparison

图 5:小提琴图适合展示大量细胞或样本的分布形状。单细胞表达图常用小提琴图,但要注意零值和归一化方式。

分面图:同时比较多个基因或分组

set.seed(123)

multi_gene_data <- data.frame(
gene = rep(c("Gene1", "Gene2", "Gene3"), each = 40),
condition = rep(rep(c("Control", "Treatment"), each = 20), 3),
expression = c(
rnorm(40, 5, 1),
rnorm(40, 6, 1),
rnorm(40, 7, 1)
)
)

ggplot(multi_gene_data, aes(x = condition, y = expression, fill = condition)) +
geom_boxplot(outlier.shape = NA, alpha = 0.8) +
geom_jitter(width = 0.12, alpha = 0.35, size = 1) +
facet_wrap(~ gene, nrow = 1) +
scale_fill_manual(values = c("#93C5FD", "#FCA5A5")) +
labs(x = NULL, y = "Expression") +
theme_bw() +
theme(legend.position = "none")

Facet plot - Multi-gene comparison

图 6:分面图适合在同一套坐标和样式下比较多个基因、细胞类型或条件。

一个小型表达分析示例

下面用模拟数据演示从宽表到长表、再到可视化的完整流程。

library(dplyr)
library(tidyr)
library(ggplot2)

set.seed(123)

n_genes <- 100

gene_expression <- data.frame(
gene_id = paste0("Gene_", 1:n_genes),
control_1 = rpois(n_genes, lambda = 50),
control_2 = rpois(n_genes, lambda = 50),
control_3 = rpois(n_genes, lambda = 50),
treatment_1 = rpois(n_genes, lambda = 75),
treatment_2 = rpois(n_genes, lambda = 75),
treatment_3 = rpois(n_genes, lambda = 75)
)

gene_long <- gene_expression %>%
pivot_longer(
cols = -gene_id,
names_to = "sample",
values_to = "counts"
) %>%
mutate(
condition = if_else(grepl("control", sample), "Control", "Treatment"),
log_counts = log10(counts + 1)
)

可视化表达分布:

ggplot(gene_long, aes(x = condition, y = log_counts, fill = condition)) +
geom_violin(trim = FALSE, alpha = 0.7) +
geom_boxplot(width = 0.12, fill = "white", outlier.shape = NA) +
scale_fill_manual(values = c("#93C5FD", "#FCA5A5")) +
labs(x = NULL, y = "log10(counts + 1)") +
theme_classic() +
theme(legend.position = "none")

Expression distribution

图 7:表达量分布图可以快速检查组间整体表达差异。真实差异分析不能只看这张图,还需要合适的统计模型。

火山图和热图的注意事项

火山图通常需要两类信息:

  • x 轴:log2 fold change
  • y 轴:显著性,例如 -log10(adjusted p-value)

如果没有真实 p 值或校正后的 p 值,不应该画成正式火山图。可以画示意图,但必须标清楚“模拟数据”。

热图适合展示一组基因在多个样本或细胞类型中的模式。常见注意点:

  • 是否按行标准化
  • 是否显示聚类
  • 是否展示样本分组注释
  • 颜色是否有清晰含义
  • 基因数量是否过多

Volcano plot

图 8:火山图示例。真实项目中应使用差异分析结果中的 log2FC 和校正后 p 值。

Gene expression heatmap

图 9:热图示例。热图适合展示表达模式,而不是替代统计检验。

保存图片

建议所有图都显式保存,避免只留在 Notebook 或 RStudio 窗口里。

ggsave(
filename = "results/figures/expression_distribution.png",
width = 7,
height = 5,
dpi = 300
)

保存前确认:

  • 图片尺寸是否适合论文或网页
  • 字体是否清晰
  • 坐标轴是否有单位
  • 图例是否能解释颜色
  • 文件名是否能看出内容

AI 辅助改图

AI 很适合帮助你把“能画出来的图”改成“更清楚的图”。

可以这样提问:

请检查这段 ggplot2 代码。目标是展示 Control 和 Treatment 的表达分布。请指出:
1. 数据是否应该先转成长表
2. 图类型是否合适
3. 坐标轴和图例是否清楚
4. 是否需要叠加样本点
5. 不要改变统计含义,只优化可读性

也可以让 AI 帮你解释图:

请根据这张图的代码写一段图注,说明 x 轴、y 轴、颜色、每个点或箱体代表什么。不要夸大统计结论。

但下面这些事情必须自己判断:

  • 用箱线图还是小提琴图是否符合数据量
  • 是否应该展示样本点而不是只展示均值
  • 是否需要多重检验校正
  • 是否能从图上得出生物学结论
  • 图注是否准确描述了数据处理方式

完整代码下载

如果你想直接运行完整代码并生成本章相关图表,可以下载完整脚本:

(17 KB)

检查清单

完成本章后,你应该能够:

  • 用 R 创建和查看数据框
  • 用 dplyr 完成基础表格整理
  • 解释 ggplot2 中 data、aes 和 geom 的作用
  • 根据问题选择柱状图、散点图、箱线图、小提琴图、直方图或热图
  • 保存 300 DPI 图片
  • 用 AI 辅助检查图表代码和图注

下一步

继续学习:

参考资源