2. 数据下载与预处理:从官方资源获取原始数据
做空间转录组分析,第一步就是拿到对的数据。说白了,数据质量直接决定最终结论靠不靠谱。我刚开始接触Visium时,图省事从第三方平台拷了一份数据,结果跑出来的聚类分布死活不对劲——最后发现是下载版本不对,图像和基因矩阵没对齐。从那以后,我老老实实只从官方渠道拿原始数据。
下面我就带你走一遍标准流程:从10x Genomics官网下载Visium原始数据,做基本的预处理,为后续参数调试打好底子。
官方数据源简介
10x Genomics官方提供了大量Visium公开数据集,涵盖多种组织类型和物种。这些数据以Space Ranger输出格式发布,包含三大类文件:
- 空间基因表达矩阵(barcodes.tsv.gz、features.tsv.gz、matrix.mtx.gz)
- 组织图像文件(tissue_hires_image.png、tissue_lowres_image.png)
- 图像对齐信息(scalefactors_json.json、tissue_positions_list.csv)
官方下载链接通常长这样:
https://www.10xgenomics.com/resources/datasets/
或直接通过wget获取示例数据集:
wget https://cf.10xgenomics.com/samples/spatial-exp/1.2.0/Visium_Mouse_Olfactory_Bulb/Visium_Mouse_Olfactory_Bulb_raw_feature_bc_matrix.h5
wget https://cf.10xgenomics.com/samples/spatial-exp/1.2.0/Visium_Mouse_Olfactory_Bulb/Visium_Mouse_Olfactory_Bulb_spatial.tar.gz
下载命令与目录结构
我个人习惯用wget批量拉取,再统一解压。注意,不同版本的数据集文件夹命名可能有细微差别,最好先看一眼官方README。
# 创建项目目录
mkdir -p visium_raw_data && cd visium_raw_data
# 下载小鼠嗅球示例数据(约300MB)
wget https://cf.10xgenomics.com/samples/spatial-exp/1.2.0/Visium_Mouse_Olfactory_Bulb/Visium_Mouse_Olfactory_Bulb_raw_feature_bc_matrix.h5
wget https://cf.10xgenomics.com/samples/spatial-exp/1.2.0/Visium_Mouse_Olfactory_Bulb/Visium_Mouse_Olfactory_Bulb_spatial.tar.gz
# 解压图像与对齐文件
tar -xzf Visium_Mouse_Olfactory_Bulb_spatial.tar.gz
# 查看目录结构
tree
解压后的`spatial/`文件夹里通常会包含以下文件:
spatial/
├── tissue_hires_image.png # 高分辨率染色图(约2000x2000)
├── tissue_lowres_image.png # 低分辨率预览图
├── scalefactors_json.json # 图像缩放因子
├── tissue_positions_list.csv # 每个位置对应的barcode与像素坐标
└── aligned_tissue_image.jpg # 可选对齐后图像
核心文件说明
| 文件 | 格式 | 内容 |
|---|---|---|
| barcodes.tsv.gz / .h5 | 文本/HDF5 | 所有捕获点的barcode序列 |
| features.tsv.gz / .h5 | 文本/HDF5 | 基因名称与ID |
| matrix.mtx.gz / .h5 | MTX/HDF5 | 稀疏表达矩阵(UMI counts) |
| tissue_positions_list.csv | CSV | barcode → 像素坐标 + 组织内/外标记 |
| scalefactors_json.json | JSON | 高/低分辨率缩放因子、spot直径(像素)等 |
注意: 有些数据集用.h5格式打包了全部内容(包括barcode、feature、matrix),读起来更省事。如果你用scanpy,我建议优先选.h5版本,少一重解压步骤。
用Python读取数据
这里我推荐使用scanpy的read_visium函数,它一步到位,自动关联基因矩阵和空间坐标。为什么不自己写循环?因为官方API已经封装好,而且社区验证过很多遍了,你想想看,何必给自己挖坑呢?
import scanpy as sc
# 从h5文件读取(推荐)
adata = sc.read_visium("Visium_Mouse_Olfactory_Bulb_raw_feature_bc_matrix.h5",
source_image_path="spatial/")
# 或者从传统MTX格式读取
# adata = sc.read_visium("raw_feature_bc_matrix/",
# source_image_path="spatial/")
print(adata)
# 输出:AnnData object with n_obs × n_vars = 4500 × 21000
# obs: 'in_tissue', 'array_row', 'array_col'
# var: 'gene_ids', 'feature_types'
# obsm: 'spatial'
# uns: 'spatial_crambin' (图像对象)
嗯,这里有个坑——source_image_path参数要指向包含tissue_hires_image.png的文件夹。我遇到过路径写错导致图像无法嵌入的情况,后来老老实实打印adata.uns['spatial']检查了才定位到问题。
质量控制与预处理
拿到原始数据后,别急着冲进聚类调试。先做几道基础过滤,把明显不合格的spot和基因筛掉。我个人的经验是:
- 过滤低质量spot:UMI数量过少(<200)或线粒体基因占比过高(>20%)的spot,多半是破损细胞或背景噪音。
- 过滤低表达基因:在少于3个spot中表达的基因,统计意义不大,留着只会增加计算量。
- 归一化与对数化:让spot间的表达量可比,常用sc.pp.normalize_total和sc.pp.log1p。
- 识别高变基因:用于后续降维和聚类,sc.pp.highly_variable_genes。
# 基础QC
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.filter_genes(adata, min_cells=3)
# 计算线粒体占比
adata.var['mt'] = adata.var_names.str.startswith('MT-')
sc.pp.calculate_qc_metrics(adata, qc_vars=['mt'], percent_top=None, log1p=False, inplace=True)
# 过滤高线粒体spot
adata = adata[adata.obs.pct_counts_mt < 20, :].copy()
# 归一化+对数化
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
# 筛选高变基因(默认5000个)
sc.pp.highly_variable_genes(adata, n_top_genes=5000)
adata = adata[:, adata.var.highly_variable].copy()
print(adata)
# 输出:AnnData object with n_obs × n_vars = 4100 × 5000
MT-前缀,小鼠是mt-。我曾经在分析小鼠数据时忘了改前缀,结果线粒体占比全为0,让我以为数据特别干净…后来检查才发现是前缀写错了。
预处理流程总览
下图把“下载→解压→读入→过滤→归一化→保存”串起来,方便你对照执行:
保存中间结果
预处理完成后,我习惯把处理过的数据存成.h5ad文件,方便后续章节反复加载,不用每次从头跑过滤。
adata.write("Data/visium_processed.h5ad")
# 下次恢复
adata = sc.read("Data/visium_processed.h5ad")
你可能会问:为什么不直接在原始数据上做所有操作?说白了,预处理过程本身就有不少试错空间。保存一份中间态,万一参数调坏了,还能从干净的过滤后数据重新开始,不用再下载一遍。
好了,到此为止,原始数据已经下载、解压、读入、过滤、归一化,并保存成标准格式。接下来你就可以拿着这份干净的AnnData对象,去探索空间基因表达模式、做聚类参数调试了。